diff options
Diffstat (limited to 'third_party/python/python-hglib/hglib/util.py')
-rw-r--r-- | third_party/python/python-hglib/hglib/util.py | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/third_party/python/python-hglib/hglib/util.py b/third_party/python/python-hglib/hglib/util.py new file mode 100644 index 0000000000..b4bfe731f9 --- /dev/null +++ b/third_party/python/python-hglib/hglib/util.py @@ -0,0 +1,217 @@ +import os, subprocess, sys +from hglib import error +try: + from io import BytesIO +except ImportError: + from cStringIO import StringIO as BytesIO + +if sys.version_info[0] > 2: + izip = zip + integertypes = (int,) + + def b(s): + """Encode the string as bytes.""" + return s.encode('latin-1') +else: + from itertools import izip + integertypes = (long, int) + bytes = str # Defined in Python 2.6/2.7, but to the same value. + + def b(s): + """Encode the string as bytes.""" + return s + +def strtobytes(s): + """Return the bytes of the string representation of an object.""" + return str(s).encode('latin-1') + +def grouper(n, iterable): + ''' list(grouper(2, range(4))) -> [(0, 1), (2, 3)] ''' + args = [iter(iterable)] * n + return izip(*args) + +def eatlines(s, n): + """ + >>> eatlines(b("1\\n2"), 1) == b('2') + True + >>> eatlines(b("1\\n2"), 2) == b('') + True + >>> eatlines(b("1\\n2"), 3) == b('') + True + >>> eatlines(b("1\\n2\\n3"), 1) == b('2\\n3') + True + """ + cs = BytesIO(s) + + for line in cs: + n -= 1 + if n == 0: + return cs.read() + return b('') + +def skiplines(s, prefix): + """ + Skip lines starting with prefix in s + + >>> skiplines(b('a\\nb\\na\\n'), b('a')) == b('b\\na\\n') + True + >>> skiplines(b('a\\na\\n'), b('a')) == b('') + True + >>> skiplines(b(''), b('a')) == b('') + True + >>> skiplines(b('a\\nb'), b('b')) == b('a\\nb') + True + """ + cs = BytesIO(s) + + for line in cs: + if not line.startswith(prefix): + return line + cs.read() + + return b('') + +def _cmdval(val): + if isinstance(val, bytes): + return val + else: + return strtobytes(val) + +def cmdbuilder(name, *args, **kwargs): + """ + A helper for building the command arguments + + args are the positional arguments + + kwargs are the options + keys that are single lettered are prepended with '-', others with '--', + underscores are replaced with dashes + + keys with False boolean values are ignored, lists add the key multiple times + + None arguments are skipped + + >>> cmdbuilder(b('cmd'), a=True, b=False, c=None) == [b('cmd'), b('-a')] + True + >>> cmdbuilder(b('cmd'), long=True) == [b('cmd'), b('--long')] + True + >>> cmdbuilder(b('cmd'), str=b('s')) == [b('cmd'), b('--str'), b('s')] + True + >>> cmdbuilder(b('cmd'), d_ash=True) == [b('cmd'), b('--d-ash')] + True + >>> cmdbuilder(b('cmd'), _=True) == [b('cmd'), b('-')] + True + >>> expect = [b('cmd'), b('--list'), b('1'), b('--list'), b('2')] + >>> cmdbuilder(b('cmd'), list=[1, 2]) == expect + True + >>> cmdbuilder(b('cmd'), None) == [b('cmd')] + True + """ + cmd = [name] + for arg, val in kwargs.items(): + if val is None: + continue + + arg = arg.encode('latin-1').replace(b('_'), b('-')) + if arg != b('-'): + if len(arg) == 1: + arg = b('-') + arg + else: + arg = b('--') + arg + if isinstance(val, bool): + if val: + cmd.append(arg) + elif isinstance(val, list): + for v in val: + cmd.append(arg) + cmd.append(_cmdval(v)) + else: + cmd.append(arg) + cmd.append(_cmdval(val)) + + for a in args: + if a is not None: + cmd.append(a) + + return cmd + +class reterrorhandler(object): + """This class is meant to be used with rawcommand() error handler + argument. It remembers the return value the command returned if + it's one of allowed values, which is only 1 if none are given. + Otherwise it raises a CommandError. + + >>> e = reterrorhandler('') + >>> bool(e) + True + >>> e(1, 'a', '') + 'a' + >>> bool(e) + False + + """ + def __init__(self, args, allowed=None): + self.args = args + self.ret = 0 + if allowed is None: + self.allowed = [1] + else: + self.allowed = allowed + + def __call__(self, ret, out, err): + self.ret = ret + if ret not in self.allowed: + raise error.CommandError(self.args, ret, out, err) + return out + + def __nonzero__(self): + """ Returns True if the return code was 0, False otherwise """ + return self.ret == 0 + + def __bool__(self): + return self.__nonzero__() + +class propertycache(object): + """ + Decorator that remembers the return value of a function call. + + >>> execcount = 0 + >>> class obj(object): + ... def func(self): + ... global execcount + ... execcount += 1 + ... return [] + ... func = propertycache(func) + >>> o = obj() + >>> o.func + [] + >>> execcount + 1 + >>> o.func + [] + >>> execcount + 1 + """ + def __init__(self, func): + self.func = func + self.name = func.__name__ + def __get__(self, obj, type=None): + result = self.func(obj) + setattr(obj, self.name, result) + return result + +close_fds = os.name == 'posix' + +startupinfo = None +if os.name == 'nt': + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + +def popen(args, env=None): + environ = None + if env: + environ = dict(os.environ) + environ.update(env) + + return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=close_fds, + startupinfo=startupinfo, env=environ) |