comparison tests/run-tests.py @ 44448:55c443fcb4fc

tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str() The names were not general enough because e.g. _strpath() was used for converting IP addresses.
author Manuel Jacob <me@manueljacob.de>
date Fri, 06 Mar 2020 09:50:57 +0100
parents fc70291f3d24
children ff72bd52d56a
comparison
equal deleted inserted replaced
44447:fc70291f3d24 44448:55c443fcb4fc
141 141
142 if sys.version_info > (3, 5, 0): 142 if sys.version_info > (3, 5, 0):
143 PYTHON3 = True 143 PYTHON3 = True
144 xrange = range # we use xrange in one place, and we'd rather not use range 144 xrange = range # we use xrange in one place, and we'd rather not use range
145 145
146 def _bytespath(p): 146 def _sys2bytes(p):
147 if p is None: 147 if p is None:
148 return p 148 return p
149 return p.encode('utf-8') 149 return p.encode('utf-8')
150 150
151 def _strpath(p): 151 def _bytes2sys(p):
152 if p is None: 152 if p is None:
153 return p 153 return p
154 return p.decode('utf-8') 154 return p.decode('utf-8')
155 155
156 osenvironb = getattr(os, 'environb', None) 156 osenvironb = getattr(os, 'environb', None)
163 self.__len__ = strenv.__len__ 163 self.__len__ = strenv.__len__
164 self.clear = strenv.clear 164 self.clear = strenv.clear
165 self._strenv = strenv 165 self._strenv = strenv
166 166
167 def __getitem__(self, k): 167 def __getitem__(self, k):
168 v = self._strenv.__getitem__(_strpath(k)) 168 v = self._strenv.__getitem__(_bytes2sys(k))
169 return _bytespath(v) 169 return _sys2bytes(v)
170 170
171 def __setitem__(self, k, v): 171 def __setitem__(self, k, v):
172 self._strenv.__setitem__(_strpath(k), _strpath(v)) 172 self._strenv.__setitem__(_bytes2sys(k), _bytes2sys(v))
173 173
174 def __delitem__(self, k): 174 def __delitem__(self, k):
175 self._strenv.__delitem__(_strpath(k)) 175 self._strenv.__delitem__(_bytes2sys(k))
176 176
177 def __contains__(self, k): 177 def __contains__(self, k):
178 return self._strenv.__contains__(_strpath(k)) 178 return self._strenv.__contains__(_bytes2sys(k))
179 179
180 def __iter__(self): 180 def __iter__(self):
181 return iter([_bytespath(k) for k in iter(self._strenv)]) 181 return iter([_sys2bytes(k) for k in iter(self._strenv)])
182 182
183 def get(self, k, default=None): 183 def get(self, k, default=None):
184 v = self._strenv.get(_strpath(k), _strpath(default)) 184 v = self._strenv.get(_bytes2sys(k), _bytes2sys(default))
185 return _bytespath(v) 185 return _sys2bytes(v)
186 186
187 def pop(self, k, default=None): 187 def pop(self, k, default=None):
188 v = self._strenv.pop(_strpath(k), _strpath(default)) 188 v = self._strenv.pop(_bytes2sys(k), _bytes2sys(default))
189 return _bytespath(v) 189 return _sys2bytes(v)
190 190
191 osenvironb = environbytes(os.environ) 191 osenvironb = environbytes(os.environ)
192 192
193 getcwdb = getattr(os, 'getcwdb') 193 getcwdb = getattr(os, 'getcwdb')
194 if not getcwdb or os.name == 'nt': 194 if not getcwdb or os.name == 'nt':
195 getcwdb = lambda: _bytespath(os.getcwd()) 195 getcwdb = lambda: _sys2bytes(os.getcwd())
196 196
197 elif sys.version_info >= (3, 0, 0): 197 elif sys.version_info >= (3, 0, 0):
198 print( 198 print(
199 '%s is only supported on Python 3.5+ and 2.7, not %s' 199 '%s is only supported on Python 3.5+ and 2.7, not %s'
200 % (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])) 200 % (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3]))
205 205
206 # In python 2.x, path operations are generally done using 206 # In python 2.x, path operations are generally done using
207 # bytestrings by default, so we don't have to do any extra 207 # bytestrings by default, so we don't have to do any extra
208 # fiddling there. We define the wrapper functions anyway just to 208 # fiddling there. We define the wrapper functions anyway just to
209 # help keep code consistent between platforms. 209 # help keep code consistent between platforms.
210 def _bytespath(p): 210 def _sys2bytes(p):
211 return p 211 return p
212 212
213 _strpath = _bytespath 213 _bytes2sys = _sys2bytes
214 osenvironb = os.environ 214 osenvironb = os.environ
215 getcwdb = os.getcwd 215 getcwdb = os.getcwd
216 216
217 # For Windows support 217 # For Windows support
218 wifexited = getattr(os, "WIFEXITED", lambda x: False) 218 wifexited = getattr(os, "WIFEXITED", lambda x: False)
272 272
273 273
274 def Popen4(cmd, wd, timeout, env=None): 274 def Popen4(cmd, wd, timeout, env=None):
275 processlock.acquire() 275 processlock.acquire()
276 p = subprocess.Popen( 276 p = subprocess.Popen(
277 _strpath(cmd), 277 _bytes2sys(cmd),
278 shell=True, 278 shell=True,
279 bufsize=-1, 279 bufsize=-1,
280 cwd=_strpath(wd), 280 cwd=_bytes2sys(wd),
281 env=env, 281 env=env,
282 close_fds=closefds, 282 close_fds=closefds,
283 stdin=subprocess.PIPE, 283 stdin=subprocess.PIPE,
284 stdout=subprocess.PIPE, 284 stdout=subprocess.PIPE,
285 stderr=subprocess.STDOUT, 285 stderr=subprocess.STDOUT,
313 elif os.environ.get('PYTHON'): 313 elif os.environ.get('PYTHON'):
314 sysexecutable = os.environ['PYTHON'] 314 sysexecutable = os.environ['PYTHON']
315 else: 315 else:
316 raise AssertionError('Could not find Python interpreter') 316 raise AssertionError('Could not find Python interpreter')
317 317
318 PYTHON = _bytespath(sysexecutable.replace('\\', '/')) 318 PYTHON = _sys2bytes(sysexecutable.replace('\\', '/'))
319 IMPL_PATH = b'PYTHONPATH' 319 IMPL_PATH = b'PYTHONPATH'
320 if 'java' in sys.platform: 320 if 'java' in sys.platform:
321 IMPL_PATH = b'JYTHONPATH' 321 IMPL_PATH = b'JYTHONPATH'
322 322
323 defaults = { 323 defaults = {
638 options.pure = True 638 options.pure = True
639 639
640 if options.local: 640 if options.local:
641 if options.with_hg or options.with_chg: 641 if options.with_hg or options.with_chg:
642 parser.error('--local cannot be used with --with-hg or --with-chg') 642 parser.error('--local cannot be used with --with-hg or --with-chg')
643 testdir = os.path.dirname(_bytespath(canonpath(sys.argv[0]))) 643 testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
644 reporootdir = os.path.dirname(testdir) 644 reporootdir = os.path.dirname(testdir)
645 pathandattrs = [(b'hg', 'with_hg')] 645 pathandattrs = [(b'hg', 'with_hg')]
646 if options.chg: 646 if options.chg:
647 pathandattrs.append((b'contrib/chg/chg', 'with_chg')) 647 pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
648 for relpath, attr in pathandattrs: 648 for relpath, attr in pathandattrs:
650 if os.name != 'nt' and not os.access(binpath, os.X_OK): 650 if os.name != 'nt' and not os.access(binpath, os.X_OK):
651 parser.error( 651 parser.error(
652 '--local specified, but %r not found or ' 652 '--local specified, but %r not found or '
653 'not executable' % binpath 653 'not executable' % binpath
654 ) 654 )
655 setattr(options, attr, _strpath(binpath)) 655 setattr(options, attr, _bytes2sys(binpath))
656 656
657 if options.with_hg: 657 if options.with_hg:
658 options.with_hg = canonpath(_bytespath(options.with_hg)) 658 options.with_hg = canonpath(_sys2bytes(options.with_hg))
659 if not ( 659 if not (
660 os.path.isfile(options.with_hg) 660 os.path.isfile(options.with_hg)
661 and os.access(options.with_hg, os.X_OK) 661 and os.access(options.with_hg, os.X_OK)
662 ): 662 ):
663 parser.error('--with-hg must specify an executable hg script') 663 parser.error('--with-hg must specify an executable hg script')
667 667
668 if (options.chg or options.with_chg) and os.name == 'nt': 668 if (options.chg or options.with_chg) and os.name == 'nt':
669 parser.error('chg does not work on %s' % os.name) 669 parser.error('chg does not work on %s' % os.name)
670 if options.with_chg: 670 if options.with_chg:
671 options.chg = False # no installation to temporary location 671 options.chg = False # no installation to temporary location
672 options.with_chg = canonpath(_bytespath(options.with_chg)) 672 options.with_chg = canonpath(_sys2bytes(options.with_chg))
673 if not ( 673 if not (
674 os.path.isfile(options.with_chg) 674 os.path.isfile(options.with_chg)
675 and os.access(options.with_chg, os.X_OK) 675 and os.access(options.with_chg, os.X_OK)
676 ): 676 ):
677 parser.error('--with-chg must specify a chg executable') 677 parser.error('--with-chg must specify a chg executable')
940 startport = defaults['port'] 940 startport = defaults['port']
941 if slowtimeout is None: 941 if slowtimeout is None:
942 slowtimeout = defaults['slowtimeout'] 942 slowtimeout = defaults['slowtimeout']
943 self.path = path 943 self.path = path
944 self.bname = os.path.basename(path) 944 self.bname = os.path.basename(path)
945 self.name = _strpath(self.bname) 945 self.name = _bytes2sys(self.bname)
946 self._testdir = os.path.dirname(path) 946 self._testdir = os.path.dirname(path)
947 self._outputdir = outputdir 947 self._outputdir = outputdir
948 self._tmpname = os.path.basename(path) 948 self._tmpname = os.path.basename(path)
949 self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname) 949 self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname)
950 950
954 self._first = first 954 self._first = first
955 self._timeout = timeout 955 self._timeout = timeout
956 self._slowtimeout = slowtimeout 956 self._slowtimeout = slowtimeout
957 self._startport = startport 957 self._startport = startport
958 self._extraconfigopts = extraconfigopts or [] 958 self._extraconfigopts = extraconfigopts or []
959 self._shell = _bytespath(shell) 959 self._shell = _sys2bytes(shell)
960 self._hgcommand = hgcommand or b'hg' 960 self._hgcommand = hgcommand or b'hg'
961 self._usechg = usechg 961 self._usechg = usechg
962 self._useipv6 = useipv6 962 self._useipv6 = useipv6
963 963
964 self._aborted = False 964 self._aborted = False
1266 def _genrestoreenv(self, testenv): 1266 def _genrestoreenv(self, testenv):
1267 """Generate a script that can be used by tests to restore the original 1267 """Generate a script that can be used by tests to restore the original
1268 environment.""" 1268 environment."""
1269 # Put the restoreenv script inside self._threadtmp 1269 # Put the restoreenv script inside self._threadtmp
1270 scriptpath = os.path.join(self._threadtmp, b'restoreenv.sh') 1270 scriptpath = os.path.join(self._threadtmp, b'restoreenv.sh')
1271 testenv['HGTEST_RESTOREENV'] = _strpath(scriptpath) 1271 testenv['HGTEST_RESTOREENV'] = _bytes2sys(scriptpath)
1272 1272
1273 # Only restore environment variable names that the shell allows 1273 # Only restore environment variable names that the shell allows
1274 # us to export. 1274 # us to export.
1275 name_regex = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$') 1275 name_regex = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$')
1276 1276
1300 env["HGPORT%s" % offset] = '%s' % (self._startport + i) 1300 env["HGPORT%s" % offset] = '%s' % (self._startport + i)
1301 1301
1302 env = os.environ.copy() 1302 env = os.environ.copy()
1303 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or '' 1303 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or ''
1304 env['HGEMITWARNINGS'] = '1' 1304 env['HGEMITWARNINGS'] = '1'
1305 env['TESTTMP'] = _strpath(self._testtmp) 1305 env['TESTTMP'] = _bytes2sys(self._testtmp)
1306 env['TESTNAME'] = self.name 1306 env['TESTNAME'] = self.name
1307 env['HOME'] = _strpath(self._testtmp) 1307 env['HOME'] = _bytes2sys(self._testtmp)
1308 # This number should match portneeded in _getport 1308 # This number should match portneeded in _getport
1309 for port in xrange(3): 1309 for port in xrange(3):
1310 # This list should be parallel to _portmap in _getreplacements 1310 # This list should be parallel to _portmap in _getreplacements
1311 defineport(port) 1311 defineport(port)
1312 env["HGRCPATH"] = _strpath(os.path.join(self._threadtmp, b'.hgrc')) 1312 env["HGRCPATH"] = _bytes2sys(os.path.join(self._threadtmp, b'.hgrc'))
1313 env["DAEMON_PIDS"] = _strpath( 1313 env["DAEMON_PIDS"] = _bytes2sys(
1314 os.path.join(self._threadtmp, b'daemon.pids') 1314 os.path.join(self._threadtmp, b'daemon.pids')
1315 ) 1315 )
1316 env["HGEDITOR"] = ( 1316 env["HGEDITOR"] = (
1317 '"' + sysexecutable + '"' + ' -c "import sys; sys.exit(0)"' 1317 '"' + sysexecutable + '"' + ' -c "import sys; sys.exit(0)"'
1318 ) 1318 )
1340 if extraextensions: 1340 if extraextensions:
1341 env['HGTESTEXTRAEXTENSIONS'] = b' '.join(extraextensions) 1341 env['HGTESTEXTRAEXTENSIONS'] = b' '.join(extraextensions)
1342 1342
1343 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw 1343 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
1344 # IP addresses. 1344 # IP addresses.
1345 env['LOCALIP'] = _strpath(self._localip()) 1345 env['LOCALIP'] = _bytes2sys(self._localip())
1346 1346
1347 # This has the same effect as Py_LegacyWindowsStdioFlag in exewrapper.c, 1347 # This has the same effect as Py_LegacyWindowsStdioFlag in exewrapper.c,
1348 # but this is needed for testing python instances like dummyssh, 1348 # but this is needed for testing python instances like dummyssh,
1349 # dummysmtpd.py, and dumbhttp.py. 1349 # dummysmtpd.py, and dumbhttp.py.
1350 if PYTHON3 and os.name == 'nt': 1350 if PYTHON3 and os.name == 'nt':
1449 1449
1450 Return a tuple (exitcode, output). output is None in debug mode. 1450 Return a tuple (exitcode, output). output is None in debug mode.
1451 """ 1451 """
1452 if self._debug: 1452 if self._debug:
1453 proc = subprocess.Popen( 1453 proc = subprocess.Popen(
1454 _strpath(cmd), shell=True, cwd=_strpath(self._testtmp), env=env 1454 _bytes2sys(cmd),
1455 shell=True,
1456 cwd=_bytes2sys(self._testtmp),
1457 env=env,
1455 ) 1458 )
1456 ret = proc.wait() 1459 ret = proc.wait()
1457 return (ret, None) 1460 return (ret, None)
1458 1461
1459 proc = Popen4(cmd, self._testtmp, self._timeout, env) 1462 proc = Popen4(cmd, self._testtmp, self._timeout, env)
1559 self._case = case 1562 self._case = case
1560 self._allcases = {x for y in parsettestcases(path) for x in y} 1563 self._allcases = {x for y in parsettestcases(path) for x in y}
1561 super(TTest, self).__init__(path, *args, **kwds) 1564 super(TTest, self).__init__(path, *args, **kwds)
1562 if case: 1565 if case:
1563 casepath = b'#'.join(case) 1566 casepath = b'#'.join(case)
1564 self.name = '%s#%s' % (self.name, _strpath(casepath)) 1567 self.name = '%s#%s' % (self.name, _bytes2sys(casepath))
1565 self.errpath = b'%s#%s.err' % (self.errpath[:-4], casepath) 1568 self.errpath = b'%s#%s.err' % (self.errpath[:-4], casepath)
1566 self._tmpname += b'-%s' % casepath 1569 self._tmpname += b'-%s' % casepath
1567 self._have = {} 1570 self._have = {}
1568 1571
1569 @property 1572 @property
1610 1613
1611 if allreqs in self._have: 1614 if allreqs in self._have:
1612 return self._have.get(allreqs) 1615 return self._have.get(allreqs)
1613 1616
1614 # TODO do something smarter when all other uses of hghave are gone. 1617 # TODO do something smarter when all other uses of hghave are gone.
1615 runtestdir = os.path.abspath(os.path.dirname(_bytespath(__file__))) 1618 runtestdir = os.path.abspath(os.path.dirname(_sys2bytes(__file__)))
1616 tdir = runtestdir.replace(b'\\', b'/') 1619 tdir = runtestdir.replace(b'\\', b'/')
1617 proc = Popen4( 1620 proc = Popen4(
1618 b'%s -c "%s/hghave %s"' % (self._shell, tdir, allreqs), 1621 b'%s -c "%s/hghave %s"' % (self._shell, tdir, allreqs),
1619 self._testtmp, 1622 self._testtmp,
1620 0, 1623 0,
2197 pass 2200 pass
2198 elif self._options.view: 2201 elif self._options.view:
2199 v = self._options.view 2202 v = self._options.view
2200 subprocess.call( 2203 subprocess.call(
2201 r'"%s" "%s" "%s"' 2204 r'"%s" "%s" "%s"'
2202 % (v, _strpath(test.refpath), _strpath(test.errpath)), 2205 % (v, _bytes2sys(test.refpath), _bytes2sys(test.errpath)),
2203 shell=True, 2206 shell=True,
2204 ) 2207 )
2205 else: 2208 else:
2206 servefail, lines = getdiff( 2209 servefail, lines = getdiff(
2207 expected, got, test.refpath, test.errpath 2210 expected, got, test.refpath, test.errpath
2686 # TODO: we probably need to forward more options 2689 # TODO: we probably need to forward more options
2687 # that alter hg's behavior inside the tests. 2690 # that alter hg's behavior inside the tests.
2688 opts = '' 2691 opts = ''
2689 withhg = self._runner.options.with_hg 2692 withhg = self._runner.options.with_hg
2690 if withhg: 2693 if withhg:
2691 opts += ' --with-hg=%s ' % shellquote(_strpath(withhg)) 2694 opts += ' --with-hg=%s ' % shellquote(_bytes2sys(withhg))
2692 rtc = '%s %s %s %s' % (sysexecutable, sys.argv[0], opts, test) 2695 rtc = '%s %s %s %s' % (sysexecutable, sys.argv[0], opts, test)
2693 data = pread(bisectcmd + ['--command', rtc]) 2696 data = pread(bisectcmd + ['--command', rtc])
2694 m = re.search( 2697 m = re.search(
2695 ( 2698 (
2696 br'\nThe first (?P<goodbad>bad|good) revision ' 2699 br'\nThe first (?P<goodbad>bad|good) revision '
2928 """Run the test suite.""" 2931 """Run the test suite."""
2929 oldmask = os.umask(0o22) 2932 oldmask = os.umask(0o22)
2930 try: 2933 try:
2931 parser = parser or getparser() 2934 parser = parser or getparser()
2932 options = parseargs(args, parser) 2935 options = parseargs(args, parser)
2933 tests = [_bytespath(a) for a in options.tests] 2936 tests = [_sys2bytes(a) for a in options.tests]
2934 if options.test_list is not None: 2937 if options.test_list is not None:
2935 for listfile in options.test_list: 2938 for listfile in options.test_list:
2936 with open(listfile, 'rb') as f: 2939 with open(listfile, 'rb') as f:
2937 tests.extend(t for t in f.read().splitlines() if t) 2940 tests.extend(t for t in f.read().splitlines() if t)
2938 self.options = options 2941 self.options = options
2960 pathname = os.path.dirname(testdescs[0]['path']) 2963 pathname = os.path.dirname(testdescs[0]['path'])
2961 if pathname: 2964 if pathname:
2962 testdir = os.path.join(testdir, pathname) 2965 testdir = os.path.join(testdir, pathname)
2963 self._testdir = osenvironb[b'TESTDIR'] = testdir 2966 self._testdir = osenvironb[b'TESTDIR'] = testdir
2964 if self.options.outputdir: 2967 if self.options.outputdir:
2965 self._outputdir = canonpath(_bytespath(self.options.outputdir)) 2968 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
2966 else: 2969 else:
2967 self._outputdir = getcwdb() 2970 self._outputdir = getcwdb()
2968 if testdescs and pathname: 2971 if testdescs and pathname:
2969 self._outputdir = os.path.join(self._outputdir, pathname) 2972 self._outputdir = os.path.join(self._outputdir, pathname)
2970 previoustimes = {} 2973 previoustimes = {}
2977 # we do the randomness ourself to know what seed is used 2980 # we do the randomness ourself to know what seed is used
2978 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32)) 2981 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
2979 2982
2980 if self.options.tmpdir: 2983 if self.options.tmpdir:
2981 self.options.keep_tmpdir = True 2984 self.options.keep_tmpdir = True
2982 tmpdir = _bytespath(self.options.tmpdir) 2985 tmpdir = _sys2bytes(self.options.tmpdir)
2983 if os.path.exists(tmpdir): 2986 if os.path.exists(tmpdir):
2984 # Meaning of tmpdir has changed since 1.3: we used to create 2987 # Meaning of tmpdir has changed since 1.3: we used to create
2985 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if 2988 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
2986 # tmpdir already exists. 2989 # tmpdir already exists.
2987 print("error: temp dir %r already exists" % tmpdir) 2990 print("error: temp dir %r already exists" % tmpdir)
3006 self._hgcommand = os.path.basename(whg) 3009 self._hgcommand = os.path.basename(whg)
3007 self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin') 3010 self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
3008 os.makedirs(self._tmpbindir) 3011 os.makedirs(self._tmpbindir)
3009 3012
3010 normbin = os.path.normpath(os.path.abspath(whg)) 3013 normbin = os.path.normpath(os.path.abspath(whg))
3011 normbin = normbin.replace(_bytespath(os.sep), b'/') 3014 normbin = normbin.replace(_sys2bytes(os.sep), b'/')
3012 3015
3013 # Other Python scripts in the test harness need to 3016 # Other Python scripts in the test harness need to
3014 # `import mercurial`. If `hg` is a Python script, we assume 3017 # `import mercurial`. If `hg` is a Python script, we assume
3015 # the Mercurial modules are relative to its path and tell the tests 3018 # the Mercurial modules are relative to its path and tell the tests
3016 # to load Python modules from its directory. 3019 # to load Python modules from its directory.
3055 self._hgcommand = os.path.basename(self.options.with_chg) 3058 self._hgcommand = os.path.basename(self.options.with_chg)
3056 3059
3057 osenvironb[b"BINDIR"] = self._bindir 3060 osenvironb[b"BINDIR"] = self._bindir
3058 osenvironb[b"PYTHON"] = PYTHON 3061 osenvironb[b"PYTHON"] = PYTHON
3059 3062
3060 fileb = _bytespath(__file__) 3063 fileb = _sys2bytes(__file__)
3061 runtestdir = os.path.abspath(os.path.dirname(fileb)) 3064 runtestdir = os.path.abspath(os.path.dirname(fileb))
3062 osenvironb[b'RUNTESTDIR'] = runtestdir 3065 osenvironb[b'RUNTESTDIR'] = runtestdir
3063 if PYTHON3: 3066 if PYTHON3:
3064 sepb = _bytespath(os.pathsep) 3067 sepb = _sys2bytes(os.pathsep)
3065 else: 3068 else:
3066 sepb = os.pathsep 3069 sepb = os.pathsep
3067 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb) 3070 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
3068 if os.path.islink(__file__): 3071 if os.path.islink(__file__):
3069 # test helper will likely be at the end of the symlink 3072 # test helper will likely be at the end of the symlink
3119 logexceptions = os.path.join(self._testdir, b'logexceptions.py') 3122 logexceptions = os.path.join(self._testdir, b'logexceptions.py')
3120 self.options.extra_config_opt.append( 3123 self.options.extra_config_opt.append(
3121 'extensions.logexceptions=%s' % logexceptions.decode('utf-8') 3124 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
3122 ) 3125 )
3123 3126
3124 vlog("# Using TESTDIR", _strpath(self._testdir)) 3127 vlog("# Using TESTDIR", _bytes2sys(self._testdir))
3125 vlog("# Using RUNTESTDIR", _strpath(osenvironb[b'RUNTESTDIR'])) 3128 vlog("# Using RUNTESTDIR", _bytes2sys(osenvironb[b'RUNTESTDIR']))
3126 vlog("# Using HGTMP", _strpath(self._hgtmp)) 3129 vlog("# Using HGTMP", _bytes2sys(self._hgtmp))
3127 vlog("# Using PATH", os.environ["PATH"]) 3130 vlog("# Using PATH", os.environ["PATH"])
3128 vlog( 3131 vlog(
3129 "# Using", _strpath(IMPL_PATH), _strpath(osenvironb[IMPL_PATH]), 3132 "# Using", _bytes2sys(IMPL_PATH), _bytes2sys(osenvironb[IMPL_PATH]),
3130 ) 3133 )
3131 vlog("# Writing to directory", _strpath(self._outputdir)) 3134 vlog("# Writing to directory", _bytes2sys(self._outputdir))
3132 3135
3133 try: 3136 try:
3134 return self._runtests(testdescs) or 0 3137 return self._runtests(testdescs) or 0
3135 finally: 3138 finally:
3136 time.sleep(0.1) 3139 time.sleep(0.1)
3144 """ 3147 """
3145 if not args: 3148 if not args:
3146 if self.options.changed: 3149 if self.options.changed:
3147 proc = Popen4( 3150 proc = Popen4(
3148 b'hg st --rev "%s" -man0 .' 3151 b'hg st --rev "%s" -man0 .'
3149 % _bytespath(self.options.changed), 3152 % _sys2bytes(self.options.changed),
3150 None, 3153 None,
3151 0, 3154 0,
3152 ) 3155 )
3153 stdout, stderr = proc.communicate() 3156 stdout, stderr = proc.communicate()
3154 args = stdout.strip(b'\0').split(b'\0') 3157 args = stdout.strip(b'\0').split(b'\0')
3364 def _cleanup(self): 3367 def _cleanup(self):
3365 """Clean up state from this test invocation.""" 3368 """Clean up state from this test invocation."""
3366 if self.options.keep_tmpdir: 3369 if self.options.keep_tmpdir:
3367 return 3370 return
3368 3371
3369 vlog("# Cleaning up HGTMP", _strpath(self._hgtmp)) 3372 vlog("# Cleaning up HGTMP", _bytes2sys(self._hgtmp))
3370 shutil.rmtree(self._hgtmp, True) 3373 shutil.rmtree(self._hgtmp, True)
3371 for f in self._createdfiles: 3374 for f in self._createdfiles:
3372 try: 3375 try:
3373 os.remove(f) 3376 os.remove(f)
3374 except OSError: 3377 except OSError:
3432 3435
3433 # Run installer in hg root 3436 # Run installer in hg root
3434 script = os.path.realpath(sys.argv[0]) 3437 script = os.path.realpath(sys.argv[0])
3435 exe = sysexecutable 3438 exe = sysexecutable
3436 if PYTHON3: 3439 if PYTHON3:
3437 compiler = _bytespath(compiler) 3440 compiler = _sys2bytes(compiler)
3438 script = _bytespath(script) 3441 script = _sys2bytes(script)
3439 exe = _bytespath(exe) 3442 exe = _sys2bytes(exe)
3440 hgroot = os.path.dirname(os.path.dirname(script)) 3443 hgroot = os.path.dirname(os.path.dirname(script))
3441 self._hgroot = hgroot 3444 self._hgroot = hgroot
3442 os.chdir(hgroot) 3445 os.chdir(hgroot)
3443 nohome = b'--home=""' 3446 nohome = b'--home=""'
3444 if os.name == 'nt': 3447 if os.name == 'nt':
3476 3479
3477 makedirs(self._pythondir) 3480 makedirs(self._pythondir)
3478 makedirs(self._bindir) 3481 makedirs(self._bindir)
3479 3482
3480 vlog("# Running", cmd.decode("utf-8")) 3483 vlog("# Running", cmd.decode("utf-8"))
3481 if subprocess.call(_strpath(cmd), shell=True) == 0: 3484 if subprocess.call(_bytes2sys(cmd), shell=True) == 0:
3482 if not self.options.verbose: 3485 if not self.options.verbose:
3483 try: 3486 try:
3484 os.remove(installerrs) 3487 os.remove(installerrs)
3485 except OSError as e: 3488 except OSError as e:
3486 if e.errno != errno.ENOENT: 3489 if e.errno != errno.ENOENT:
3556 return self._hgpath 3559 return self._hgpath
3557 3560
3558 cmd = b'"%s" -c "import mercurial; print (mercurial.__path__[0])"' 3561 cmd = b'"%s" -c "import mercurial; print (mercurial.__path__[0])"'
3559 cmd = cmd % PYTHON 3562 cmd = cmd % PYTHON
3560 if PYTHON3: 3563 if PYTHON3:
3561 cmd = _strpath(cmd) 3564 cmd = _bytes2sys(cmd)
3562 3565
3563 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 3566 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
3564 out, err = p.communicate() 3567 out, err = p.communicate()
3565 3568
3566 self._hgpath = out.strip() 3569 self._hgpath = out.strip()
3602 3605
3603 vlog('# Producing coverage report') 3606 vlog('# Producing coverage report')
3604 # chdir is the easiest way to get short, relative paths in the 3607 # chdir is the easiest way to get short, relative paths in the
3605 # output. 3608 # output.
3606 os.chdir(self._hgroot) 3609 os.chdir(self._hgroot)
3607 covdir = os.path.join(_strpath(self._installdir), '..', 'coverage') 3610 covdir = os.path.join(_bytes2sys(self._installdir), '..', 'coverage')
3608 cov = coverage(data_file=os.path.join(covdir, 'cov')) 3611 cov = coverage(data_file=os.path.join(covdir, 'cov'))
3609 3612
3610 # Map install directory paths back to source directory. 3613 # Map install directory paths back to source directory.
3611 cov.config.paths['srcdir'] = ['.', _strpath(self._pythondir)] 3614 cov.config.paths['srcdir'] = ['.', _bytes2sys(self._pythondir)]
3612 3615
3613 cov.combine() 3616 cov.combine()
3614 3617
3615 omit = [ 3618 omit = [
3616 _strpath(os.path.join(x, b'*')) 3619 _bytes2sys(os.path.join(x, b'*'))
3617 for x in [self._bindir, self._testdir] 3620 for x in [self._bindir, self._testdir]
3618 ] 3621 ]
3619 cov.report(ignore_errors=True, omit=omit) 3622 cov.report(ignore_errors=True, omit=omit)
3620 3623
3621 if self.options.htmlcov: 3624 if self.options.htmlcov:
3622 htmldir = os.path.join(_strpath(self._outputdir), 'htmlcov') 3625 htmldir = os.path.join(_bytes2sys(self._outputdir), 'htmlcov')
3623 cov.html_report(directory=htmldir, omit=omit) 3626 cov.html_report(directory=htmldir, omit=omit)
3624 if self.options.annotate: 3627 if self.options.annotate:
3625 adir = os.path.join(_strpath(self._outputdir), 'annotated') 3628 adir = os.path.join(_bytes2sys(self._outputdir), 'annotated')
3626 if not os.path.isdir(adir): 3629 if not os.path.isdir(adir):
3627 os.mkdir(adir) 3630 os.mkdir(adir)
3628 cov.annotate(directory=adir, omit=omit) 3631 cov.annotate(directory=adir, omit=omit)
3629 3632
3630 def _findprogram(self, program): 3633 def _findprogram(self, program):
3631 """Search PATH for a executable program""" 3634 """Search PATH for a executable program"""
3632 dpb = _bytespath(os.defpath) 3635 dpb = _sys2bytes(os.defpath)
3633 sepb = _bytespath(os.pathsep) 3636 sepb = _sys2bytes(os.pathsep)
3634 for p in osenvironb.get(b'PATH', dpb).split(sepb): 3637 for p in osenvironb.get(b'PATH', dpb).split(sepb):
3635 name = os.path.join(p, program) 3638 name = os.path.join(p, program)
3636 if os.name == 'nt' or os.access(name, os.X_OK): 3639 if os.name == 'nt' or os.access(name, os.X_OK):
3637 return name 3640 return name
3638 return None 3641 return None
3643 if os.name == 'nt' and not p.endswith(b'.exe'): 3646 if os.name == 'nt' and not p.endswith(b'.exe'):
3644 p += b'.exe' 3647 p += b'.exe'
3645 found = self._findprogram(p) 3648 found = self._findprogram(p)
3646 p = p.decode("utf-8") 3649 p = p.decode("utf-8")
3647 if found: 3650 if found:
3648 vlog("# Found prerequisite", p, "at", _strpath(found)) 3651 vlog("# Found prerequisite", p, "at", _bytes2sys(found))
3649 else: 3652 else:
3650 print("WARNING: Did not find prerequisite tool: %s " % p) 3653 print("WARNING: Did not find prerequisite tool: %s " % p)
3651 3654
3652 3655
3653 def aggregateexceptions(path): 3656 def aggregateexceptions(path):