python/mozbuild/dumbmake/dumbmake.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 from __future__ import unicode_literals
     7 from collections import OrderedDict
     8 from itertools import groupby
     9 from operator import itemgetter
    10 from os.path import dirname
    12 WHITESPACE_CHARACTERS = ' \t'
    14 def indentation(line):
    15     """Number of whitespace (tab and space) characters at start of |line|."""
    16     i = 0
    17     while i < len(line):
    18         if line[i] not in WHITESPACE_CHARACTERS:
    19             break
    20         i += 1
    21     return i
    23 def dependency_map(lines):
    24     """Return a dictionary with keys that are targets and values that
    25     are ordered lists of targets that should also be built.
    27     This implementation is O(n^2), but lovely and simple!  We walk the
    28     targets in the list, and for each target we walk backwards
    29     collecting its dependencies.  To make the walking easier, we
    30     reverse the list so that we are always walking forwards.
    32     """
    33     pairs = [(indentation(line), line.strip()) for line in lines]
    34     pairs.reverse()
    36     deps = {}
    38     for i, (indent, target) in enumerate(pairs):
    39         if not deps.has_key(target):
    40             deps[target] = []
    42         for j in range(i+1, len(pairs)):
    43             ind, tar = pairs[j]
    44             if ind < indent:
    45                 indent = ind
    46                 if tar not in deps[target]:
    47                     deps[target].append(tar)
    49     return deps
    51 def all_dependencies(*targets, **kwargs):
    52     """Return a list containing all the dependencies of |targets|.
    54     The relative order of targets is maintained if possible.
    56     """
    57     dm = kwargs.pop('dependency_map', None)
    58     if dm is None:
    59         dm = dependency_map(targets)
    61     all_targets = OrderedDict() # Used as an ordered set.
    63     for target in targets:
    64         if target in dm:
    65             for dependency in dm[target]:
    66                 # Move element back in the ordered set.
    67                 if dependency in all_targets:
    68                     del all_targets[dependency]
    69                 all_targets[dependency] = True
    71     return all_targets.keys()
    73 def get_components(path):
    74     """Take a path and return all the components of the path."""
    75     paths = [path]
    76     while True:
    77         parent = dirname(paths[-1])
    78         if parent == "":
    79             break
    80         paths.append(parent)
    82     paths.reverse()
    83     return paths
    85 def add_extra_dependencies(target_pairs, dependency_map):
    86     """Take a list [(make_dir, make_target)] and expand (make_dir, None)
    87     entries with extra make dependencies from |dependency_map|.
    89     Returns an iterator of pairs (make_dir, make_target).
    91     """
    92     all_targets = OrderedDict() # Used as an ordered set.
    93     make_dirs = OrderedDict() # Used as an ordered set.
    95     for make_target, group in groupby(target_pairs, itemgetter(1)):
    96         # Return non-simple directory targets untouched.
    97         if make_target is not None:
    98             for pair in group:
    99                 # Generate dependencies for all components of a path.
   100                 # Given path a/b/c, examine a, a/b, and a/b/c in that order.
   101                 paths = get_components(pair[1])
   102                 # For each component of a path, find and add all dependencies
   103                 # to the final target list.
   104                 for target in paths:
   105                     if target not in all_targets:
   106                         yield pair[0], target
   107                         all_targets[target] = True
   108             continue
   110         # Add extra dumbmake dependencies to simple directory targets.
   111         for make_dir, _ in group:
   112             if make_dir not in make_dirs:
   113                 yield make_dir, None
   114                 make_dirs[make_dir] = True
   116     all_components = []
   117     for make_dir in make_dirs.iterkeys():
   118         all_components.extend(get_components(make_dir))
   120     for i in all_dependencies(*all_components, dependency_map=dependency_map):
   121         if i not in make_dirs:
   122             yield i, None

mercurial