update_clang.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 
6 """This script is used to download prebuilt clang binaries."""
7 
8 from __future__ import division
9 from __future__ import print_function
10 
11 import os
12 import shutil
13 import subprocess
14 import stat
15 import sys
16 import tarfile
17 import tempfile
18 import time
19 
20 try:
21  # Python 3.0 or later
22  from urllib.error import HTTPError, URLError
23  from urllib.request import urlopen
24 except ImportError:
25  from urllib2 import urlopen, HTTPError, URLError
26 
27 
28 # CLANG_REVISION and CLANG_SUB_REVISION determine the build of clang
29 # to use. These should be synced with tools/clang/scripts/update.py in
30 # Chromium.
31 CLANG_REVISION = 'llvmorg-14-init-6722-g0fbd3aad'
32 CLANG_SUB_REVISION = 2
33 
34 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
35 
36 # Path constants. (All of these should be absolute paths.)
37 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
38 LLVM_BUILD_DIR = os.path.join(THIS_DIR, 'llvm-build')
39 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
40 
41 # URL for pre-built binaries.
42 CDS_URL = os.environ.get('CDS_CLANG_BUCKET_OVERRIDE',
43  'https://commondatastorage.googleapis.com/chromium-browser-clang')
44 
45 
46 def DownloadUrl(url, output_file):
47  """Download url into output_file."""
48  CHUNK_SIZE = 4096
49  TOTAL_DOTS = 10
50  num_retries = 3
51  retry_wait_s = 5 # Doubled at each retry.
52 
53  while True:
54  try:
55  sys.stdout.write('Downloading %s ' % url)
56  sys.stdout.flush()
57  response = urlopen(url)
58  total_size = int(response.headers.get('Content-Length').strip())
59  bytes_done = 0
60  dots_printed = 0
61  while True:
62  chunk = response.read(CHUNK_SIZE)
63  if not chunk:
64  break
65  output_file.write(chunk)
66  bytes_done += len(chunk)
67  num_dots = TOTAL_DOTS * bytes_done // total_size
68  sys.stdout.write('.' * (num_dots - dots_printed))
69  sys.stdout.flush()
70  dots_printed = num_dots
71  if bytes_done != total_size:
72  raise URLError("only got %d of %d bytes" % (bytes_done, total_size))
73  print(' Done.')
74  return
75  except URLError as e:
76  sys.stdout.write('\n')
77  print(e)
78  if num_retries == 0 or isinstance(e, HTTPError) and e.code == 404:
79  raise e
80  num_retries -= 1
81  print('Retrying in %d s ...' % retry_wait_s)
82  time.sleep(retry_wait_s)
83  retry_wait_s *= 2
84 
85 
86 def EnsureDirExists(path):
87  if not os.path.exists(path):
88  print("Creating directory %s" % path)
89  os.makedirs(path)
90 
91 
92 def DownloadAndUnpack(url, output_dir):
93  with tempfile.TemporaryFile() as f:
94  DownloadUrl(url, f)
95  f.seek(0)
96  EnsureDirExists(output_dir)
97  tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir)
98 
99 
100 def ReadStampFile(path=STAMP_FILE):
101  """Return the contents of the stamp file, or '' if it doesn't exist."""
102  try:
103  with open(path, 'r') as f:
104  return f.read().rstrip()
105  except IOError:
106  return ''
107 
108 
109 def WriteStampFile(s, path=STAMP_FILE):
110  """Write s to the stamp file."""
111  EnsureDirExists(os.path.dirname(path))
112  with open(path, 'w') as f:
113  f.write(s)
114  f.write('\n')
115 
116 
117 def RmTree(dir):
118  """Delete dir."""
119  def ChmodAndRetry(func, path, _):
120  # Subversion can leave read-only files around.
121  if not os.access(path, os.W_OK):
122  os.chmod(path, stat.S_IWUSR)
123  return func(path)
124  raise
125 
126  shutil.rmtree(dir, onerror=ChmodAndRetry)
127 
128 
129 def CopyFile(src, dst):
130  """Copy a file from src to dst."""
131  print("Copying %s to %s" % (src, dst))
132  shutil.copy(src, dst)
133 
134 
136  cds_file = "clang-%s.tgz" % PACKAGE_VERSION
137  if sys.platform == 'win32' or sys.platform == 'cygwin':
138  cds_full_url = CDS_URL + '/Win/' + cds_file
139  elif sys.platform.startswith('linux'):
140  cds_full_url = CDS_URL + '/Linux_x64/' + cds_file
141  else:
142  return 0
143 
144  print('Updating Clang to %s...' % PACKAGE_VERSION)
145 
146  if ReadStampFile() == PACKAGE_VERSION:
147  print('Clang is already up to date.')
148  return 0
149 
150  # Reset the stamp file in case the build is unsuccessful.
151  WriteStampFile('')
152 
153  print('Downloading prebuilt clang')
154  if os.path.exists(LLVM_BUILD_DIR):
155  RmTree(LLVM_BUILD_DIR)
156  try:
157  DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR)
158  print('clang %s unpacked' % PACKAGE_VERSION)
159  WriteStampFile(PACKAGE_VERSION)
160  return 0
161  except URLError:
162  print('Failed to download prebuilt clang %s' % cds_file)
163  print('Exiting.')
164  return 1
165 
166 
167 def main():
168  return UpdateClang()
169 
170 
171 if __name__ == '__main__':
172  sys.exit(main())
update_clang.DownloadUrl
def DownloadUrl(url, output_file)
Definition: update_clang.py:46
update_clang.CopyFile
def CopyFile(src, dst)
Definition: update_clang.py:129
xds_interop_client.int
int
Definition: xds_interop_client.py:113
update_clang.DownloadAndUnpack
def DownloadAndUnpack(url, output_dir)
Definition: update_clang.py:92
update_clang.EnsureDirExists
def EnsureDirExists(path)
Definition: update_clang.py:86
update_clang.WriteStampFile
def WriteStampFile(s, path=STAMP_FILE)
Definition: update_clang.py:109
update_clang.ReadStampFile
def ReadStampFile(path=STAMP_FILE)
Definition: update_clang.py:100
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
update_clang.UpdateClang
def UpdateClang()
Definition: update_clang.py:135
main
Definition: main.py:1
update_clang.RmTree
def RmTree(dir)
Definition: update_clang.py:117
open
#define open
Definition: test-fs.c:46
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
update_clang.main
def main()
Definition: update_clang.py:167


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:47