--- mozjs-78.11.0/python/mozbuild/mozbuild/util.py 2021-05-31 17:20:25.000000000 +0300 +++ mozjs-91.5.0/python/mozbuild/mozbuild/util.py 2022-01-07 17:21:02.000000000 +0300 @@ -9,6 +9,7 @@ import argparse import collections +import collections.abc import ctypes import difflib import errno @@ -22,19 +23,21 @@ import stat import sys import time -from collections import ( - OrderedDict, -) -from io import (BytesIO, StringIO) +from collections import OrderedDict +from io import BytesIO, StringIO import six -if sys.platform == 'win32': +MOZBUILD_METRICS_PATH = os.path.abspath( + os.path.join(__file__, "..", "..", "metrics.yaml") +) + +if sys.platform == "win32": _kernel32 = ctypes.windll.kernel32 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000 - system_encoding = 'mbcs' + system_encoding = "mbcs" else: - system_encoding = 'utf-8' + system_encoding = "utf-8" def exec_(object, globals=None, locals=None): @@ -54,9 +57,9 @@ def _open(path, mode): - if 'b' in mode: + if "b" in mode: return io.open(path, mode) - return io.open(path, mode, encoding='utf-8', newline='\n') + return io.open(path, mode, encoding="utf-8", newline="\n") def hash_file(path, hasher=None): @@ -66,7 +69,7 @@ # lots of cached data. Don't change it lightly. h = hasher or hashlib.sha1() - with open(path, 'rb') as fh: + with open(path, "rb") as fh: while True: data = fh.read(8192) @@ -98,20 +101,21 @@ super(ReadOnlyNamespace, self).__setattr__(k, v) def __delattr__(self, key): - raise Exception('Object does not support deletion.') + raise Exception("Object does not support deletion.") def __setattr__(self, key, value): - raise Exception('Object does not support assignment.') + raise Exception("Object does not support assignment.") def __ne__(self, other): return not (self == other) def __eq__(self, other): return self is other or ( - hasattr(other, '__dict__') and self.__dict__ == other.__dict__) + hasattr(other, "__dict__") and self.__dict__ == other.__dict__ + ) def __repr__(self): - return '<%s %r>' % (self.__class__.__name__, self.__dict__) + return "<%s %r>" % (self.__class__.__name__, self.__dict__) class ReadOnlyDict(dict): @@ -121,13 +125,13 @@ dict.__init__(self, *args, **kwargs) def __delitem__(self, key): - raise Exception('Object does not support deletion.') + raise Exception("Object does not support deletion.") def __setitem__(self, key, value): - raise Exception('Object does not support assignment.') + raise Exception("Object does not support assignment.") def update(self, *args, **kwargs): - raise Exception('Object does not support update.') + raise Exception("Object does not support update.") class undefined_default(object): @@ -174,15 +178,15 @@ raise if not_indexed: - if sys.platform == 'win32': + if sys.platform == "win32": if isinstance(path, six.string_types): fn = _kernel32.SetFileAttributesW else: fn = _kernel32.SetFileAttributesA fn(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) - elif sys.platform == 'darwin': - with open(os.path.join(path, '.metadata_never_index'), 'a'): + elif sys.platform == "darwin": + with open(os.path.join(path, ".metadata_never_index"), "a"): pass @@ -196,11 +200,12 @@ new_lines can be None, indicating a file deletion. """ - old_name = '/dev/null' if old_lines is None else filename - new_name = '/dev/null' if new_lines is None else filename + old_name = "/dev/null" if old_lines is None else filename + new_name = "/dev/null" if new_lines is None else filename - return difflib.unified_diff(old_lines or [], new_lines or [], - old_name, new_name, n=4, lineterm='') + return difflib.unified_diff( + old_lines or [], new_lines or [], old_name, new_name, n=4, lineterm="" + ) class FileAvoidWrite(BytesIO): @@ -220,17 +225,17 @@ still occur, as well as diff capture if requested. """ - def __init__(self, filename, capture_diff=False, dry_run=False, readmode='rU'): + def __init__(self, filename, capture_diff=False, dry_run=False, readmode="rU"): BytesIO.__init__(self) self.name = filename assert type(capture_diff) == bool assert type(dry_run) == bool - assert 'r' in readmode + assert "r" in readmode self._capture_diff = capture_diff self._write_to_file = not dry_run self.diff = None self.mode = readmode - self._binary_mode = 'b' in readmode + self._binary_mode = "b" in readmode def write(self, buf): BytesIO.write(self, six.ensure_binary(buf)) @@ -276,9 +281,9 @@ ensureParentDir(self.name) # Maintain 'b' if specified. 'U' only applies to modes starting with # 'r', so it is dropped. - writemode = 'w' + writemode = "w" if self._binary_mode: - writemode += 'b' + writemode += "b" buf = six.ensure_binary(buf) else: buf = six.ensure_text(buf) @@ -309,13 +314,13 @@ else: if self._binary_mode: # difflib doesn't work with bytes. - old_content = old_content.decode('utf-8') + old_content = old_content.decode("utf-8") old_lines = old_content.splitlines() if self._binary_mode: # difflib doesn't work with bytes. - new_content = new_content.decode('utf-8') + new_content = new_content.decode("utf-8") new_lines = new_content.splitlines() @@ -327,8 +332,7 @@ # This can go away once FileAvoidWrite uses io.BytesIO and # io.StringIO. But that will require a lot of work. except (UnicodeDecodeError, UnicodeEncodeError): - self.diff = ['Binary or non-ascii file changed: %s' % - self.name] + self.diff = ["Binary or non-ascii file changed: %s" % self.name] def __enter__(self): return self @@ -339,7 +343,7 @@ def resolve_target_to_make(topobjdir, target): - r''' + r""" Resolve `target` (a target, directory, or file) to a make target. `topobjdir` is the object directory; all make targets will be @@ -359,9 +363,9 @@ A Makefile resolves to the nearest parent strictly above the Makefile containing a different Makefile, and an appropriate target. - ''' + """ - target = target.replace(os.sep, '/').lstrip('/') + target = target.replace(os.sep, "/").lstrip("/") abs_target = os.path.join(topobjdir, target) # For directories, run |make -C dir|. If the directory does not @@ -371,15 +375,15 @@ current = abs_target while True: - make_path = os.path.join(current, 'Makefile') + make_path = os.path.join(current, "Makefile") if os.path.exists(make_path): - return (current[len(topobjdir) + 1:], None) + return (current[len(topobjdir) + 1 :], None) current = os.path.dirname(current) # If it's not in a directory, this is probably a top-level make # target. Treat it as such. - if '/' not in target: + if "/" not in target: return (None, target) # We have a relative path within the tree. We look for a Makefile @@ -389,11 +393,11 @@ target = os.path.basename(target) while True: - make_path = os.path.join(topobjdir, reldir, 'Makefile') + make_path = os.path.join(topobjdir, reldir, "Makefile") # We append to target every iteration, so the check below # happens exactly once. - if target != 'Makefile' and os.path.exists(make_path): + if target != "Makefile" and os.path.exists(make_path): return (reldir, target) target = os.path.join(os.path.basename(reldir), target) @@ -412,29 +416,28 @@ if iterable is None: iterable = [] if not isinstance(iterable, list): - raise ValueError('List can only be created from other list instances.') + raise ValueError("List can only be created from other list instances.") self._kwargs = kwargs return super(List, self).__init__(iterable) def extend(self, l): if not isinstance(l, list): - raise ValueError('List can only be extended with other list instances.') + raise ValueError("List can only be extended with other list instances.") return super(List, self).extend(l) def __setitem__(self, key, val): if isinstance(key, slice): if not isinstance(val, list): - raise ValueError('List can only be sliced with other list ' - 'instances.') + raise ValueError( + "List can only be sliced with other list " "instances." + ) if key.step: - raise ValueError('List cannot be sliced with a nonzero step ' - 'value') + raise ValueError("List cannot be sliced with a nonzero step " "value") # Python 2 and Python 3 do this differently for some reason. if six.PY2: - return super(List, self).__setslice__(key.start, key.stop, - val) + return super(List, self).__setslice__(key.start, key.stop, val) else: return super(List, self).__setitem__(key, val) return super(List, self).__setitem__(key, val) @@ -447,7 +450,7 @@ # variable references in moz.build behave better. other = [] if isinstance(other, (type(None), EmptyValue)) else other if not isinstance(other, list): - raise ValueError('Only lists can be appended to lists.') + raise ValueError("Only lists can be appended to lists.") new_list = self.__class__(self, **self._kwargs) new_list.extend(other) @@ -456,7 +459,7 @@ def __iadd__(self, other): other = [] if isinstance(other, (type(None), EmptyValue)) else other if not isinstance(other, list): - raise ValueError('Only lists can be appended to lists.') + raise ValueError("Only lists can be appended to lists.") return super(List, self).__iadd__(other) @@ -478,11 +481,12 @@ def __str__(self): s = StringIO() - s.write('An attempt was made to add an unsorted sequence to a list. ') - s.write('The incoming list is unsorted starting at element %d. ' % - self.i) - s.write('We expected "%s" but got "%s"' % ( - self.sorted[self.i], self.original[self.i])) + s.write("An attempt was made to add an unsorted sequence to a list. ") + s.write("The incoming list is unsorted starting at element %d. " % self.i) + s.write( + 'We expected "%s" but got "%s"' + % (self.sorted[self.i], self.original[self.i]) + ) return s.getvalue() @@ -503,6 +507,7 @@ # If the list entry is a tuple, we sort based on the first element # in the tuple. return e[0] if isinstance(e, tuple) else e + srtd = sorted(l, key=lambda x: _first_element(x).lower()) if srtd != l: @@ -538,8 +543,7 @@ class ImmutableStrictOrderingOnAppendList(StrictOrderingOnAppendList): - """Like StrictOrderingOnAppendList, but not allowing mutations of the value. - """ + """Like StrictOrderingOnAppendList, but not allowing mutations of the value.""" def append(self, elt): raise Exception("cannot use append on this type") @@ -567,23 +571,28 @@ def __init__(self, iterable=(), action=None): if not callable(action): - raise ValueError('A callable action is required to construct ' - 'a StrictOrderingOnAppendListWithAction') + raise ValueError( + "A callable action is required to construct " + "a StrictOrderingOnAppendListWithAction" + ) self._action = action if not isinstance(iterable, (tuple, list)): raise ValueError( - 'StrictOrderingOnAppendListWithAction can only be initialized ' - 'with another list') + "StrictOrderingOnAppendListWithAction can only be initialized " + "with another list" + ) iterable = [self._action(i) for i in iterable] super(StrictOrderingOnAppendListWithAction, self).__init__( - iterable, action=action) + iterable, action=action + ) def extend(self, l): if not isinstance(l, list): raise ValueError( - 'StrictOrderingOnAppendListWithAction can only be extended ' - 'with another list') + "StrictOrderingOnAppendListWithAction can only be extended " + "with another list" + ) l = [self._action(i) for i in l] return super(StrictOrderingOnAppendListWithAction, self).extend(l) @@ -591,24 +600,26 @@ if isinstance(key, slice): if not isinstance(val, list): raise ValueError( - 'StrictOrderingOnAppendListWithAction can only be sliced ' - 'with another list') + "StrictOrderingOnAppendListWithAction can only be sliced " + "with another list" + ) val = [self._action(item) for item in val] - return super(StrictOrderingOnAppendListWithAction, self).__setitem__( - key, val) + return super(StrictOrderingOnAppendListWithAction, self).__setitem__(key, val) def __add__(self, other): if not isinstance(other, list): raise ValueError( - 'StrictOrderingOnAppendListWithAction can only be added with ' - 'another list') + "StrictOrderingOnAppendListWithAction can only be added with " + "another list" + ) return super(StrictOrderingOnAppendListWithAction, self).__add__(other) def __iadd__(self, other): if not isinstance(other, list): raise ValueError( - 'StrictOrderingOnAppendListWithAction can only be added with ' - 'another list') + "StrictOrderingOnAppendListWithAction can only be added with " + "another list" + ) other = [self._action(i) for i in other] return super(StrictOrderingOnAppendListWithAction, self).__iadd__(other) @@ -639,8 +650,10 @@ def __getattr__(self, name): if name not in self.__slots__: - raise AttributeError("'%s' object has no attribute '%s'" % - (self.__class__.__name__, name)) + raise AttributeError( + "'%s' object has no attribute '%s'" + % (self.__class__.__name__, name) + ) try: return object.__getattr__(self, name) except AttributeError: @@ -650,16 +663,19 @@ def __setattr__(self, name, value): if name not in self.__slots__: - raise AttributeError("'%s' object has no attribute '%s'" % - (self.__class__.__name__, name)) + raise AttributeError( + "'%s' object has no attribute '%s'" + % (self.__class__.__name__, name) + ) if not isinstance(value, self._flags[name]): - raise TypeError("'%s' attribute of class '%s' must be '%s'" % - (name, self.__class__.__name__, - self._flags[name].__name__)) + raise TypeError( + "'%s' attribute of class '%s' must be '%s'" + % (name, self.__class__.__name__, self._flags[name].__name__) + ) return object.__setattr__(self, name, value) def __delattr__(self, name): - raise MozbuildDeletionError('Unable to delete attributes for this object') + raise MozbuildDeletionError("Unable to delete attributes for this object") return Flags @@ -687,7 +703,10 @@ foo['a'].foo = True foo['b'].bar = 'bar' """ - class StrictOrderingOnAppendListWithFlagsSpecialization(StrictOrderingOnAppendListWithFlags): + + class StrictOrderingOnAppendListWithFlagsSpecialization( + StrictOrderingOnAppendListWithFlags + ): def __init__(self, iterable=None): if iterable is None: iterable = [] @@ -704,10 +723,13 @@ def __setitem__(self, name, value): if not isinstance(name, slice): - raise TypeError("'%s' object does not support item assignment" % - self.__class__.__name__) - result = super(StrictOrderingOnAppendListWithFlagsSpecialization, - self).__setitem__(name, value) + raise TypeError( + "'%s' object does not support item assignment" + % self.__class__.__name__ + ) + result = super( + StrictOrderingOnAppendListWithFlagsSpecialization, self + ).__setitem__(name, value) # We may have removed items. for k in set(self._flags.keys()) - set(self): del self._flags[k] @@ -717,26 +739,30 @@ def _update_flags(self, other): if self._flags_type._flags != other._flags_type._flags: - raise ValueError('Expected a list of strings with flags like %s, not like %s' % - (self._flags_type._flags, other._flags_type._flags)) + raise ValueError( + "Expected a list of strings with flags like %s, not like %s" + % (self._flags_type._flags, other._flags_type._flags) + ) intersection = set(self._flags.keys()) & set(other._flags.keys()) if intersection: raise ValueError( - 'Cannot update flags: both lists of strings with flags configure %s' % - intersection - ) + "Cannot update flags: both lists of strings with flags configure %s" + % intersection + ) self._flags.update(other._flags) def extend(self, l): - result = super(StrictOrderingOnAppendListWithFlagsSpecialization, - self).extend(l) + result = super( + StrictOrderingOnAppendListWithFlagsSpecialization, self + ).extend(l) if isinstance(l, StrictOrderingOnAppendListWithFlags): self._update_flags(l) return result def __add__(self, other): - result = super(StrictOrderingOnAppendListWithFlagsSpecialization, - self).__add__(other) + result = super( + StrictOrderingOnAppendListWithFlagsSpecialization, self + ).__add__(other) if isinstance(other, StrictOrderingOnAppendListWithFlags): # Result has flags from other but not from self, since # internally we duplicate self and then extend with other, and @@ -748,8 +774,9 @@ return result def __iadd__(self, other): - result = super(StrictOrderingOnAppendListWithFlagsSpecialization, - self).__iadd__(other) + result = super( + StrictOrderingOnAppendListWithFlagsSpecialization, self + ).__iadd__(other) if isinstance(other, StrictOrderingOnAppendListWithFlags): self._update_flags(other) return result @@ -774,7 +801,8 @@ EXPORTS.mozilla.dom), and the first and last each have one element in their list. """ - __slots__ = ('_strings', '_children') + + __slots__ = ("_strings", "_children") def __init__(self): # Please change ContextDerivedTypedHierarchicalStringList in context.py @@ -782,7 +810,7 @@ self._strings = StrictOrderingOnAppendList() self._children = {} - class StringListAdaptor(collections.Sequence): + class StringListAdaptor(collections.abc.Sequence): def __init__(self, hsl): self._hsl = hsl @@ -803,13 +831,13 @@ """ if self._strings: - path_to_here = '' + path_to_here = "" yield path_to_here, self.StringListAdaptor(self) for k, l in sorted(self._children.items()): for p, v in l.walk(): - path_to_there = '%s/%s' % (k, p) - yield path_to_there.strip('/'), v + path_to_there = "%s/%s" % (k, p) + yield path_to_there.strip("/"), v def __setattr__(self, name, value): if name in self.__slots__: @@ -829,12 +857,12 @@ self._set_exportvariable(name, value) def __getattr__(self, name): - if name.startswith('__'): + if name.startswith("__"): return object.__getattr__(self, name) return self._get_exportvariable(name) def __delattr__(self, name): - raise MozbuildDeletionError('Unable to delete attributes for this object') + raise MozbuildDeletionError("Unable to delete attributes for this object") def __iadd__(self, other): if isinstance(other, HierarchicalStringList): @@ -864,8 +892,7 @@ if name in self._children: if value is self._get_exportvariable(name): return - raise KeyError('global_ns', 'reassign', - '.%s' % name) + raise KeyError("global_ns", "reassign", ".%s" % name) exports = self._get_exportvariable(name) exports._check_list(value) @@ -873,11 +900,12 @@ def _check_list(self, value): if not isinstance(value, list): - raise ValueError('Expected a list of strings, not %s' % type(value)) + raise ValueError("Expected a list of strings, not %s" % type(value)) for v in value: if not isinstance(v, six.string_types): raise ValueError( - 'Expected a list of strings, not an element of %s' % type(v)) + "Expected a list of strings, not an element of %s" % type(v) + ) class LockFile(object): @@ -921,8 +949,9 @@ # We created the lockfile, so we're the owner break except OSError as e: - if (e.errno == errno.EEXIST or - (sys.platform == "win32" and e.errno == errno.EACCES)): + if e.errno == errno.EEXIST or ( + sys.platform == "win32" and e.errno == errno.EACCES + ): pass else: # Should not occur @@ -931,7 +960,7 @@ try: # The lock file exists, try to stat it to get its age # and read its contents to report the owner PID - f = open(lockfile, 'r') + f = open(lockfile, "r") s = os.stat(lockfile) except EnvironmentError as e: if e.errno == errno.ENOENT or e.errno == errno.EACCES: @@ -939,16 +968,19 @@ # gone now. Just try again continue - raise Exception('{0} exists but stat() failed: {1}'.format( - lockfile, e.strerror)) + raise Exception( + "{0} exists but stat() failed: {1}".format(lockfile, e.strerror) + ) # We didn't create the lockfile and it's still there, check # its age now = int(time.time()) if now - s[stat.ST_MTIME] > max_wait: pid = f.readline().rstrip() - raise Exception('{0} has been locked for more than ' - '{1} seconds (PID {2})'.format(lockfile, max_wait, pid)) + raise Exception( + "{0} has been locked for more than " + "{1} seconds (PID {2})".format(lockfile, max_wait, pid) + ) # It's not been locked too long, wait a while and retry f.close() @@ -956,15 +988,15 @@ # if we get here. we have the lockfile. Convert the os.open file # descriptor into a Python file object and record our PID in it - f = os.fdopen(fd, 'w') - f.write('{0}\n'.format(os.getpid())) + f = os.fdopen(fd, "w") + f.write("{0}\n".format(os.getpid())) f.close() return LockFile(lockfile) class OrderedDefaultDict(OrderedDict): - '''A combination of OrderedDict and defaultdict.''' + """A combination of OrderedDict and defaultdict.""" def __init__(self, default_factory, *args, **kwargs): OrderedDict.__init__(self, *args, **kwargs) @@ -976,8 +1008,8 @@ class KeyedDefaultDict(dict): - '''Like a defaultdict, but the default_factory function takes the key as - argument''' + """Like a defaultdict, but the default_factory function takes the key as + argument""" def __init__(self, default_factory, *args, **kwargs): dict.__init__(self, *args, **kwargs) @@ -990,15 +1022,15 @@ class ReadOnlyKeyedDefaultDict(KeyedDefaultDict, ReadOnlyDict): - '''Like KeyedDefaultDict, but read-only.''' + """Like KeyedDefaultDict, but read-only.""" class memoize(dict): - '''A decorator to memoize the results of function calls depending + """A decorator to memoize the results of function calls depending on its arguments. Both functions and instance methods are handled, although in the instance method case, the results are cache in the instance itself. - ''' + """ def __init__(self, func): self.func = func @@ -1010,7 +1042,7 @@ return self[args] def method_call(self, instance, *args): - name = '_%s' % self.func.__name__ + name = "_%s" % self.func.__name__ if not hasattr(instance, name): setattr(instance, name, {}) cache = getattr(instance, name) @@ -1020,19 +1052,20 @@ def __get__(self, instance, cls): return functools.update_wrapper( - functools.partial(self.method_call, instance), self.func) + functools.partial(self.method_call, instance), self.func + ) class memoized_property(object): - '''A specialized version of the memoize decorator that works for + """A specialized version of the memoize decorator that works for class instance properties. - ''' + """ def __init__(self, func): self.func = func def __get__(self, instance, cls): - name = '_%s' % self.func.__name__ + name = "_%s" % self.func.__name__ if not hasattr(instance, name): setattr(instance, name, self.func(instance)) return getattr(instance, name) @@ -1077,9 +1110,10 @@ value = self[i] if not isinstance(value, ftype): - raise TypeError('field in tuple not of proper type: %s; ' - 'got %s, expected %s' % (fname, - type(value), ftype)) + raise TypeError( + "field in tuple not of proper type: %s; " + "got %s, expected %s" % (fname, type(value), ftype) + ) TypedTuple._fields = fields @@ -1088,7 +1122,7 @@ @memoize def TypedList(type, base_class=List): - '''A list with type coercion. + """A list with type coercion. The given ``type`` is what list elements are being coerced to. It may do strict validation, throwing ValueError exceptions. @@ -1097,7 +1131,8 @@ example, a Typed StrictOrderingOnAppendList can be created with: TypedList(unicode, StrictOrderingOnAppendList) - ''' + """ + class _TypedList(base_class): @staticmethod def normalize(e): @@ -1144,8 +1179,7 @@ return _TypedList -def group_unified_files(files, unified_prefix, unified_suffix, - files_per_unified_file): +def group_unified_files(files, unified_prefix, unified_suffix, files_per_unified_file): """Return an iterator of (unified_filename, source_filenames) tuples. We compile most C and C++ files in "unified mode"; instead of compiling @@ -1169,8 +1203,7 @@ dummy_fill_value = ("dummy",) def filter_out_dummy(iterable): - return six.moves.filter(lambda x: x != dummy_fill_value, - iterable) + return six.moves.filter(lambda x: x != dummy_fill_value, iterable) # From the itertools documentation, slightly modified: def grouper(n, iterable): @@ -1178,67 +1211,66 @@ args = [iter(iterable)] * n return six.moves.zip_longest(fillvalue=dummy_fill_value, *args) - for i, unified_group in enumerate(grouper(files_per_unified_file, - files)): + for i, unified_group in enumerate(grouper(files_per_unified_file, files)): just_the_filenames = list(filter_out_dummy(unified_group)) - yield '%s%d.%s' % (unified_prefix, i, unified_suffix), just_the_filenames + yield "%s%d.%s" % (unified_prefix, i, unified_suffix), just_the_filenames def pair(iterable): - '''Given an iterable, returns an iterable pairing its items. + """Given an iterable, returns an iterable pairing its items. For example, list(pair([1,2,3,4,5,6])) returns [(1,2), (3,4), (5,6)] - ''' + """ i = iter(iterable) return six.moves.zip_longest(i, i) def pairwise(iterable): - '''Given an iterable, returns an iterable of overlapped pairs of + """Given an iterable, returns an iterable of overlapped pairs of its items. Based on the Python itertools documentation. For example, list(pairwise([1,2,3,4,5,6])) returns [(1,2), (2,3), (3,4), (4,5), (5,6)] - ''' + """ a, b = itertools.tee(iterable) next(b, None) return zip(a, b) -VARIABLES_RE = re.compile('\$\((\w+)\)') +VARIABLES_RE = re.compile("\$\((\w+)\)") def expand_variables(s, variables): - '''Given a string with $(var) variable references, replace those references + """Given a string with $(var) variable references, replace those references with the corresponding entries from the given `variables` dict. If a variable value is not a string, it is iterated and its items are - joined with a whitespace.''' - result = '' + joined with a whitespace.""" + result = "" for s, name in pair(VARIABLES_RE.split(s)): result += s value = variables.get(name) if not value: continue if not isinstance(value, six.string_types): - value = ' '.join(value) + value = " ".join(value) result += value return result class DefinesAction(argparse.Action): - '''An ArgumentParser action to handle -Dvar[=value] type of arguments.''' + """An ArgumentParser action to handle -Dvar[=value] type of arguments.""" def __call__(self, parser, namespace, values, option_string): defines = getattr(namespace, self.dest) if defines is None: defines = {} - values = values.split('=', 1) + values = values.split("=", 1) if len(values) == 1: name, value = values[0], 1 else: @@ -1254,25 +1286,28 @@ class EnumString(six.text_type): - '''A string type that only can have a limited set of values, similarly to + """A string type that only can have a limited set of values, similarly to an Enum, and can only be compared against that set of values. The class is meant to be subclassed, where the subclass defines POSSIBLE_VALUES. The `subclass` method is a helper to create such subclasses. - ''' + """ + POSSIBLE_VALUES = () def __init__(self, value): if value not in self.POSSIBLE_VALUES: - raise ValueError("'%s' is not a valid value for %s" - % (value, self.__class__.__name__)) + raise ValueError( + "'%s' is not a valid value for %s" % (value, self.__class__.__name__) + ) def __eq__(self, other): if other not in self.POSSIBLE_VALUES: raise EnumStringComparisonError( - 'Can only compare with %s' - % ', '.join("'%s'" % v for v in self.POSSIBLE_VALUES)) + "Can only compare with %s" + % ", ".join("'%s'" % v for v in self.POSSIBLE_VALUES) + ) return super(EnumString, self).__eq__(other) def __ne__(self, other): @@ -1285,6 +1320,7 @@ def subclass(*possible_values): class EnumStringSubclass(EnumString): POSSIBLE_VALUES = possible_values + return EnumStringSubclass @@ -1293,7 +1329,7 @@ # quoting could be done with either ' or ". if c == "'": return "\\'" - return six.text_type(c.encode('unicode_escape')) + return six.text_type(c.encode("unicode_escape")) if six.PY2: # Delete when we get rid of Python 2. @@ -1301,43 +1337,43 @@ # counterpart, when they differ _INDENTED_REPR_TABLE = { c: e - for c, e in map(lambda x: (x, _escape_char(x)), - map(unichr, range(128))) + for c, e in map(lambda x: (x, _escape_char(x)), map(unichr, range(128))) if c != e } # Regexp matching all characters to escape. _INDENTED_REPR_RE = re.compile( - '([' + ''.join(_INDENTED_REPR_TABLE.values()) + ']+)') + "([" + "".join(_INDENTED_REPR_TABLE.values()) + "]+)" + ) def write_indented_repr(f, o, indent=4): - '''Write an indented representation (similar to repr()) of the object to the + """Write an indented representation (similar to repr()) of the object to the given file `f`. One notable difference with repr is that the returned representation assumes `from __future__ import unicode_literals`. - ''' + """ if six.PY3: pprint.pprint(o, stream=f, indent=indent) return # Delete everything below when we get rid of Python 2. - one_indent = ' ' * indent + one_indent = " " * indent def recurse_indented_repr(o, level): if isinstance(o, dict): - yield '{\n' + yield "{\n" for k, v in sorted(o.items()): yield one_indent * (level + 1) for d in recurse_indented_repr(k, level + 1): yield d - yield ': ' + yield ": " for d in recurse_indented_repr(v, level + 1): yield d - yield ',\n' + yield ",\n" yield one_indent * level - yield '}' + yield "}" elif isinstance(o, bytes): - yield 'b' + yield "b" yield repr(o) elif isinstance(o, six.text_type): yield "'" @@ -1350,23 +1386,24 @@ else: yield s yield "'" - elif hasattr(o, '__iter__'): - yield '[\n' + elif hasattr(o, "__iter__"): + yield "[\n" for i in o: yield one_indent * (level + 1) for d in recurse_indented_repr(i, level + 1): yield d - yield ',\n' + yield ",\n" yield one_indent * level - yield ']' + yield "]" else: yield repr(o) - result = ''.join(recurse_indented_repr(o, 0)) + '\n' + + result = "".join(recurse_indented_repr(o, 0)) + "\n" f.write(result) def patch_main(): - '''This is a hack to work around the fact that Windows multiprocessing needs + """This is a hack to work around the fact that Windows multiprocessing needs to import the original main module, and assumes that it corresponds to a file ending in .py. @@ -1383,92 +1420,66 @@ See also: http://bugs.python.org/issue19946 And: https://bugzilla.mozilla.org/show_bug.cgi?id=914563 - ''' + """ # XXX In Python 3.4 the multiprocessing module was re-written and the below # code is no longer valid. The Python issue19946 also claims to be fixed in # this version. It's not clear whether this hack is still needed in 3.4+ or # not, but at least some basic mach commands appear to work without it. So # skip it in 3.4+ until we determine it's still needed. - if sys.platform == 'win32' and sys.version_info < (3, 4): - import inspect + if sys.platform == "win32" and sys.version_info < (3, 4): import os from multiprocessing import forking + global orig_command_line # Figure out what multiprocessing will assume our main module # is called (see python/Lib/multiprocessing/forking.py). - main_path = getattr(sys.modules['__main__'], '__file__', None) + main_path = getattr(sys.modules["__main__"], "__file__", None) if main_path is None: # If someone deleted or modified __main__, there's nothing left for # us to do. return main_file_name = os.path.basename(main_path) main_module_name, ext = os.path.splitext(main_file_name) - if ext == '.py': + if ext == ".py": # If main is a .py file, everything ought to work as expected. return - def fork_interpose(): - import imp - import os - import sys - orig_find_module = imp.find_module - - def my_find_module(name, dirs): - if name == main_module_name: - path = os.path.join(dirs[0], main_file_name) - f = open(path) - return (f, path, ('', 'r', imp.PY_SOURCE)) - return orig_find_module(name, dirs) - - # Don't allow writing bytecode file for the main module. - orig_load_module = imp.load_module - - def my_load_module(name, file, path, description): - # multiprocess.forking invokes imp.load_module manually and - # hard-codes the name __parents_main__ as the module name. - if name == '__parents_main__': - old_bytecode = sys.dont_write_bytecode - sys.dont_write_bytecode = True - try: - return orig_load_module(name, file, path, description) - finally: - sys.dont_write_bytecode = old_bytecode - - return orig_load_module(name, file, path, description) - - imp.find_module = my_find_module - imp.load_module = my_load_module - from multiprocessing.forking import main - main() - def my_get_command_line(): - fork_code, lineno = inspect.getsourcelines(fork_interpose) - # Remove the first line (for 'def fork_interpose():') and the three - # levels of indentation (12 spaces), add our relevant globals. - fork_string = ("main_file_name = '%s'\n" % main_file_name + - "main_module_name = '%s'\n" % main_module_name + - ''.join(x[12:] for x in fork_code[1:])) + with open( + os.path.join(os.path.dirname(__file__), "fork_interpose.py"), "rU" + ) as fork_file: + fork_code = fork_file.read() + # Add our relevant globals. + fork_string = ( + "main_file_name = '%s'\n" % main_file_name + + "main_module_name = '%s'\n" % main_module_name + + fork_code + ) cmdline = orig_command_line() - cmdline[2] = fork_string + # We don't catch errors if "-c" is not found because it's not clear + # what we should do if the original command line is not of the form + # "python ... -c 'script'". + cmdline[cmdline.index("-c") + 1] = fork_string return cmdline + orig_command_line = forking.get_command_line forking.get_command_line = my_get_command_line -def ensure_bytes(value, encoding='utf-8'): +def ensure_bytes(value, encoding="utf-8"): if isinstance(value, six.text_type): return value.encode(encoding) return value -def ensure_unicode(value, encoding='utf-8'): +def ensure_unicode(value, encoding="utf-8"): if isinstance(value, six.binary_type): return value.decode(encoding) return value -def ensure_subprocess_env(env, encoding='utf-8'): +def ensure_subprocess_env(env, encoding="utf-8"): """Ensure the environment is in the correct format for the `subprocess` module. @@ -1489,3 +1500,34 @@ return time.clock() else: return time.process_time() + + +def hexdump(buf): + """ + Returns a list of hexdump-like lines corresponding to the given input buffer. + """ + assert six.PY3 + off_format = "%0{}x ".format(len(str(len(buf)))) + lines = [] + for off in range(0, len(buf), 16): + line = off_format % off + chunk = buf[off : min(off + 16, len(buf))] + for n, byte in enumerate(chunk): + line += " %02x" % byte + if n == 7: + line += " " + for n in range(len(chunk), 16): + line += " " + if n == 7: + line += " " + line += " |" + for byte in chunk: + if byte < 127 and byte >= 32: + line += chr(byte) + else: + line += "." + for n in range(len(chunk), 16): + line += " " + line += "|\n" + lines.append(line) + return lines --- mozjs-78.11.0/python/mozbuild/mozbuild/backend/configenvironment.py 2021-05-31 17:20:25.000000000 +0300 +++ mozjs-91.5.0/python/mozbuild/mozbuild/backend/configenvironment.py 2022-01-07 17:21:02.000000000 +0300 @@ -9,7 +9,8 @@ import sys import json -from collections import Iterable, OrderedDict +from collections.abc import Iterable +from collections import OrderedDict from types import ModuleType import mozpack.path as mozpath @@ -52,21 +52,18 @@ if path not in code_cache or code_cache[path][0] != mtime: # Add config.status manually to sys.modules so it gets picked up by # iter_modules_in_path() for automatic dependencies. - mod = ModuleType('config.status') + mod = ModuleType("config.status") mod.__file__ = path - sys.modules['config.status'] = mod + sys.modules["config.status"] = mod - with open(path, 'rt') as fh: + with open(path, "rt") as fh: source = fh.read() code_cache[path] = ( mtime, - compile(source, path, 'exec', dont_inherit=1) + compile(source, path, "exec", dont_inherit=1), ) - g = { - '__builtins__': __builtins__, - '__file__': path, - } + g = {"__builtins__": __builtins__, "__file__": path} l = {} try: exec(code_cache[path][1], g, l) @@ -75,7 +72,7 @@ config = BuildConfig() - for name in l['__all__']: + for name in l["__all__"]: setattr(config, name, l[name]) return config @@ -221,7 +207,7 @@ def __init__(self, config_statusd, typ, environ_override=False): self._dict = {} self._datadir = mozpath.join(config_statusd, typ) - self._config_track = mozpath.join(self._datadir, 'config.track') + self._config_track = mozpath.join(self._datadir, "config.track") self._files = set() self._environ_override = environ_override @@ -265,11 +251,11 @@ with FileAvoidWrite(self._config_track) as fh: for f in sorted(new_files): - fh.write('%s\n' % f) + fh.write("%s\n" % f) def __getitem__(self, key): if self._environ_override: - if (key not in ('CPP', 'CXXCPP', 'SHELL')) and (key in os.environ): + if (key not in ("CPP", "CXXCPP", "SHELL")) and (key in os.environ): return os.environ[key] if key not in self._dict: --- mozjs-78.11.0/testing/mozbase/manifestparser/manifestparser/filters.py 2021-05-31 17:20:25.000000000 +0300 +++ mozjs-91.5.0/testing/mozbase/manifestparser/manifestparser/filters.py 2022-01-07 17:21:02.000000000 +0300 @@ -8,11 +8,16 @@ possible to define custom filters if the built-in ones are not enough. """ -from __future__ import absolute_import +from __future__ import absolute_import, division import itertools import os -from collections import defaultdict, MutableSequence +from collections import defaultdict + +try: + from collections.abc import MutableSequence +except ImportError: + from collections import MutableSequence import six from six import string_types @@ -26,26 +31,34 @@ logger = None -def log(msg, level='info'): +def log(msg, level="info"): from mozlog import get_default_logger + global logger if not logger: - logger = get_default_logger(component='manifestparser') + logger = get_default_logger(component="manifestparser") if logger: getattr(logger, level)(msg) # built-in filters + +def _match(exprs, **values): + if any(parse(e, **values) for e in exprs.splitlines() if e): + return True + return False + + def skip_if(tests, values): """ Sets disabled on all tests containing the `skip-if` tag and whose condition is True. This filter is added by default. """ - tag = 'skip-if' + tag = "skip-if" for test in tests: - if tag in test and parse(test[tag], **values): - test.setdefault('disabled', '{}: {}'.format(tag, test[tag])) + if tag in test and _match(test[tag], **values): + test.setdefault("disabled", "{}: {}".format(tag, test[tag])) yield test @@ -54,10 +67,10 @@ Sets disabled on all tests containing the `run-if` tag and whose condition is False. This filter is added by default. """ - tag = 'run-if' + tag = "run-if" for test in tests: - if tag in test and not parse(test[tag], **values): - test.setdefault('disabled', '{}: {}'.format(tag, test[tag])) + if tag in test and not _match(test[tag], **values): + test.setdefault("disabled", "{}: {}".format(tag, test[tag])) yield test @@ -66,10 +79,10 @@ Sets expected to 'fail' on all tests containing the `fail-if` tag and whose condition is True. This filter is added by default. """ - tag = 'fail-if' + tag = "fail-if" for test in tests: - if tag in test and parse(test[tag], **values): - test['expected'] = 'fail' + if tag in test and _match(test[tag], **values): + test["expected"] = "fail" yield test @@ -79,7 +92,7 @@ added by passing `disabled=False` into `active_tests`. """ for test in tests: - if 'disabled' not in test: + if "disabled" not in test: yield test @@ -90,12 +103,13 @@ `active_tests`. """ for test in tests: - if os.path.exists(test['path']): + if os.path.exists(test["path"]): yield test # built-in instance filters + class InstanceFilter(object): """ Generally only one instance of a class filter should be applied at a time. @@ -104,14 +118,18 @@ `filterlist`. This class also formats filters' __str__ method for easier debugging. """ + unique = True __hash__ = super.__hash__ def __init__(self, *args, **kwargs): - self.fmt_args = ', '.join(itertools.chain( - [str(a) for a in args], - ['{}={}'.format(k, v) for k, v in six.iteritems(kwargs)])) + self.fmt_args = ", ".join( + itertools.chain( + [str(a) for a in args], + ["{}={}".format(k, v) for k, v in six.iteritems(kwargs)], + ) + ) def __eq__(self, other): if self.unique: @@ -145,24 +163,24 @@ # Look for conditional subsuites, and replace them with the subsuite # itself (if the condition is true), or nothing. for test in tests: - subsuite = test.get('subsuite', '') - if ',' in subsuite: + subsuite = test.get("subsuite", "") + if "," in subsuite: try: - subsuite, cond = subsuite.split(',') + subsuite, cond = subsuite.split(",") except ValueError: raise ParseError("subsuite condition can't contain commas") matched = parse(cond, **values) if matched: - test['subsuite'] = subsuite + test["subsuite"] = subsuite else: - test['subsuite'] = '' + test["subsuite"] = "" # Filter on current subsuite if self.name is None: - if not test.get('subsuite'): + if not test.get("subsuite"): yield test else: - if test.get('subsuite', '') == self.name: + if test.get("subsuite", "") == self.name: yield test @@ -180,8 +198,7 @@ def __init__(self, this_chunk, total_chunks, disabled=False): assert 1 <= this_chunk <= total_chunks - InstanceFilter.__init__(self, this_chunk, total_chunks, - disabled=disabled) + InstanceFilter.__init__(self, this_chunk, total_chunks, disabled=disabled) self.this_chunk = this_chunk self.total_chunks = total_chunks self.disabled = disabled @@ -191,9 +208,10 @@ if self.disabled: chunk_tests = tests[:] else: - chunk_tests = [t for t in tests if 'disabled' not in t] + chunk_tests = [t for t in tests if "disabled" not in t] tests_per_chunk = float(len(chunk_tests)) / self.total_chunks + # pylint: disable=W1633 start = int(round((self.this_chunk - 1) * tests_per_chunk)) end = int(round(self.this_chunk * tests_per_chunk)) @@ -241,21 +259,22 @@ tests_by_dir = defaultdict(list) ordered_dirs = [] for test in tests: - path = test['relpath'] + path = test["relpath"] if path.startswith(os.sep): path = path[1:] dirs = path.split(os.sep) - dirs = dirs[:min(self.depth, len(dirs) - 1)] + dirs = dirs[: min(self.depth, len(dirs) - 1)] path = os.sep.join(dirs) # don't count directories that only have disabled tests in them, # but still yield disabled tests that are alongside enabled tests - if path not in ordered_dirs and 'disabled' not in test: + if path not in ordered_dirs and "disabled" not in test: ordered_dirs.append(path) tests_by_dir[path].append(test) + # pylint: disable=W1633 tests_per_chunk = float(len(ordered_dirs)) / self.total_chunks start = int(round((self.this_chunk - 1) * tests_per_chunk)) end = int(round(self.this_chunk * tests_per_chunk)) @@ -268,8 +287,9 @@ # be yielded for reporting purposes. Put them all in chunk 1 for # simplicity. if self.this_chunk == 1: - disabled_dirs = [v for k, v in six.iteritems(tests_by_dir) - if k not in ordered_dirs] + disabled_dirs = [ + v for k, v in six.iteritems(tests_by_dir) if k not in ordered_dirs + ] for disabled_test in itertools.chain(*disabled_dirs): yield disabled_test @@ -282,6 +302,7 @@ :param this_chunk: the current chunk, 1 <= this_chunk <= total_chunks :param total_chunks: the total number of chunks """ + def __init__(self, this_chunk, total_chunks, *args, **kwargs): InstanceFilter.__init__(self, this_chunk, total_chunks, *args, **kwargs) self.this_chunk = this_chunk @@ -289,19 +310,24 @@ def __call__(self, tests, values): tests = list(tests) - manifests = set(t['manifest'] for t in tests) + manifests = set(t["manifest"] for t in tests) tests_by_manifest = [] for manifest in manifests: - mtests = [t for t in tests if t['manifest'] == manifest] + mtests = [t for t in tests if t["manifest"] == manifest] tests_by_manifest.append(mtests) - tests_by_manifest.sort(reverse=True, key=lambda x: (len(x), x)) + # Sort tests_by_manifest from largest manifest to shortest; include + # manifest name as secondary key to ensure consistent order across + # multiple runs. + tests_by_manifest.sort(reverse=True, key=lambda x: (len(x), x[0]["manifest"])) tests_by_chunk = [[] for i in range(self.total_chunks)] for batch in tests_by_manifest: # Sort to guarantee the chunk with the lowest score will always # get the next batch of tests. - tests_by_chunk.sort(key=lambda x: (len(x), x)) + tests_by_chunk.sort( + key=lambda x: (len(x), x[0]["manifest"] if len(x) else "") + ) tests_by_chunk[0].extend(batch) return (t for t in tests_by_chunk[self.this_chunk - 1]) @@ -327,14 +353,14 @@ @classmethod def get_manifest(cls, test): - manifest = normsep(test.get('ancestor_manifest', '')) + manifest = normsep(test.get("ancestor_manifest", "")) # Ignore ancestor_manifests that live at the root (e.g, don't have a # path separator). The only time this should happen is when they are # generated by the build system and we shouldn't count generated # manifests for chunking purposes. - if not manifest or '/' not in manifest: - manifest = normsep(test['manifest_relpath']) + if not manifest or "/" not in manifest: + manifest = normsep(test["manifest_relpath"]) return manifest def get_chunked_manifests(self, manifests): @@ -343,10 +369,15 @@ # Compute the average to use as a default for manifests that don't exist. times = [r[0] for r in runtimes] + # pylint --py3k W1619 + # pylint: disable=W1633 avg = round(sum(times) / len(times), 2) if times else 0 missing = sorted([m for m in manifests if m not in self.runtimes]) - log("Applying average runtime of {}s to the following missing manifests:\n{}".format( - avg, ' ' + '\n '.join(missing))) + log( + "Applying average runtime of {}s to the following missing manifests:\n{}".format( + avg, " " + "\n ".join(missing) + ) + ) runtimes.extend([(avg, m) for m in missing]) # Each chunk is of the form [, ]. @@ -370,8 +401,14 @@ manifests = set(self.get_manifest(t) for t in tests) chunks = self.get_chunked_manifests(manifests) runtime, this_manifests = chunks[self.this_chunk - 1] - log("Cumulative test runtime is around {} minutes (average is {} minutes)".format( - round(runtime / 60), round(sum([c[0] for c in chunks]) / (60 * len(chunks))))) + # pylint --py3k W1619 + # pylint: disable=W1633 + log( + "Cumulative test runtime is around {} minutes (average is {} minutes)".format( + round(runtime / 60), + round(sum([c[0] for c in chunks]) / (60 * len(chunks))), + ) + ) return (t for t in tests if self.get_manifest(t) in this_manifests) @@ -420,19 +487,21 @@ if isinstance(paths, string_types): paths = [paths] self.paths = paths + self.missing = set() def __call__(self, tests, values): + seen = set() for test in tests: for tp in self.paths: tp = os.path.normpath(tp) - if tp.endswith('.ini'): - mpaths = [test['manifest_relpath']] - if 'ancestor_manifest' in test: - mpaths.append(test['ancestor_manifest']) + if tp.endswith(".ini"): + mpaths = [test["manifest_relpath"]] + if "ancestor_manifest" in test: + mpaths.append(test["ancestor_manifest"]) if os.path.isabs(tp): - root = test['manifest'][:-len(test['manifest_relpath'])-1] + root = test["manifest"][: -len(test["manifest_relpath"]) - 1] mpaths = [os.path.join(root, m) for m in mpaths] # only return tests that are in this manifest @@ -440,20 +509,24 @@ continue else: # only return tests that start with this path - path = test['relpath'] + path = test["relpath"] if os.path.isabs(tp): - path = test['path'] + path = test["path"] if not os.path.normpath(path).startswith(tp): continue # any test path that points to a single file will be run no # matter what, even if it's disabled - if 'disabled' in test and os.path.normpath(test['relpath']) == tp: - del test['disabled'] + if "disabled" in test and os.path.normpath(test["relpath"]) == tp: + del test["disabled"] + + seen.add(tp) yield test break + self.missing = set(self.paths) - seen + # filter container --- mozjs-78.11.0/python/mozbuild/mozbuild/makeutil.py 2021-05-31 17:20:25.000000000 +0300 +++ mozjs-91.5.0/python/mozbuild/mozbuild/makeutil.py 2022-01-07 17:21:02.000000000 +0300 @@ -7,24 +7,24 @@ import os import re import six -from collections import Iterable +from collections.abc import Iterable class Makefile(object): - '''Provides an interface for writing simple makefiles + """Provides an interface for writing simple makefiles Instances of this class are created, populated with rules, then written. - ''' + """ def __init__(self): self._statements = [] def create_rule(self, targets=()): - ''' + """ Create a new rule in the makefile for the given targets. Returns the corresponding Rule instance. - ''' + """ targets = list(targets) for target in targets: assert isinstance(target, six.text_type) @@ -33,19 +33,19 @@ return rule def add_statement(self, statement): - ''' + """ Add a raw statement in the makefile. Meant to be used for simple variable assignments. - ''' + """ assert isinstance(statement, six.text_type) self._statements.append(statement) def dump(self, fh, removal_guard=True): - ''' + """ Dump all the rules to the given file handle. Optionally (and by default), add guard rules for file removals (empty rules for other rules' dependencies) - ''' + """ all_deps = set() all_targets = set() for statement in self._statements: @@ -54,18 +54,18 @@ all_deps.update(statement.dependencies()) all_targets.update(statement.targets()) else: - fh.write('%s\n' % statement) + fh.write("%s\n" % statement) if removal_guard: guard = Rule(sorted(all_deps - all_targets)) guard.dump(fh) class _SimpleOrderedSet(object): - ''' + """ Simple ordered set, specialized for used in Rule below only. It doesn't expose a complete API, and normalizes path separators at insertion. - ''' + """ def __init__(self): self._list = [] @@ -87,22 +87,23 @@ def _add(iterable): emitted = set() for i in iterable: - i = i.replace(os.sep, '/') + i = i.replace(os.sep, "/") if i not in self._set and i not in emitted: yield i emitted.add(i) + added = list(_add(iterable)) self._set.update(added) self._list.extend(added) class Rule(object): - '''Class handling simple rules in the form: - target1 target2 ... : dep1 dep2 ... - command1 - command2 - ... - ''' + """Class handling simple rules in the form: + target1 target2 ... : dep1 dep2 ... + command1 + command2 + ... + """ def __init__(self, targets=()): self._targets = _SimpleOrderedSet() @@ -111,9 +112,10 @@ self.add_targets(targets) def add_targets(self, targets): - '''Add additional targets to the rule.''' + """Add additional targets to the rule.""" assert isinstance(targets, Iterable) and not isinstance( - targets, six.string_types) + targets, six.string_types + ) targets = list(targets) for target in targets: assert isinstance(target, six.text_type) @@ -121,9 +123,8 @@ return self def add_dependencies(self, deps): - '''Add dependencies to the rule.''' - assert isinstance(deps, Iterable) and not isinstance( - deps, six.string_types) + """Add dependencies to the rule.""" + assert isinstance(deps, Iterable) and not isinstance(deps, six.string_types) deps = list(deps) for dep in deps: assert isinstance(dep, six.text_type) @@ -131,9 +132,10 @@ return self def add_commands(self, commands): - '''Add commands to the rule.''' + """Add commands to the rule.""" assert isinstance(commands, Iterable) and not isinstance( - commands, six.string_types) + commands, six.string_types + ) commands = list(commands) for command in commands: assert isinstance(command, six.text_type) @@ -141,35 +143,35 @@ return self def targets(self): - '''Return an iterator on the rule targets.''' + """Return an iterator on the rule targets.""" # Ensure the returned iterator is actually just that, an iterator. # Avoids caller fiddling with the set itself. return iter(self._targets) def dependencies(self): - '''Return an iterator on the rule dependencies.''' + """Return an iterator on the rule dependencies.""" return iter(d for d in self._dependencies if d not in self._targets) def commands(self): - '''Return an iterator on the rule commands.''' + """Return an iterator on the rule commands.""" return iter(self._commands) def dump(self, fh): - ''' + """ Dump the rule to the given file handle. - ''' + """ if not self._targets: return - fh.write('%s:' % ' '.join(self._targets)) + fh.write("%s:" % " ".join(self._targets)) if self._dependencies: - fh.write(' %s' % ' '.join(self.dependencies())) - fh.write('\n') + fh.write(" %s" % " ".join(self.dependencies())) + fh.write("\n") for cmd in self._commands: - fh.write('\t%s\n' % cmd) + fh.write("\t%s\n" % cmd) # colon followed by anything except a slash (Windows path detection) -_depfilesplitter = re.compile(r':(?![\\/])') +_depfilesplitter = re.compile(r":(?![\\/])") def read_dep_makefile(fh): @@ -179,30 +181,31 @@ it contains. Ignores removal guard rules. """ - rule = '' + rule = "" for line in fh.readlines(): line = six.ensure_text(line) - assert not line.startswith('\t') + assert not line.startswith("\t") line = line.strip() - if line.endswith('\\'): + if line.endswith("\\"): rule += line[:-1] else: rule += line split_rule = _depfilesplitter.split(rule, 1) if len(split_rule) > 1 and split_rule[1].strip(): - yield Rule(split_rule[0].strip().split()) \ - .add_dependencies(split_rule[1].strip().split()) - rule = '' + yield Rule(split_rule[0].strip().split()).add_dependencies( + split_rule[1].strip().split() + ) + rule = "" if rule: - raise Exception('Makefile finishes with a backslash. Expected more input.') + raise Exception("Makefile finishes with a backslash. Expected more input.") def write_dep_makefile(fh, target, deps): - ''' + """ Write a Makefile containing only target's dependencies to the file handle specified. - ''' + """ mk = Makefile() rule = mk.create_rule(targets=[target]) rule.add_dependencies(deps)