diff options
Diffstat (limited to 'indra/lib')
| -rwxr-xr-x | indra/lib/python/indra/util/llmanifest.py | 82 | 
1 files changed, 75 insertions, 7 deletions
| diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index d4e61aedd1..7050ce43b7 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -376,12 +376,30 @@ class LLManifest(object):          self.excludes.append(glob)      def prefix(self, src='', build=None, dst=None): -        """ Pushes a prefix onto the stack.  Until end_prefix is -        called, all relevant method calls (esp. to path()) will prefix -        paths with the entire prefix stack.  Source and destination -        prefixes can be different, though if only one is provided they -        are both equal.  To specify a no-op, use an empty string, not -        None.""" +        """ +        Usage: + +        with self.prefix(...args as described...): +            self.path(...) + +        For the duration of the 'with' block, pushes a prefix onto the stack. +        Within that block, all relevant method calls (esp. to path()) will +        prefix paths with the entire prefix stack. Source and destination +        prefixes can be different, though if only one is provided they are +        both equal. To specify a no-op, use an empty string, not None. + +        Also supports the older (pre-Python-2.5) syntax: + +        if self.prefix(...args as described...): +            self.path(...) +            self.end_prefix(...) + +        Before the arrival of the 'with' statement, one was required to code +        self.prefix() and self.end_prefix() in matching pairs to push and to +        pop the prefix stacks, respectively. The older prefix() method +        returned True specifically so that the caller could indent the +        relevant block of code with 'if', just for aesthetic purposes. +        """          if dst is None:              dst = src          if build is None: @@ -390,7 +408,57 @@ class LLManifest(object):          self.artwork_prefix.append(src)          self.build_prefix.append(build)          self.dst_prefix.append(dst) -        return True  # so that you can wrap it in an if to get indentation + +        # The above code is unchanged from the original implementation. What's +        # new is the return value. We're going to return an instance of +        # PrefixManager that binds this LLManifest instance and Does The Right +        # Thing on exit. +        return self.PrefixManager(self) + +    class PrefixManager(object): +        def __init__(self, manifest): +            self.manifest = manifest +            # stack attributes we manage in this LLManifest (sub)class +            # instance +            stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix") +            # If the caller wrote: +            # with self.prefix(...): +            # as intended, then bind the state of each prefix stack as it was +            # just BEFORE the call to prefix(). Since prefix() appended an +            # entry to each prefix stack, capture len()-1. +            self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1 +                             for stack in stacks } + +        def __nonzero__(self): +            # If the caller wrote: +            # if self.prefix(...): +            # then a value of this class had better evaluate as 'True'. +            return True + +        def __enter__(self): +            # nobody uses 'with self.prefix(...) as variable:' +            return None + +        def __exit__(self, type, value, traceback): +            # First, if the 'with' block raised an exception, just propagate. +            # Do NOT swallow it. +            if type is not None: +                return False + +            # Okay, 'with' block completed successfully. Restore previous +            # state of each of the prefix stacks in self.stacks. +            # Note that we do NOT simply call pop() on them as end_prefix() +            # does. This is to cope with the possibility that the coder +            # changed 'if self.prefix(...):' to 'with self.prefix(...):' yet +            # forgot to remove the self.end_prefix(...) call at the bottom of +            # the block. In that case, calling pop() again would be Bad! But +            # if we restore the length of each stack to what it was before the +            # current prefix() block, it doesn't matter whether end_prefix() +            # was called or not. +            for stack, prevlen in self.prevlen.items(): +                # find the attribute in 'self.manifest' named by 'stack', and +                # truncate that list back to 'prevlen' +                del getattr(self.manifest, stack)[prevlen:]      def end_prefix(self, descr=None):          """Pops a prefix off the stack.  If given an argument, checks | 
