67 httplib = pycompat.httplib |
64 httplib = pycompat.httplib |
68 pickle = pycompat.pickle |
65 pickle = pycompat.pickle |
69 queue = pycompat.queue |
66 queue = pycompat.queue |
70 safehasattr = pycompat.safehasattr |
67 safehasattr = pycompat.safehasattr |
71 socketserver = pycompat.socketserver |
68 socketserver = pycompat.socketserver |
72 stderr = pycompat.stderr |
|
73 stdin = pycompat.stdin |
|
74 stdout = pycompat.stdout |
|
75 bytesio = pycompat.bytesio |
69 bytesio = pycompat.bytesio |
76 # TODO deprecate stringio name, as it is a lie on Python 3. |
70 # TODO deprecate stringio name, as it is a lie on Python 3. |
77 stringio = bytesio |
71 stringio = bytesio |
78 xmlrpclib = pycompat.xmlrpclib |
72 xmlrpclib = pycompat.xmlrpclib |
79 |
73 |
108 cachestat = platform.cachestat |
89 cachestat = platform.cachestat |
109 checkexec = platform.checkexec |
90 checkexec = platform.checkexec |
110 checklink = platform.checklink |
91 checklink = platform.checklink |
111 copymode = platform.copymode |
92 copymode = platform.copymode |
112 expandglobs = platform.expandglobs |
93 expandglobs = platform.expandglobs |
113 explainexit = platform.explainexit |
|
114 findexe = platform.findexe |
|
115 getfsmountpoint = platform.getfsmountpoint |
94 getfsmountpoint = platform.getfsmountpoint |
116 getfstype = platform.getfstype |
95 getfstype = platform.getfstype |
117 _gethgcmd = platform.gethgcmd |
|
118 getuser = platform.getuser |
|
119 getpid = os.getpid |
|
120 groupmembers = platform.groupmembers |
96 groupmembers = platform.groupmembers |
121 groupname = platform.groupname |
97 groupname = platform.groupname |
122 hidewindow = platform.hidewindow |
|
123 isexec = platform.isexec |
98 isexec = platform.isexec |
124 isowner = platform.isowner |
99 isowner = platform.isowner |
125 listdir = osutil.listdir |
100 listdir = osutil.listdir |
126 localpath = platform.localpath |
101 localpath = platform.localpath |
127 lookupreg = platform.lookupreg |
102 lookupreg = platform.lookupreg |
134 openhardlinks = platform.openhardlinks |
109 openhardlinks = platform.openhardlinks |
135 oslink = platform.oslink |
110 oslink = platform.oslink |
136 parsepatchoutput = platform.parsepatchoutput |
111 parsepatchoutput = platform.parsepatchoutput |
137 pconvert = platform.pconvert |
112 pconvert = platform.pconvert |
138 poll = platform.poll |
113 poll = platform.poll |
139 popen = platform.popen |
|
140 posixfile = platform.posixfile |
114 posixfile = platform.posixfile |
141 quotecommand = platform.quotecommand |
|
142 readpipe = platform.readpipe |
|
143 rename = platform.rename |
115 rename = platform.rename |
144 removedirs = platform.removedirs |
116 removedirs = platform.removedirs |
145 samedevice = platform.samedevice |
117 samedevice = platform.samedevice |
146 samefile = platform.samefile |
118 samefile = platform.samefile |
147 samestat = platform.samestat |
119 samestat = platform.samestat |
148 setbinary = platform.setbinary |
|
149 setflags = platform.setflags |
120 setflags = platform.setflags |
150 setsignalhandler = platform.setsignalhandler |
|
151 shellquote = platform.shellquote |
|
152 shellsplit = platform.shellsplit |
|
153 spawndetached = platform.spawndetached |
|
154 split = platform.split |
121 split = platform.split |
155 sshargs = platform.sshargs |
|
156 statfiles = getattr(osutil, 'statfiles', platform.statfiles) |
122 statfiles = getattr(osutil, 'statfiles', platform.statfiles) |
157 statisexec = platform.statisexec |
123 statisexec = platform.statisexec |
158 statislink = platform.statislink |
124 statislink = platform.statislink |
159 testpid = platform.testpid |
|
160 umask = platform.umask |
125 umask = platform.umask |
161 unlink = platform.unlink |
126 unlink = platform.unlink |
162 username = platform.username |
127 username = platform.username |
163 |
128 |
164 try: |
129 try: |
165 recvfds = osutil.recvfds |
130 recvfds = osutil.recvfds |
166 except AttributeError: |
|
167 pass |
|
168 try: |
|
169 setprocname = osutil.setprocname |
|
170 except AttributeError: |
|
171 pass |
|
172 try: |
|
173 unblocksignal = osutil.unblocksignal |
|
174 except AttributeError: |
131 except AttributeError: |
175 pass |
132 pass |
176 |
133 |
177 # Python compatibility |
134 # Python compatibility |
178 |
135 |
461 # Empty files cannot be mmapped, but mmapread should still work. Check |
416 # Empty files cannot be mmapped, but mmapread should still work. Check |
462 # if the file is empty, and if so, return an empty buffer. |
417 # if the file is empty, and if so, return an empty buffer. |
463 if os.fstat(fd).st_size == 0: |
418 if os.fstat(fd).st_size == 0: |
464 return '' |
419 return '' |
465 raise |
420 raise |
466 |
|
467 def popen2(cmd, env=None, newlines=False): |
|
468 # Setting bufsize to -1 lets the system decide the buffer size. |
|
469 # The default for bufsize is 0, meaning unbuffered. This leads to |
|
470 # poor performance on Mac OS X: http://bugs.python.org/issue4194 |
|
471 p = subprocess.Popen(cmd, shell=True, bufsize=-1, |
|
472 close_fds=closefds, |
|
473 stdin=subprocess.PIPE, stdout=subprocess.PIPE, |
|
474 universal_newlines=newlines, |
|
475 env=env) |
|
476 return p.stdin, p.stdout |
|
477 |
|
478 def popen3(cmd, env=None, newlines=False): |
|
479 stdin, stdout, stderr, p = popen4(cmd, env, newlines) |
|
480 return stdin, stdout, stderr |
|
481 |
|
482 def popen4(cmd, env=None, newlines=False, bufsize=-1): |
|
483 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, |
|
484 close_fds=closefds, |
|
485 stdin=subprocess.PIPE, stdout=subprocess.PIPE, |
|
486 stderr=subprocess.PIPE, |
|
487 universal_newlines=newlines, |
|
488 env=env) |
|
489 return p.stdin, p.stdout, p.stderr, p |
|
490 |
421 |
491 class fileobjectproxy(object): |
422 class fileobjectproxy(object): |
492 """A proxy around file objects that tells a watcher when events occur. |
423 """A proxy around file objects that tells a watcher when events occur. |
493 |
424 |
494 This type is intended to only be used for testing purposes. Think hard |
425 This type is intended to only be used for testing purposes. Think hard |
1498 def clearcachedproperty(obj, prop): |
1429 def clearcachedproperty(obj, prop): |
1499 '''clear a cached property value, if one has been set''' |
1430 '''clear a cached property value, if one has been set''' |
1500 if prop in obj.__dict__: |
1431 if prop in obj.__dict__: |
1501 del obj.__dict__[prop] |
1432 del obj.__dict__[prop] |
1502 |
1433 |
1503 def pipefilter(s, cmd): |
|
1504 '''filter string S through command CMD, returning its output''' |
|
1505 p = subprocess.Popen(cmd, shell=True, close_fds=closefds, |
|
1506 stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
|
1507 pout, perr = p.communicate(s) |
|
1508 return pout |
|
1509 |
|
1510 def tempfilter(s, cmd): |
|
1511 '''filter string S through a pair of temporary files with CMD. |
|
1512 CMD is used as a template to create the real command to be run, |
|
1513 with the strings INFILE and OUTFILE replaced by the real names of |
|
1514 the temporary files generated.''' |
|
1515 inname, outname = None, None |
|
1516 try: |
|
1517 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-') |
|
1518 fp = os.fdopen(infd, r'wb') |
|
1519 fp.write(s) |
|
1520 fp.close() |
|
1521 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-') |
|
1522 os.close(outfd) |
|
1523 cmd = cmd.replace('INFILE', inname) |
|
1524 cmd = cmd.replace('OUTFILE', outname) |
|
1525 code = os.system(cmd) |
|
1526 if pycompat.sysplatform == 'OpenVMS' and code & 1: |
|
1527 code = 0 |
|
1528 if code: |
|
1529 raise error.Abort(_("command '%s' failed: %s") % |
|
1530 (cmd, explainexit(code))) |
|
1531 with open(outname, 'rb') as fp: |
|
1532 return fp.read() |
|
1533 finally: |
|
1534 try: |
|
1535 if inname: |
|
1536 os.unlink(inname) |
|
1537 except OSError: |
|
1538 pass |
|
1539 try: |
|
1540 if outname: |
|
1541 os.unlink(outname) |
|
1542 except OSError: |
|
1543 pass |
|
1544 |
|
1545 _filtertable = { |
|
1546 'tempfile:': tempfilter, |
|
1547 'pipe:': pipefilter, |
|
1548 } |
|
1549 |
|
1550 def filter(s, cmd): |
|
1551 "filter a string through a command that transforms its input to its output" |
|
1552 for name, fn in _filtertable.iteritems(): |
|
1553 if cmd.startswith(name): |
|
1554 return fn(s, cmd[len(name):].lstrip()) |
|
1555 return pipefilter(s, cmd) |
|
1556 |
|
1557 def increasingchunks(source, min=1024, max=65536): |
1434 def increasingchunks(source, min=1024, max=65536): |
1558 '''return no less than min bytes per chunk while data remains, |
1435 '''return no less than min bytes per chunk while data remains, |
1559 doubling min after each chunk until it reaches max''' |
1436 doubling min after each chunk until it reaches max''' |
1560 def log2(x): |
1437 def log2(x): |
1561 if not x: |
1438 if not x: |
1642 a.pop() |
1519 a.pop() |
1643 b.pop() |
1520 b.pop() |
1644 b.reverse() |
1521 b.reverse() |
1645 return pycompat.ossep.join((['..'] * len(a)) + b) or '.' |
1522 return pycompat.ossep.join((['..'] * len(a)) + b) or '.' |
1646 |
1523 |
1647 def mainfrozen(): |
|
1648 """return True if we are a frozen executable. |
|
1649 |
|
1650 The code supports py2exe (most common, Windows only) and tools/freeze |
|
1651 (portable, not much used). |
|
1652 """ |
|
1653 return (safehasattr(sys, "frozen") or # new py2exe |
|
1654 safehasattr(sys, "importers") or # old py2exe |
|
1655 imp.is_frozen(u"__main__")) # tools/freeze |
|
1656 |
|
1657 # the location of data files matching the source code |
1524 # the location of data files matching the source code |
1658 if mainfrozen() and getattr(sys, 'frozen', None) != 'macosx_app': |
1525 if procutil.mainfrozen() and getattr(sys, 'frozen', None) != 'macosx_app': |
1659 # executable version (py2exe) doesn't support __file__ |
1526 # executable version (py2exe) doesn't support __file__ |
1660 datapath = os.path.dirname(pycompat.sysexecutable) |
1527 datapath = os.path.dirname(pycompat.sysexecutable) |
1661 else: |
1528 else: |
1662 datapath = os.path.dirname(pycompat.fsencode(__file__)) |
1529 datapath = os.path.dirname(pycompat.fsencode(__file__)) |
1663 |
1530 |
1664 i18n.setdatapath(datapath) |
1531 i18n.setdatapath(datapath) |
1665 |
|
1666 _hgexecutable = None |
|
1667 |
|
1668 def hgexecutable(): |
|
1669 """return location of the 'hg' executable. |
|
1670 |
|
1671 Defaults to $HG or 'hg' in the search path. |
|
1672 """ |
|
1673 if _hgexecutable is None: |
|
1674 hg = encoding.environ.get('HG') |
|
1675 mainmod = sys.modules[r'__main__'] |
|
1676 if hg: |
|
1677 _sethgexecutable(hg) |
|
1678 elif mainfrozen(): |
|
1679 if getattr(sys, 'frozen', None) == 'macosx_app': |
|
1680 # Env variable set by py2app |
|
1681 _sethgexecutable(encoding.environ['EXECUTABLEPATH']) |
|
1682 else: |
|
1683 _sethgexecutable(pycompat.sysexecutable) |
|
1684 elif (os.path.basename( |
|
1685 pycompat.fsencode(getattr(mainmod, '__file__', ''))) == 'hg'): |
|
1686 _sethgexecutable(pycompat.fsencode(mainmod.__file__)) |
|
1687 else: |
|
1688 exe = findexe('hg') or os.path.basename(sys.argv[0]) |
|
1689 _sethgexecutable(exe) |
|
1690 return _hgexecutable |
|
1691 |
|
1692 def _sethgexecutable(path): |
|
1693 """set location of the 'hg' executable""" |
|
1694 global _hgexecutable |
|
1695 _hgexecutable = path |
|
1696 |
|
1697 def _testfileno(f, stdf): |
|
1698 fileno = getattr(f, 'fileno', None) |
|
1699 try: |
|
1700 return fileno and fileno() == stdf.fileno() |
|
1701 except io.UnsupportedOperation: |
|
1702 return False # fileno() raised UnsupportedOperation |
|
1703 |
|
1704 def isstdin(f): |
|
1705 return _testfileno(f, sys.__stdin__) |
|
1706 |
|
1707 def isstdout(f): |
|
1708 return _testfileno(f, sys.__stdout__) |
|
1709 |
|
1710 def shellenviron(environ=None): |
|
1711 """return environ with optional override, useful for shelling out""" |
|
1712 def py2shell(val): |
|
1713 'convert python object into string that is useful to shell' |
|
1714 if val is None or val is False: |
|
1715 return '0' |
|
1716 if val is True: |
|
1717 return '1' |
|
1718 return pycompat.bytestr(val) |
|
1719 env = dict(encoding.environ) |
|
1720 if environ: |
|
1721 env.update((k, py2shell(v)) for k, v in environ.iteritems()) |
|
1722 env['HG'] = hgexecutable() |
|
1723 return env |
|
1724 |
|
1725 def system(cmd, environ=None, cwd=None, out=None): |
|
1726 '''enhanced shell command execution. |
|
1727 run with environment maybe modified, maybe in different dir. |
|
1728 |
|
1729 if out is specified, it is assumed to be a file-like object that has a |
|
1730 write() method. stdout and stderr will be redirected to out.''' |
|
1731 try: |
|
1732 stdout.flush() |
|
1733 except Exception: |
|
1734 pass |
|
1735 cmd = quotecommand(cmd) |
|
1736 env = shellenviron(environ) |
|
1737 if out is None or isstdout(out): |
|
1738 rc = subprocess.call(cmd, shell=True, close_fds=closefds, |
|
1739 env=env, cwd=cwd) |
|
1740 else: |
|
1741 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds, |
|
1742 env=env, cwd=cwd, stdout=subprocess.PIPE, |
|
1743 stderr=subprocess.STDOUT) |
|
1744 for line in iter(proc.stdout.readline, ''): |
|
1745 out.write(line) |
|
1746 proc.wait() |
|
1747 rc = proc.returncode |
|
1748 if pycompat.sysplatform == 'OpenVMS' and rc & 1: |
|
1749 rc = 0 |
|
1750 return rc |
|
1751 |
1532 |
1752 def checksignature(func): |
1533 def checksignature(func): |
1753 '''wrap a function with code to check for calling errors''' |
1534 '''wrap a function with code to check for calling errors''' |
1754 def check(*args, **kwargs): |
1535 def check(*args, **kwargs): |
1755 try: |
1536 try: |
2130 Note that this function does not use os.altsep because this is |
1911 Note that this function does not use os.altsep because this is |
2131 an alternative of simple "xxx.split(os.sep)". |
1912 an alternative of simple "xxx.split(os.sep)". |
2132 It is recommended to use os.path.normpath() before using this |
1913 It is recommended to use os.path.normpath() before using this |
2133 function if need.''' |
1914 function if need.''' |
2134 return path.split(pycompat.ossep) |
1915 return path.split(pycompat.ossep) |
2135 |
|
2136 def gui(): |
|
2137 '''Are we running in a GUI?''' |
|
2138 if pycompat.isdarwin: |
|
2139 if 'SSH_CONNECTION' in encoding.environ: |
|
2140 # handle SSH access to a box where the user is logged in |
|
2141 return False |
|
2142 elif getattr(osutil, 'isgui', None): |
|
2143 # check if a CoreGraphics session is available |
|
2144 return osutil.isgui() |
|
2145 else: |
|
2146 # pure build; use a safe default |
|
2147 return True |
|
2148 else: |
|
2149 return pycompat.iswindows or encoding.environ.get("DISPLAY") |
|
2150 |
1916 |
2151 def mktempcopy(name, emptyok=False, createmode=None): |
1917 def mktempcopy(name, emptyok=False, createmode=None): |
2152 """Create a temporary file with the same contents from name |
1918 """Create a temporary file with the same contents from name |
2153 |
1919 |
2154 The permission bits are copied from the original file. |
1920 The permission bits are copied from the original file. |
2714 yield line |
2480 yield line |
2715 |
2481 |
2716 def expandpath(path): |
2482 def expandpath(path): |
2717 return os.path.expanduser(os.path.expandvars(path)) |
2483 return os.path.expanduser(os.path.expandvars(path)) |
2718 |
2484 |
2719 def hgcmd(): |
|
2720 """Return the command used to execute current hg |
|
2721 |
|
2722 This is different from hgexecutable() because on Windows we want |
|
2723 to avoid things opening new shell windows like batch files, so we |
|
2724 get either the python call or current executable. |
|
2725 """ |
|
2726 if mainfrozen(): |
|
2727 if getattr(sys, 'frozen', None) == 'macosx_app': |
|
2728 # Env variable set by py2app |
|
2729 return [encoding.environ['EXECUTABLEPATH']] |
|
2730 else: |
|
2731 return [pycompat.sysexecutable] |
|
2732 return _gethgcmd() |
|
2733 |
|
2734 def rundetached(args, condfn): |
|
2735 """Execute the argument list in a detached process. |
|
2736 |
|
2737 condfn is a callable which is called repeatedly and should return |
|
2738 True once the child process is known to have started successfully. |
|
2739 At this point, the child process PID is returned. If the child |
|
2740 process fails to start or finishes before condfn() evaluates to |
|
2741 True, return -1. |
|
2742 """ |
|
2743 # Windows case is easier because the child process is either |
|
2744 # successfully starting and validating the condition or exiting |
|
2745 # on failure. We just poll on its PID. On Unix, if the child |
|
2746 # process fails to start, it will be left in a zombie state until |
|
2747 # the parent wait on it, which we cannot do since we expect a long |
|
2748 # running process on success. Instead we listen for SIGCHLD telling |
|
2749 # us our child process terminated. |
|
2750 terminated = set() |
|
2751 def handler(signum, frame): |
|
2752 terminated.add(os.wait()) |
|
2753 prevhandler = None |
|
2754 SIGCHLD = getattr(signal, 'SIGCHLD', None) |
|
2755 if SIGCHLD is not None: |
|
2756 prevhandler = signal.signal(SIGCHLD, handler) |
|
2757 try: |
|
2758 pid = spawndetached(args) |
|
2759 while not condfn(): |
|
2760 if ((pid in terminated or not testpid(pid)) |
|
2761 and not condfn()): |
|
2762 return -1 |
|
2763 time.sleep(0.1) |
|
2764 return pid |
|
2765 finally: |
|
2766 if prevhandler is not None: |
|
2767 signal.signal(signal.SIGCHLD, prevhandler) |
|
2768 |
|
2769 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False): |
2485 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False): |
2770 """Return the result of interpolating items in the mapping into string s. |
2486 """Return the result of interpolating items in the mapping into string s. |
2771 |
2487 |
2772 prefix is a single character string, or a two character string with |
2488 prefix is a single character string, or a two character string with |
2773 a backslash as the first character if the prefix needs to be escaped in |
2489 a backslash as the first character if the prefix needs to be escaped in |
3255 yield (fnmax, fnln, func) |
2971 yield (fnmax, fnln, func) |
3256 else: |
2972 else: |
3257 yield line % (fnmax, fnln, func) |
2973 yield line % (fnmax, fnln, func) |
3258 |
2974 |
3259 def debugstacktrace(msg='stacktrace', skip=0, |
2975 def debugstacktrace(msg='stacktrace', skip=0, |
3260 f=stderr, otherf=stdout, depth=0): |
2976 f=procutil.stderr, otherf=procutil.stdout, depth=0): |
3261 '''Writes a message to f (stderr) with a nicely formatted stacktrace. |
2977 '''Writes a message to f (stderr) with a nicely formatted stacktrace. |
3262 Skips the 'skip' entries closest to the call, then show 'depth' entries. |
2978 Skips the 'skip' entries closest to the call, then show 'depth' entries. |
3263 By default it will flush stdout first. |
2979 By default it will flush stdout first. |
3264 It can be used everywhere and intentionally does not require an ui object. |
2980 It can be used everywhere and intentionally does not require an ui object. |
3265 Not be used in production code but very convenient while developing. |
2981 Not be used in production code but very convenient while developing. |
4074 parsetimezone = _deprecatedfunc(dateutil.parsetimezone, '4.6') |
3790 parsetimezone = _deprecatedfunc(dateutil.parsetimezone, '4.6') |
4075 strdate = _deprecatedfunc(dateutil.strdate, '4.6') |
3791 strdate = _deprecatedfunc(dateutil.strdate, '4.6') |
4076 parsedate = _deprecatedfunc(dateutil.parsedate, '4.6') |
3792 parsedate = _deprecatedfunc(dateutil.parsedate, '4.6') |
4077 matchdate = _deprecatedfunc(dateutil.matchdate, '4.6') |
3793 matchdate = _deprecatedfunc(dateutil.matchdate, '4.6') |
4078 |
3794 |
|
3795 stderr = procutil.stderr |
|
3796 stdin = procutil.stdin |
|
3797 stdout = procutil.stdout |
|
3798 explainexit = procutil.explainexit |
|
3799 findexe = procutil.findexe |
|
3800 getuser = procutil.getuser |
|
3801 getpid = procutil.getpid |
|
3802 hidewindow = procutil.hidewindow |
|
3803 popen = procutil.popen |
|
3804 quotecommand = procutil.quotecommand |
|
3805 readpipe = procutil.readpipe |
|
3806 setbinary = procutil.setbinary |
|
3807 setsignalhandler = procutil.setsignalhandler |
|
3808 shellquote = procutil.shellquote |
|
3809 shellsplit = procutil.shellsplit |
|
3810 spawndetached = procutil.spawndetached |
|
3811 sshargs = procutil.sshargs |
|
3812 testpid = procutil.testpid |
|
3813 try: |
|
3814 setprocname = procutil.setprocname |
|
3815 except AttributeError: |
|
3816 pass |
|
3817 try: |
|
3818 unblocksignal = procutil.unblocksignal |
|
3819 except AttributeError: |
|
3820 pass |
|
3821 closefds = procutil.closefds |
|
3822 isatty = procutil.isatty |
|
3823 popen2 = procutil.popen2 |
|
3824 popen3 = procutil.popen3 |
|
3825 popen4 = procutil.popen4 |
|
3826 pipefilter = procutil.pipefilter |
|
3827 tempfilter = procutil.tempfilter |
|
3828 filter = procutil.filter |
|
3829 mainfrozen = procutil.mainfrozen |
|
3830 hgexecutable = procutil.hgexecutable |
|
3831 isstdin = procutil.isstdin |
|
3832 isstdout = procutil.isstdout |
|
3833 shellenviron = procutil.shellenviron |
|
3834 system = procutil.system |
|
3835 gui = procutil.gui |
|
3836 hgcmd = procutil.hgcmd |
|
3837 rundetached = procutil.rundetached |
|
3838 |
4079 escapedata = _deprecatedfunc(stringutil.escapedata, '4.6') |
3839 escapedata = _deprecatedfunc(stringutil.escapedata, '4.6') |
4080 binary = _deprecatedfunc(stringutil.binary, '4.6') |
3840 binary = _deprecatedfunc(stringutil.binary, '4.6') |
4081 stringmatcher = _deprecatedfunc(stringutil.stringmatcher, '4.6') |
3841 stringmatcher = _deprecatedfunc(stringutil.stringmatcher, '4.6') |
4082 shortuser = _deprecatedfunc(stringutil.shortuser, '4.6') |
3842 shortuser = _deprecatedfunc(stringutil.shortuser, '4.6') |
4083 emailuser = _deprecatedfunc(stringutil.emailuser, '4.6') |
3843 emailuser = _deprecatedfunc(stringutil.emailuser, '4.6') |