mercurial/util.py
changeset 33439 0e114b992e02
parent 33096 d9962854a4a2
child 33446 fad6852cf879
equal deleted inserted replaced
33438:8056481caa81 33439:0e114b992e02
  3050     pos = path.rfind('/')
  3050     pos = path.rfind('/')
  3051     while pos != -1:
  3051     while pos != -1:
  3052         yield path[:pos]
  3052         yield path[:pos]
  3053         pos = path.rfind('/', 0, pos)
  3053         pos = path.rfind('/', 0, pos)
  3054 
  3054 
  3055 class ctxmanager(object):
       
  3056     '''A context manager for use in 'with' blocks to allow multiple
       
  3057     contexts to be entered at once.  This is both safer and more
       
  3058     flexible than contextlib.nested.
       
  3059 
       
  3060     Once Mercurial supports Python 2.7+, this will become mostly
       
  3061     unnecessary.
       
  3062     '''
       
  3063 
       
  3064     def __init__(self, *args):
       
  3065         '''Accepts a list of no-argument functions that return context
       
  3066         managers.  These will be invoked at __call__ time.'''
       
  3067         self._pending = args
       
  3068         self._atexit = []
       
  3069 
       
  3070     def __enter__(self):
       
  3071         return self
       
  3072 
       
  3073     def enter(self):
       
  3074         '''Create and enter context managers in the order in which they were
       
  3075         passed to the constructor.'''
       
  3076         values = []
       
  3077         for func in self._pending:
       
  3078             obj = func()
       
  3079             values.append(obj.__enter__())
       
  3080             self._atexit.append(obj.__exit__)
       
  3081         del self._pending
       
  3082         return values
       
  3083 
       
  3084     def atexit(self, func, *args, **kwargs):
       
  3085         '''Add a function to call when this context manager exits.  The
       
  3086         ordering of multiple atexit calls is unspecified, save that
       
  3087         they will happen before any __exit__ functions.'''
       
  3088         def wrapper(exc_type, exc_val, exc_tb):
       
  3089             func(*args, **kwargs)
       
  3090         self._atexit.append(wrapper)
       
  3091         return func
       
  3092 
       
  3093     def __exit__(self, exc_type, exc_val, exc_tb):
       
  3094         '''Context managers are exited in the reverse order from which
       
  3095         they were created.'''
       
  3096         received = exc_type is not None
       
  3097         suppressed = False
       
  3098         pending = None
       
  3099         self._atexit.reverse()
       
  3100         for exitfunc in self._atexit:
       
  3101             try:
       
  3102                 if exitfunc(exc_type, exc_val, exc_tb):
       
  3103                     suppressed = True
       
  3104                     exc_type = None
       
  3105                     exc_val = None
       
  3106                     exc_tb = None
       
  3107             except BaseException:
       
  3108                 pending = sys.exc_info()
       
  3109                 exc_type, exc_val, exc_tb = pending = sys.exc_info()
       
  3110         del self._atexit
       
  3111         if pending:
       
  3112             raise exc_val
       
  3113         return received and suppressed
       
  3114 
       
  3115 # compression code
  3055 # compression code
  3116 
  3056 
  3117 SERVERROLE = 'server'
  3057 SERVERROLE = 'server'
  3118 CLIENTROLE = 'client'
  3058 CLIENTROLE = 'client'
  3119 
  3059