ya 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #!/usr/bin/env python
  2. import os
  3. import sys
  4. import platform
  5. import json
  6. URLS = ["https://storage.mds.yandex.net/get-devtools-opensource/471749/6a65891429890bff3fba00c421eb1911"]
  7. MD5 = "6a65891429890bff3fba00c421eb1911"
  8. RETRIES = 5
  9. HASH_PREFIX = 10
  10. HOME_DIR = os.path.expanduser('~')
  11. def create_dirs(path):
  12. try:
  13. os.makedirs(path)
  14. except OSError as e:
  15. import errno
  16. if e.errno != errno.EEXIST:
  17. raise
  18. return path
  19. def misc_root():
  20. return create_dirs(os.getenv('YA_CACHE_DIR') or os.path.join(HOME_DIR, '.ya'))
  21. def tool_root():
  22. return create_dirs(os.getenv('YA_CACHE_DIR_TOOLS') or os.path.join(misc_root(), 'tools'))
  23. def ya_token():
  24. def get_token_from_file():
  25. try:
  26. with open(os.environ.get('YA_TOKEN_PATH', os.path.join(HOME_DIR, '.ya_token')), 'r') as f:
  27. return f.read().strip()
  28. except:
  29. pass
  30. return os.getenv('YA_TOKEN') or get_token_from_file()
  31. TOOLS_DIR = tool_root()
  32. def uniq(size=6):
  33. import string
  34. import random
  35. return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(size))
  36. def _fetch(url, into):
  37. import hashlib
  38. try:
  39. from urllib2 import urlopen
  40. from urllib2 import Request
  41. from urlparse import urlparse
  42. except ImportError:
  43. from urllib.request import urlopen
  44. from urllib.request import Request
  45. from urllib.parse import urlparse
  46. request = Request(str(url))
  47. request.add_header('User-Agent', 'ya-bootstrap')
  48. if urlparse(url).netloc == 'proxy.sandbox.yandex-team.ru':
  49. token = ya_token()
  50. if token:
  51. request.add_header('Authorization', 'OAuth {}'.format(token))
  52. md5 = hashlib.md5()
  53. sys.stderr.write('Downloading %s ' % url)
  54. sys.stderr.flush()
  55. conn = urlopen(request, timeout=10)
  56. sys.stderr.write('[')
  57. sys.stderr.flush()
  58. try:
  59. with open(into, 'wb') as f:
  60. while True:
  61. block = conn.read(1024 * 1024)
  62. sys.stderr.write('.')
  63. sys.stderr.flush()
  64. if block:
  65. md5.update(block)
  66. f.write(block)
  67. else:
  68. break
  69. return md5.hexdigest()
  70. finally:
  71. sys.stderr.write('] ')
  72. sys.stderr.flush()
  73. def _atomic_fetch(url, into, md5):
  74. tmp_dest = into + '.' + uniq()
  75. try:
  76. real_md5 = _fetch(url, tmp_dest)
  77. if real_md5 != md5:
  78. raise Exception('MD5 mismatched: %s differs from %s' % (real_md5, md5))
  79. os.rename(tmp_dest, into)
  80. sys.stderr.write('OK\n')
  81. except Exception as e:
  82. sys.stderr.write('ERROR: ' + str(e) + '\n')
  83. raise
  84. finally:
  85. try:
  86. os.remove(tmp_dest)
  87. except OSError:
  88. pass
  89. def _extract(path, into):
  90. import tarfile
  91. tar = tarfile.open(path, errorlevel=2)
  92. tar.extractall(path=into)
  93. tar.close()
  94. def _get(urls, md5):
  95. dest_path = os.path.join(TOOLS_DIR, md5[:HASH_PREFIX])
  96. if not os.path.exists(dest_path):
  97. for iter in range(RETRIES):
  98. try:
  99. _atomic_fetch(urls[iter % len(urls)], dest_path, md5)
  100. break
  101. except Exception:
  102. if iter + 1 == RETRIES:
  103. raise
  104. else:
  105. import time
  106. time.sleep(iter)
  107. return dest_path
  108. def _get_dir(urls, md5, ya_name):
  109. dest_dir = os.path.join(TOOLS_DIR, md5[:HASH_PREFIX] + '_d')
  110. if os.path.isfile(os.path.join(dest_dir, ya_name)):
  111. return dest_dir
  112. try:
  113. packed_path = _get(urls, md5)
  114. except Exception:
  115. if os.path.isfile(os.path.join(dest_dir, ya_name)):
  116. return dest_dir
  117. raise
  118. tmp_dir = dest_dir + '.' + uniq()
  119. try:
  120. try:
  121. _extract(packed_path, tmp_dir)
  122. except Exception:
  123. if os.path.isfile(os.path.join(dest_dir, ya_name)):
  124. return dest_dir
  125. raise
  126. try:
  127. os.rename(tmp_dir, dest_dir)
  128. except OSError as e:
  129. import errno
  130. if e.errno != errno.ENOTEMPTY:
  131. raise
  132. return dest_dir
  133. finally:
  134. import shutil
  135. shutil.rmtree(tmp_dir, ignore_errors=True)
  136. try:
  137. os.remove(packed_path)
  138. except Exception:
  139. pass
  140. def _mine_arc_root():
  141. return os.path.dirname(os.path.realpath(__file__))
  142. def main():
  143. if not os.path.exists(TOOLS_DIR):
  144. os.makedirs(TOOLS_DIR)
  145. with open(_get(URLS, MD5), 'r') as fp:
  146. meta = json.load(fp)['data']
  147. my_platform = platform.system().lower()
  148. my_machine = platform.machine().lower()
  149. if my_platform == 'linux':
  150. my_platform = 'linux-ppc64le' if 'ppc64le' in platform.platform() else 'linux_musl'
  151. if my_platform == 'darwin' and my_machine == 'arm64':
  152. my_platform = 'darwin-arm64'
  153. # match by max prefix length, prefer shortest
  154. best_key = max(meta.keys(), key=lambda x: (len(os.path.commonprefix([my_platform, x])), -len(x)))
  155. value = meta[best_key]
  156. if len(sys.argv) == 2 and sys.argv[1].startswith('--print-sandbox-id='):
  157. target = sys.argv[1].split('=')[1]
  158. best_target = max(meta.keys(), key=lambda x: len(os.path.commonprefix([target, x])))
  159. sys.stdout.write(str(meta[best_target]['resource_id']) + '\n')
  160. exit(0)
  161. ya_name = {'win32': 'ya-bin.exe'}.get(best_key, 'ya-bin') # XXX
  162. ya_dir = _get_dir(value['urls'], value['md5'], ya_name)
  163. # Popen `args` must have `str` type
  164. ya_path = str(os.path.join(ya_dir, ya_name))
  165. env = os.environ.copy()
  166. if 'YA_SOURCE_ROOT' not in env:
  167. src_root = _mine_arc_root()
  168. if src_root is not None:
  169. env['YA_SOURCE_ROOT'] = src_root
  170. # For more info see YT-14105
  171. if 'LD_PRELOAD' in env:
  172. sys.stderr.write("Warn: LD_PRELOAD='{}' is specified and may affect the correct operation of the ya\n".format(env['LD_PRELOAD']))
  173. if os.name == 'nt':
  174. import subprocess
  175. p = subprocess.Popen([ya_path] + sys.argv[1:], env=env)
  176. p.wait()
  177. sys.exit(p.returncode)
  178. else:
  179. os.execve(ya_path, [ya_path] + sys.argv[1:], env)
  180. if __name__ == '__main__':
  181. try:
  182. main()
  183. except Exception as e:
  184. sys.stderr.write('ERROR: ' + str(e) + '\n')
  185. sys.exit(1)