util.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #!/usr/bin/env python
  2. import atexit
  3. import contextlib
  4. import errno
  5. import platform
  6. import re
  7. import shutil
  8. import ssl
  9. import subprocess
  10. import sys
  11. import tarfile
  12. import tempfile
  13. import urllib2
  14. import os
  15. import zipfile
  16. from config import is_verbose_mode, PLATFORM
  17. from env_util import get_vs_env
  18. BOTO_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'vendor',
  19. 'boto'))
  20. NPM = 'npm'
  21. if sys.platform in ['win32', 'cygwin']:
  22. NPM += '.cmd'
  23. def get_host_arch():
  24. """Returns the host architecture with a predictable string."""
  25. host_arch = platform.machine()
  26. # Convert machine type to format recognized by gyp.
  27. if re.match(r'i.86', host_arch) or host_arch == 'i86pc':
  28. host_arch = 'ia32'
  29. elif host_arch in ['x86_64', 'amd64']:
  30. host_arch = 'x64'
  31. elif host_arch.startswith('arm'):
  32. host_arch = 'arm'
  33. # platform.machine is based on running kernel. It's possible to use 64-bit
  34. # kernel with 32-bit userland, e.g. to give linker slightly more memory.
  35. # Distinguish between different userland bitness by querying
  36. # the python binary.
  37. if host_arch == 'x64' and platform.architecture()[0] == '32bit':
  38. host_arch = 'ia32'
  39. return host_arch
  40. def tempdir(prefix=''):
  41. directory = tempfile.mkdtemp(prefix=prefix)
  42. atexit.register(shutil.rmtree, directory)
  43. return directory
  44. @contextlib.contextmanager
  45. def scoped_cwd(path):
  46. cwd = os.getcwd()
  47. os.chdir(path)
  48. try:
  49. yield
  50. finally:
  51. os.chdir(cwd)
  52. @contextlib.contextmanager
  53. def scoped_env(key, value):
  54. origin = ''
  55. if key in os.environ:
  56. origin = os.environ[key]
  57. os.environ[key] = value
  58. try:
  59. yield
  60. finally:
  61. os.environ[key] = origin
  62. def download(text, url, path):
  63. safe_mkdir(os.path.dirname(path))
  64. with open(path, 'wb') as local_file:
  65. if hasattr(ssl, '_create_unverified_context'):
  66. ssl._create_default_https_context = ssl._create_unverified_context
  67. web_file = urllib2.urlopen(url)
  68. file_size = int(web_file.info().getheaders("Content-Length")[0])
  69. downloaded_size = 0
  70. block_size = 128
  71. ci = os.environ.get('CI') == '1'
  72. while True:
  73. buf = web_file.read(block_size)
  74. if not buf:
  75. break
  76. downloaded_size += len(buf)
  77. local_file.write(buf)
  78. if not ci:
  79. percent = downloaded_size * 100. / file_size
  80. status = "\r%s %10d [%3.1f%%]" % (text, downloaded_size, percent)
  81. print status,
  82. if ci:
  83. print "%s done." % (text)
  84. else:
  85. print
  86. return path
  87. def extract_tarball(tarball_path, member, destination):
  88. with tarfile.open(tarball_path) as tarball:
  89. tarball.extract(member, destination)
  90. def extract_zip(zip_path, destination):
  91. if sys.platform == 'darwin':
  92. # Use unzip command on Mac to keep symbol links in zip file work.
  93. execute(['unzip', zip_path, '-d', destination])
  94. else:
  95. with zipfile.ZipFile(zip_path) as z:
  96. z.extractall(destination)
  97. def make_zip(zip_file_path, files, dirs):
  98. safe_unlink(zip_file_path)
  99. if sys.platform == 'darwin':
  100. files += dirs
  101. execute(['zip', '-r', '-y', zip_file_path] + files)
  102. else:
  103. zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED)
  104. for filename in files:
  105. zip_file.write(filename, filename)
  106. for dirname in dirs:
  107. for root, _, filenames in os.walk(dirname):
  108. for f in filenames:
  109. zip_file.write(os.path.join(root, f))
  110. zip_file.close()
  111. def rm_rf(path):
  112. try:
  113. shutil.rmtree(path)
  114. except OSError:
  115. pass
  116. def safe_unlink(path):
  117. try:
  118. os.unlink(path)
  119. except OSError as e:
  120. if e.errno != errno.ENOENT:
  121. raise
  122. def safe_mkdir(path):
  123. try:
  124. os.makedirs(path)
  125. except OSError as e:
  126. if e.errno != errno.EEXIST:
  127. raise
  128. def execute(argv, env=os.environ, cwd=None):
  129. if is_verbose_mode():
  130. print ' '.join(argv)
  131. try:
  132. output = subprocess.check_output(argv, stderr=subprocess.STDOUT, env=env, cwd=cwd)
  133. if is_verbose_mode():
  134. print output
  135. return output
  136. except subprocess.CalledProcessError as e:
  137. print e.output
  138. raise e
  139. def execute_stdout(argv, env=os.environ, cwd=None):
  140. if is_verbose_mode():
  141. print ' '.join(argv)
  142. try:
  143. subprocess.check_call(argv, env=env, cwd=cwd)
  144. except subprocess.CalledProcessError as e:
  145. print e.output
  146. raise e
  147. else:
  148. execute(argv, env, cwd)
  149. def electron_gyp():
  150. SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
  151. gyp = os.path.join(SOURCE_ROOT, 'electron.gyp')
  152. with open(gyp) as f:
  153. obj = eval(f.read());
  154. return obj['variables']
  155. def electron_features():
  156. SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
  157. gyp = os.path.join(SOURCE_ROOT, 'features.gypi')
  158. with open(gyp) as f:
  159. obj = eval(f.read());
  160. return obj['variables']['variables']
  161. def get_electron_version():
  162. return 'v' + electron_gyp()['version%']
  163. def parse_version(version):
  164. if version[0] == 'v':
  165. version = version[1:]
  166. vs = version.split('.')
  167. if len(vs) > 4:
  168. return vs[0:4]
  169. else:
  170. return vs + ['0'] * (4 - len(vs))
  171. def boto_path_dirs():
  172. return [
  173. os.path.join(BOTO_DIR, 'build', 'lib'),
  174. os.path.join(BOTO_DIR, 'build', 'lib.linux-x86_64-2.7')
  175. ]
  176. def run_boto_script(access_key, secret_key, script_name, *args):
  177. env = os.environ.copy()
  178. env['AWS_ACCESS_KEY_ID'] = access_key
  179. env['AWS_SECRET_ACCESS_KEY'] = secret_key
  180. env['PYTHONPATH'] = os.path.pathsep.join(
  181. [env.get('PYTHONPATH', '')] + boto_path_dirs())
  182. boto = os.path.join(BOTO_DIR, 'bin', script_name)
  183. execute([sys.executable, boto] + list(args), env)
  184. def s3put(bucket, access_key, secret_key, prefix, key_prefix, files):
  185. args = [
  186. '--bucket', bucket,
  187. '--prefix', prefix,
  188. '--key_prefix', key_prefix,
  189. '--grant', 'public-read'
  190. ] + files
  191. run_boto_script(access_key, secret_key, 's3put', *args)
  192. def import_vs_env(target_arch):
  193. if sys.platform != 'win32':
  194. return
  195. if target_arch == 'ia32':
  196. vs_arch = 'amd64_x86'
  197. else:
  198. vs_arch = 'x86_amd64'
  199. env = get_vs_env('[15.0,16.0)', vs_arch)
  200. os.environ.update(env)
  201. def set_clang_env(env):
  202. SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
  203. llvm_dir = os.path.join(SOURCE_ROOT, 'vendor', 'llvm-build',
  204. 'Release+Asserts', 'bin')
  205. env['CC'] = os.path.join(llvm_dir, 'clang')
  206. env['CXX'] = os.path.join(llvm_dir, 'clang++')
  207. def update_electron_modules(dirname, target_arch, nodedir):
  208. env = os.environ.copy()
  209. version = get_electron_version()
  210. env['npm_config_arch'] = target_arch
  211. env['npm_config_target'] = version
  212. env['npm_config_nodedir'] = nodedir
  213. update_node_modules(dirname, env)
  214. execute_stdout([NPM, 'rebuild'], env, dirname)
  215. def update_node_modules(dirname, env=None):
  216. if env is None:
  217. env = os.environ.copy()
  218. if PLATFORM == 'linux':
  219. # Use prebuilt clang for building native modules.
  220. set_clang_env(env)
  221. env['npm_config_clang'] = '1'
  222. with scoped_cwd(dirname):
  223. args = [NPM, 'install']
  224. if is_verbose_mode():
  225. args += ['--verbose']
  226. # Ignore npm install errors when running in CI.
  227. if os.environ.has_key('CI'):
  228. try:
  229. execute_stdout(args, env)
  230. except subprocess.CalledProcessError:
  231. pass
  232. else:
  233. execute_stdout(args, env)