protobuf/third_party/benchmark/mingw.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 # encoding: utf-8
3 
4 import argparse
5 import errno
6 import logging
7 import os
8 import platform
9 import re
10 import sys
11 import subprocess
12 import tempfile
13 
14 try:
15  import winreg
16 except ImportError:
17  import _winreg as winreg
18 try:
19  import urllib.request as request
20 except ImportError:
21  import urllib as request
22 try:
23  import urllib.parse as parse
24 except ImportError:
25  import urlparse as parse
26 
27 class EmptyLogger(object):
28  '''
29  Provides an implementation that performs no logging
30  '''
31  def debug(self, *k, **kw):
32  pass
33  def info(self, *k, **kw):
34  pass
35  def warn(self, *k, **kw):
36  pass
37  def error(self, *k, **kw):
38  pass
39  def critical(self, *k, **kw):
40  pass
41  def setLevel(self, *k, **kw):
42  pass
43 
44 urls = (
45  'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20'
46  'targetting%20Win32/Personal%20Builds/mingw-builds/installer/'
47  'repository.txt',
48  'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/'
49  'repository.txt'
50 )
51 '''
52 A list of mingw-build repositories
53 '''
54 
55 def repository(urls = urls, log = EmptyLogger()):
56  '''
57  Downloads and parse mingw-build repository files and parses them
58  '''
59  log.info('getting mingw-builds repository')
60  versions = {}
61  re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files')
62  re_sub = r'http://downloads.sourceforge.net/project/\1'
63  for url in urls:
64  log.debug(' - requesting: %s', url)
65  socket = request.urlopen(url)
66  repo = socket.read()
67  if not isinstance(repo, str):
68  repo = repo.decode();
69  socket.close()
70  for entry in repo.split('\n')[:-1]:
71  value = entry.split('|')
72  version = tuple([int(n) for n in value[0].strip().split('.')])
73  version = versions.setdefault(version, {})
74  arch = value[1].strip()
75  if arch == 'x32':
76  arch = 'i686'
77  elif arch == 'x64':
78  arch = 'x86_64'
79  arch = version.setdefault(arch, {})
80  threading = arch.setdefault(value[2].strip(), {})
81  exceptions = threading.setdefault(value[3].strip(), {})
82  revision = exceptions.setdefault(int(value[4].strip()[3:]),
83  re_sourceforge.sub(re_sub, value[5].strip()))
84  return versions
85 
86 def find_in_path(file, path=None):
87  '''
88  Attempts to find an executable in the path
89  '''
90  if platform.system() == 'Windows':
91  file += '.exe'
92  if path is None:
93  path = os.environ.get('PATH', '')
94  if type(path) is type(''):
95  path = path.split(os.pathsep)
96  return list(filter(os.path.exists,
97  map(lambda dir, file=file: os.path.join(dir, file), path)))
98 
99 def find_7zip(log = EmptyLogger()):
100  '''
101  Attempts to find 7zip for unpacking the mingw-build archives
102  '''
103  log.info('finding 7zip')
104  path = find_in_path('7z')
105  if not path:
106  key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip')
107  path, _ = winreg.QueryValueEx(key, 'Path')
108  path = [os.path.join(path, '7z.exe')]
109  log.debug('found \'%s\'', path[0])
110  return path[0]
111 
112 find_7zip()
113 
114 def unpack(archive, location, log = EmptyLogger()):
115  '''
116  Unpacks a mingw-builds archive
117  '''
118  sevenzip = find_7zip(log)
119  log.info('unpacking %s', os.path.basename(archive))
120  cmd = [sevenzip, 'x', archive, '-o' + location, '-y']
121  log.debug(' - %r', cmd)
122  with open(os.devnull, 'w') as devnull:
123  subprocess.check_call(cmd, stdout = devnull)
124 
125 def download(url, location, log = EmptyLogger()):
126  '''
127  Downloads and unpacks a mingw-builds archive
128  '''
129  log.info('downloading MinGW')
130  log.debug(' - url: %s', url)
131  log.debug(' - location: %s', location)
132 
133  re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*')
134 
135  stream = request.urlopen(url)
136  try:
137  content = stream.getheader('Content-Disposition') or ''
138  except AttributeError:
139  content = stream.headers.getheader('Content-Disposition') or ''
140  matches = re_content.match(content)
141  if matches:
142  filename = matches.group(2)
143  else:
144  parsed = parse.urlparse(stream.geturl())
145  filename = os.path.basename(parsed.path)
146 
147  try:
148  os.makedirs(location)
149  except OSError as e:
150  if e.errno == errno.EEXIST and os.path.isdir(location):
151  pass
152  else:
153  raise
154 
155  archive = os.path.join(location, filename)
156  with open(archive, 'wb') as out:
157  while True:
158  buf = stream.read(1024)
159  if not buf:
160  break
161  out.write(buf)
162  unpack(archive, location, log = log)
163  os.remove(archive)
164 
165  possible = os.path.join(location, 'mingw64')
166  if not os.path.exists(possible):
167  possible = os.path.join(location, 'mingw32')
168  if not os.path.exists(possible):
169  raise ValueError('Failed to find unpacked MinGW: ' + possible)
170  return possible
171 
172 def root(location = None, arch = None, version = None, threading = None,
173  exceptions = None, revision = None, log = EmptyLogger()):
174  '''
175  Returns the root folder of a specific version of the mingw-builds variant
176  of gcc. Will download the compiler if needed
177  '''
178 
179  # Get the repository if we don't have all the information
180  if not (arch and version and threading and exceptions and revision):
181  versions = repository(log = log)
182 
183  # Determine some defaults
184  version = version or max(versions.keys())
185  if not arch:
186  arch = platform.machine().lower()
187  if arch == 'x86':
188  arch = 'i686'
189  elif arch == 'amd64':
190  arch = 'x86_64'
191  if not threading:
192  keys = versions[version][arch].keys()
193  if 'posix' in keys:
194  threading = 'posix'
195  elif 'win32' in keys:
196  threading = 'win32'
197  else:
198  threading = keys[0]
199  if not exceptions:
200  keys = versions[version][arch][threading].keys()
201  if 'seh' in keys:
202  exceptions = 'seh'
203  elif 'sjlj' in keys:
204  exceptions = 'sjlj'
205  else:
206  exceptions = keys[0]
207  if revision == None:
208  revision = max(versions[version][arch][threading][exceptions].keys())
209  if not location:
210  location = os.path.join(tempfile.gettempdir(), 'mingw-builds')
211 
212  # Get the download url
213  url = versions[version][arch][threading][exceptions][revision]
214 
215  # Tell the user whatzzup
216  log.info('finding MinGW %s', '.'.join(str(v) for v in version))
217  log.debug(' - arch: %s', arch)
218  log.debug(' - threading: %s', threading)
219  log.debug(' - exceptions: %s', exceptions)
220  log.debug(' - revision: %s', revision)
221  log.debug(' - url: %s', url)
222 
223  # Store each specific revision differently
224  slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}'
225  slug = slug.format(
226  version = '.'.join(str(v) for v in version),
227  arch = arch,
228  threading = threading,
229  exceptions = exceptions,
230  revision = revision
231  )
232  if arch == 'x86_64':
233  root_dir = os.path.join(location, slug, 'mingw64')
234  elif arch == 'i686':
235  root_dir = os.path.join(location, slug, 'mingw32')
236  else:
237  raise ValueError('Unknown MinGW arch: ' + arch)
238 
239  # Download if needed
240  if not os.path.exists(root_dir):
241  downloaded = download(url, os.path.join(location, slug), log = log)
242  if downloaded != root_dir:
243  raise ValueError('The location of mingw did not match\n%s\n%s'
244  % (downloaded, root_dir))
245 
246  return root_dir
247 
248 def str2ver(string):
249  '''
250  Converts a version string into a tuple
251  '''
252  try:
253  version = tuple(int(v) for v in string.split('.'))
254  if len(version) is not 3:
255  raise ValueError()
256  except ValueError:
257  raise argparse.ArgumentTypeError(
258  'please provide a three digit version string')
259  return version
260 
261 def main():
262  '''
263  Invoked when the script is run directly by the python interpreter
264  '''
265  parser = argparse.ArgumentParser(
266  description = 'Downloads a specific version of MinGW',
267  formatter_class = argparse.ArgumentDefaultsHelpFormatter
268  )
269  parser.add_argument('--location',
270  help = 'the location to download the compiler to',
271  default = os.path.join(tempfile.gettempdir(), 'mingw-builds'))
272  parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'],
273  help = 'the target MinGW architecture string')
274  parser.add_argument('--version', type = str2ver,
275  help = 'the version of GCC to download')
276  parser.add_argument('--threading', choices = ['posix', 'win32'],
277  help = 'the threading type of the compiler')
278  parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'],
279  help = 'the method to throw exceptions')
280  parser.add_argument('--revision', type=int,
281  help = 'the revision of the MinGW release')
282  group = parser.add_mutually_exclusive_group()
283  group.add_argument('-v', '--verbose', action='store_true',
284  help='increase the script output verbosity')
285  group.add_argument('-q', '--quiet', action='store_true',
286  help='only print errors and warning')
287  args = parser.parse_args()
288 
289  # Create the logger
290  logger = logging.getLogger('mingw')
291  handler = logging.StreamHandler()
292  formatter = logging.Formatter('%(message)s')
293  handler.setFormatter(formatter)
294  logger.addHandler(handler)
295  logger.setLevel(logging.INFO)
296  if args.quiet:
297  logger.setLevel(logging.WARN)
298  if args.verbose:
299  logger.setLevel(logging.DEBUG)
300 
301  # Get MinGW
302  root_dir = root(location = args.location, arch = args.arch,
303  version = args.version, threading = args.threading,
304  exceptions = args.exceptions, revision = args.revision,
305  log = logger)
306 
307  sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin'))
308 
309 if __name__ == '__main__':
310  try:
311  main()
312  except IOError as e:
313  sys.stderr.write('IO error: %s\n' % e)
314  sys.exit(1)
315  except OSError as e:
316  sys.stderr.write('OS error: %s\n' % e)
317  sys.exit(1)
318  except KeyboardInterrupt as e:
319  sys.stderr.write('Killed\n')
320  sys.exit(1)
xds_interop_client.str
str
Definition: xds_interop_client.py:487
mingw.EmptyLogger.debug
def debug(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:31
keys
const void * keys
Definition: abseil-cpp/absl/random/internal/randen.cc:49
mingw.EmptyLogger.setLevel
def setLevel(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:41
mingw.EmptyLogger.warn
def warn(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:35
mingw.unpack
def unpack(archive, location, log=EmptyLogger())
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:114
mingw.EmptyLogger.critical
def critical(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:39
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
mingw.EmptyLogger.error
def error(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:37
mingw.download
def download(url, location, log=EmptyLogger())
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:125
xds_interop_client.int
int
Definition: xds_interop_client.py:113
mingw.find_7zip
def find_7zip(log=EmptyLogger())
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:99
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
mingw.repository
def repository(urls=urls, log=EmptyLogger())
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:55
mingw.main
def main()
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:261
main
Definition: main.py:1
mingw.root
def root(location=None, arch=None, version=None, threading=None, exceptions=None, revision=None, log=EmptyLogger())
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:172
open
#define open
Definition: test-fs.c:46
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
mingw.find_in_path
def find_in_path(file, path=None)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:86
split
static void split(const char *s, char ***ss, size_t *ns)
Definition: debug/trace.cc:111
mingw.EmptyLogger.info
def info(self, *k, **kw)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:33
mingw.str2ver
def str2ver(string)
Definition: bloaty/third_party/protobuf/third_party/benchmark/mingw.py:248


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:29