forked from mirrors/gecko-dev
		
	--HG-- extra : commitid : C634LBkrODe extra : rebase_source : 839e3ccac3fe3c3dcb58288289fad1b25d92078e
		
			
				
	
	
		
			122 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
# License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
						|
 | 
						|
from __future__ import absolute_import, unicode_literals
 | 
						|
 | 
						|
from collections import OrderedDict
 | 
						|
from itertools import groupby
 | 
						|
from operator import itemgetter
 | 
						|
from os.path import dirname
 | 
						|
 | 
						|
WHITESPACE_CHARACTERS = ' \t'
 | 
						|
 | 
						|
def indentation(line):
 | 
						|
    """Number of whitespace (tab and space) characters at start of |line|."""
 | 
						|
    i = 0
 | 
						|
    while i < len(line):
 | 
						|
        if line[i] not in WHITESPACE_CHARACTERS:
 | 
						|
            break
 | 
						|
        i += 1
 | 
						|
    return i
 | 
						|
 | 
						|
def dependency_map(lines):
 | 
						|
    """Return a dictionary with keys that are targets and values that
 | 
						|
    are ordered lists of targets that should also be built.
 | 
						|
 | 
						|
    This implementation is O(n^2), but lovely and simple!  We walk the
 | 
						|
    targets in the list, and for each target we walk backwards
 | 
						|
    collecting its dependencies.  To make the walking easier, we
 | 
						|
    reverse the list so that we are always walking forwards.
 | 
						|
 | 
						|
    """
 | 
						|
    pairs = [(indentation(line), line.strip()) for line in lines]
 | 
						|
    pairs.reverse()
 | 
						|
 | 
						|
    deps = {}
 | 
						|
 | 
						|
    for i, (indent, target) in enumerate(pairs):
 | 
						|
        if not deps.has_key(target):
 | 
						|
            deps[target] = []
 | 
						|
 | 
						|
        for j in range(i+1, len(pairs)):
 | 
						|
            ind, tar = pairs[j]
 | 
						|
            if ind < indent:
 | 
						|
                indent = ind
 | 
						|
                if tar not in deps[target]:
 | 
						|
                    deps[target].append(tar)
 | 
						|
 | 
						|
    return deps
 | 
						|
 | 
						|
def all_dependencies(*targets, **kwargs):
 | 
						|
    """Return a list containing all the dependencies of |targets|.
 | 
						|
 | 
						|
    The relative order of targets is maintained if possible.
 | 
						|
 | 
						|
    """
 | 
						|
    dm = kwargs.pop('dependency_map', None)
 | 
						|
    if dm is None:
 | 
						|
        dm = dependency_map(targets)
 | 
						|
 | 
						|
    all_targets = OrderedDict() # Used as an ordered set.
 | 
						|
 | 
						|
    for target in targets:
 | 
						|
        if target in dm:
 | 
						|
            for dependency in dm[target]:
 | 
						|
                # Move element back in the ordered set.
 | 
						|
                if dependency in all_targets:
 | 
						|
                    del all_targets[dependency]
 | 
						|
                all_targets[dependency] = True
 | 
						|
 | 
						|
    return all_targets.keys()
 | 
						|
 | 
						|
def get_components(path):
 | 
						|
    """Take a path and return all the components of the path."""
 | 
						|
    paths = [path]
 | 
						|
    while True:
 | 
						|
        parent = dirname(paths[-1])
 | 
						|
        if parent == "":
 | 
						|
            break
 | 
						|
        paths.append(parent)
 | 
						|
 | 
						|
    paths.reverse()
 | 
						|
    return paths
 | 
						|
 | 
						|
def add_extra_dependencies(target_pairs, dependency_map):
 | 
						|
    """Take a list [(make_dir, make_target)] and expand (make_dir, None)
 | 
						|
    entries with extra make dependencies from |dependency_map|.
 | 
						|
 | 
						|
    Returns an iterator of pairs (make_dir, make_target).
 | 
						|
 | 
						|
    """
 | 
						|
    all_targets = OrderedDict() # Used as an ordered set.
 | 
						|
    make_dirs = OrderedDict() # Used as an ordered set.
 | 
						|
 | 
						|
    for make_target, group in groupby(target_pairs, itemgetter(1)):
 | 
						|
        # Return non-simple directory targets untouched.
 | 
						|
        if make_target is not None:
 | 
						|
            for pair in group:
 | 
						|
                # Generate dependencies for all components of a path.
 | 
						|
                # Given path a/b/c, examine a, a/b, and a/b/c in that order.
 | 
						|
                paths = get_components(pair[1])
 | 
						|
                # For each component of a path, find and add all dependencies
 | 
						|
                # to the final target list.
 | 
						|
                for target in paths:
 | 
						|
                    if target not in all_targets:
 | 
						|
                        yield pair[0], target
 | 
						|
                        all_targets[target] = True
 | 
						|
            continue
 | 
						|
 | 
						|
        # Add extra dumbmake dependencies to simple directory targets.
 | 
						|
        for make_dir, _ in group:
 | 
						|
            if make_dir not in make_dirs:
 | 
						|
                yield make_dir, None
 | 
						|
                make_dirs[make_dir] = True
 | 
						|
 | 
						|
    all_components = []
 | 
						|
    for make_dir in make_dirs.iterkeys():
 | 
						|
        all_components.extend(get_components(make_dir))
 | 
						|
 | 
						|
    for i in all_dependencies(*all_components, dependency_map=dependency_map):
 | 
						|
        if i not in make_dirs:
 | 
						|
            yield i, None
 |