Source code for nestly.scons

"""SCons integration for nestly."""
from collections import OrderedDict
import os

[docs]def name_targets(func): """ Wrap a function such that returning ``'a', 'b', 'c', [1, 2, 3]`` transforms the value into ``dict(a=1, b=2, c=3)``. This is useful in the case where the last parameter is an SCons command. """ def wrap(*a, **kw): ret = func(*a, **kw) return dict(zip(ret[:-1], ret[-1])) return wrap
[docs]class SConsWrap(object): """A Nest wrapper to add SCons integration. This class wraps a Nest in order to provide methods which are useful for using nestly with SCons. A Nest passed to SConsWrap must have been created with include_outdir=True, which is the default. """ def __init__(self, nest, dest_dir='.'): """Initialize an SConsWrap. Takes the Nest to operate on and the base directory for all output directories. """ self.nest = nest self.dest_dir = dest_dir self.aggregates = OrderedDict() def __iter__(self): "Iterate over the current controls." return self.nest.iter(self.dest_dir)
[docs] def add(self, *a, **kw): "Call .add on the wrapped Nest." return self.nest.add(*a, **kw)
[docs] def add_nest(self, name=None, **kw): "A simple decorator which wraps nest.add." def deco(func): self.nest.add(name or func.__name__, func, **kw) return func return deco
[docs] def add_target(self, name=None): """Add an SCons target to this nest. The function decorated will be immediately called with each of the output directories and current control dictionaries. Each result will be added to the respective control dictionary for later nests to access. """ def deco(func): def nestfunc(control): destdir = os.path.join(self.dest_dir, control['OUTDIR']) return [func(destdir, control)] self.nest.add(name or func.__name__, nestfunc, create_dir=False) return func return deco
[docs] def add_aggregate(self, data_fac, name=None): """Add an aggregate target to this nest. The first argument is a nullary factory function which will be called immediately for each of the current control dictionaries and stored in each dictionary with the given name like in ``add_target``. After ``finalize_aggregate`` or ``finalize_all_aggregates`` are called, the decorated function will then be called in the same way as ``add_target``, except with an additional argument: the value which was returned by the factory function. Since nests added after the aggregate can access the factory function's value, it can be mutated to provide additional values for use when the decorated function is called. """ def deco(func): agg_name = name or func.__name__ finalizers = self.aggregates[agg_name] = [] @self.add_target(agg_name) def wrap(outdir, c): data = data_fac() def finalize(): return func(outdir, c, data) finalizers.append(finalize) return data return wrap return deco
[docs] def finalize_aggregate(self, aggregate): """Call the finalizers for one particular aggregate. Finalizing an aggregate this way means that it will not be finalized by any future calls to ``finalize_all_aggregates``. """ for finalizer in self.aggregates.pop(aggregate): finalizer()
[docs] def finalize_all_aggregates(self): """Call the finalizers for all defined aggregates. If any aggregates have been specifically finalized by ``finalize_aggregate``, they will not be finalized again. This function itself calls ``finalize_aggregate``; if ``finalize_all_aggregates`` is called twice, aggregates will not be finalized twice. Aggregates will be finalized in the same order in which they were defined. """ for aggregate in list(self.aggregates): self.finalize_aggregate(aggregate)