|
6 | 6 | import optparse
|
7 | 7 | import glob
|
8 | 8 | import os
|
| 9 | +import re |
9 | 10 | import sys
|
10 | 11 | import tempfile
|
11 | 12 | import warnings
|
@@ -317,14 +318,14 @@ def __init__(self, fname=None):
|
317 | 318 | group.add_option("--workers", dest="workers", my_default=0,
|
318 | 319 | help="Specify the number of workers, 0 disable prefork mode.",
|
319 | 320 | type="int")
|
320 |
| - group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default=2048 * 1024 * 1024, |
| 321 | + group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default="2048MiB", |
321 | 322 | help="Maximum allowed virtual memory per worker (in bytes), when reached the worker be "
|
322 | 323 | "reset after the current request (default 2048MiB).",
|
323 |
| - type="int") |
324 |
| - group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default=2560 * 1024 * 1024, |
| 324 | + action="callback", callback=self._parse_size_callback, nargs=1, type="string") |
| 325 | + group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default="2560MiB", |
325 | 326 | help="Maximum allowed virtual memory per worker (in bytes), when reached, any memory "
|
326 | 327 | "allocation will fail (default 2560MiB).",
|
327 |
| - type="int") |
| 328 | + action="callback", callback=self._parse_size_callback, nargs=1, type="string") |
328 | 329 | group.add_option("--limit-time-cpu", dest="limit_time_cpu", my_default=60,
|
329 | 330 | help="Maximum allowed CPU time per request (default 60).",
|
330 | 331 | type="int")
|
@@ -492,8 +493,14 @@ def die(cond, msg):
|
492 | 493 | if getattr(opt, arg) is not None:
|
493 | 494 | self.options[arg] = getattr(opt, arg)
|
494 | 495 | # ... or keep, but cast, the config file value.
|
495 |
| - elif isinstance(self.options[arg], str) and self.casts[arg].type in optparse.Option.TYPE_CHECKER: |
496 |
| - self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg]) |
| 496 | + elif isinstance(self.options[arg], str): |
| 497 | + opt_str = '--' + arg.replace('_', '-') |
| 498 | + option = self.parser.get_option(opt_str) |
| 499 | + if option and option.callback: |
| 500 | + option.callback(option, opt, self.options[arg], self.parser) |
| 501 | + self.options[arg] = getattr(self.parser.values, arg) |
| 502 | + elif self.casts[arg].type in optparse.Option.TYPE_CHECKER: |
| 503 | + self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg]) |
497 | 504 |
|
498 | 505 | self.options['root_path'] = self._normalize(os.path.join(os.path.dirname(__file__), '..'))
|
499 | 506 | if not self.options['addons_path'] or self.options['addons_path']=='None':
|
@@ -546,6 +553,28 @@ def die(cond, msg):
|
546 | 553 | ]
|
547 | 554 | return opt
|
548 | 555 |
|
| 556 | + def _parse_size(self, text): |
| 557 | + # https://en.wikipedia.org/wiki/Binary_prefix |
| 558 | + pattern = r"""^\s*(?P<size>\d+) # integer |
| 559 | + \s*(?P<prefix>\w{2})?B? # IEC 80000-13 binary prefix |
| 560 | + \s*$""" |
| 561 | + match = re.match(pattern, text, re.VERBOSE) |
| 562 | + if not match: |
| 563 | + raise ValueError('invalid size: {size}'.format(size=repr(text))) |
| 564 | + size = int(match['size']) |
| 565 | + try: |
| 566 | + exponent = ('', 'ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi').index(match['prefix'] or '') |
| 567 | + except ValueError: |
| 568 | + raise ValueError('invalid IEC 80000-13 binary prefix: {prefix}'.format(prefix=repr(match['prefix']))) |
| 569 | + return round(size * (1024 ** exponent)) |
| 570 | + |
| 571 | + def _parse_size_callback(self, option, opt, value, parser): |
| 572 | + try: |
| 573 | + size = self._parse_size(value) |
| 574 | + except Exception as e: |
| 575 | + raise optparse.OptionValueError("option %s: %s" % (option, str(e))) |
| 576 | + setattr(parser.values, option.dest, size) |
| 577 | + |
549 | 578 | def _warn_deprecated_options(self):
|
550 | 579 | if self.options['osv_memory_age_limit']:
|
551 | 580 | warnings.warn(
|
|
0 commit comments