Patchwork D6575: pycompat: make fewer assumptions about sys.executable

login
register
mail settings
Submitter phabricator
Date June 26, 2019, 2:38 a.m.
Message ID <differential-rev-PHID-DREV-hfo4wmh6xezq7ahhscrl-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/40677/
State Superseded
Headers show

Comments

phabricator - June 26, 2019, 2:38 a.m.
rdamazio created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  There are many Python "bundlers" which create an archive to run a Python binary
  from, and they may not set sys.executable at all - handle that case properly,
  especially to run tests.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6575

AFFECTED FILES
  mercurial/chgserver.py
  mercurial/debugcommands.py
  tests/run-tests.py

CHANGE DETAILS




To: rdamazio, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -282,7 +282,16 @@ 
 
     return p
 
-PYTHON = _bytespath(sys.executable.replace('\\', '/'))
+if sys.executable:
+    sysexecutable = sys.executable
+elif os.environ.get('PYTHONEXECUTABLE'):
+    sysexecutable = os.environ['PYTHONEXECUTABLE']
+elif os.environ.get('PYTHON'):
+    sysexecutable = os.environ['PYTHON']
+else:
+    raise AssertionError('Could not find Python interpreter')
+
+PYTHON = _bytespath(sysexecutable.replace('\\', '/'))
 IMPL_PATH = b'PYTHONPATH'
 if 'java' in sys.platform:
     IMPL_PATH = b'JYTHONPATH'
@@ -1094,7 +1103,7 @@ 
         env["HGRCPATH"] = _strpath(os.path.join(self._threadtmp, b'.hgrc'))
         env["DAEMON_PIDS"] = _strpath(os.path.join(self._threadtmp,
                                                    b'daemon.pids'))
-        env["HGEDITOR"] = ('"' + sys.executable + '"'
+        env["HGEDITOR"] = ('"' + sysexecutable + '"'
                            + ' -c "import sys; sys.exit(0)"')
         env["HGUSER"]   = "test"
         env["HGENCODING"] = "ascii"
@@ -2349,7 +2358,7 @@ 
             withhg = self._runner.options.with_hg
             if withhg:
                 opts += ' --with-hg=%s ' % shellquote(_strpath(withhg))
-            rtc = '%s %s %s %s' % (sys.executable, sys.argv[0], opts,
+            rtc = '%s %s %s %s' % (sysexecutable, sys.argv[0], opts,
                                    test)
             data = pread(bisectcmd + ['--command', rtc])
             m = re.search(
@@ -3003,25 +3012,25 @@ 
         # Administrator rights.
         if getattr(os, 'symlink', None) and os.name != 'nt':
             vlog("# Making python executable in test path a symlink to '%s'" %
-                 sys.executable)
+                 sysexecutable)
             mypython = os.path.join(self._tmpbindir, pyexename)
             try:
-                if os.readlink(mypython) == sys.executable:
+                if os.readlink(mypython) == sysexecutable:
                     return
                 os.unlink(mypython)
             except OSError as err:
                 if err.errno != errno.ENOENT:
                     raise
-            if self._findprogram(pyexename) != sys.executable:
+            if self._findprogram(pyexename) != sysexecutable:
                 try:
-                    os.symlink(sys.executable, mypython)
+                    os.symlink(sysexecutable, mypython)
                     self._createdfiles.append(mypython)
                 except OSError as err:
                     # child processes may race, which is harmless
                     if err.errno != errno.EEXIST:
                         raise
         else:
-            exedir, exename = os.path.split(sys.executable)
+            exedir, exename = os.path.split(sysexecutable)
             vlog("# Modifying search path to find %s as %s in '%s'" %
                  (exename, pyexename, exedir))
             path = os.environ['PATH'].split(os.pathsep)
@@ -3048,7 +3057,7 @@ 
 
         # Run installer in hg root
         script = os.path.realpath(sys.argv[0])
-        exe = sys.executable
+        exe = sysexecutable
         if PYTHON3:
             compiler = _bytespath(compiler)
             script = _bytespath(script)
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -1240,7 +1240,7 @@ 
 
     # Python
     fm.write('pythonexe', _("checking Python executable (%s)\n"),
-             pycompat.sysexecutable)
+             pycompat.sysexecutable or "unknown")
     fm.write('pythonver', _("checking Python version (%s)\n"),
              ("%d.%d.%d" % sys.version_info[:3]))
     fm.write('pythonlib', _("checking Python lib (%s)...\n"),
diff --git a/mercurial/chgserver.py b/mercurial/chgserver.py
--- a/mercurial/chgserver.py
+++ b/mercurial/chgserver.py
@@ -138,7 +138,9 @@ 
         modules.append(__version__)
     except ImportError:
         pass
-    files = [pycompat.sysexecutable]
+    files = []
+    if pycompat.sysexecutable:
+        files.append(pycompat.sysexecutable)
     for m in modules:
         try:
             files.append(pycompat.fsencode(inspect.getabsfile(m)))