Patchwork [5,of,5] setup: prefer using the system hg to interact with the local repository

login
register
mail settings
Submitter Adam Simpkins
Date June 26, 2017, 6:37 p.m.
Message ID <78a17c5b9516138e4506.1498502264@devbig125.prn1.facebook.com>
Download mbox | patch
Permalink /patch/21741/
State Accepted
Headers show

Comments

Adam Simpkins - June 26, 2017, 6:37 p.m.
# HG changeset patch
# User Adam Simpkins <simpkins@fb.com>
# Date 1498501890 25200
#      Mon Jun 26 11:31:30 2017 -0700
# Node ID 78a17c5b9516138e4506bd1bd634ccbb9d8d52c7
# Parent  116836ddfc564a329200f8540e0a08ae63c40e8d
setup: prefer using the system hg to interact with the local repository

Add a findhg() function that tries to be smarter about figuring out how to run
hg for examining the local repository.  It first tries running "hg" from the
user's PATH, with the default HGRCPATH settings intact, but with HGPLAIN
enabled.  This will generally use the same version of mercurial and the same
settings used to originally clone the repository, and should have a higher
chance of working successfully than trying to run the hg script from the local
repository.  If that fails findhg() falls back to the existing behavior of
running the local hg script.

Patch

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -149,9 +149,9 @@ 
     return p.returncode, out, err
 
 class hgcommand(object):
-    def __init__(self):
-        self.cmd = [sys.executable, 'hg']
-        self.env = gethgenv()
+    def __init__(self, cmd, env):
+        self.cmd = cmd
+        self.env = env
 
     def run(self, args):
         cmd = self.cmd + args
@@ -171,7 +171,50 @@ 
             return ''
         return out
 
-def gethgenv():
+def findhg():
+    """Try to figure out how we should invoke hg for examining the local
+    repository contents.
+
+    Returns an hgcommand object."""
+    # By default, prefer the "hg" command in the user's path.  This was
+    # presumably the hg command that the user used to create this repository.
+    #
+    # This repository may require extensions or other settings that would not
+    # be enabled by running the hg script directly from this local repository.
+    hgenv = os.environ.copy()
+    # Use HGPLAIN to disable hgrc settings that would change output formatting,
+    # and disable localization for the same reasons.
+    hgenv['HGPLAIN'] = '1'
+    hgenv['LANGUAGE'] = 'C'
+    hgcmd = ['hg']
+    # Run a simple "hg log" command just to see if using hg from the user's
+    # path works and can successfully interact with this repository.
+    check_cmd = ['log', '-r.', '-Ttest']
+    try:
+        retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
+    except EnvironmentError:
+        retcode = -1
+    if retcode == 0:
+        return hgcommand(hgcmd, hgenv)
+
+    # Fall back to trying the local hg installation.
+    hgenv = localhgenv()
+    # Don't source any system hgrc files when using the local hg.
+    hgenv['HGRCPATH'] = ''
+    hgcmd = [sys.executable, 'hg']
+    try:
+        retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
+    except EnvironmentError:
+        retcode = -1
+    if retcode == 0:
+        return hgcommand(hgcmd, hgenv)
+
+    raise SystemExit('Unable to find a working hg binary to extract the '
+                     'version from the repository tags')
+
+def localhgenv():
+    """Get an environment dictionary to use for invoking or importing
+    mercurial from the local repository."""
     # Execute hg out of this directory with a custom environment which takes
     # care to not use any hgrc files and do no localization.
     env = {'HGMODULEPOLICY': 'py',
@@ -188,7 +231,7 @@ 
 version = ''
 
 if os.path.isdir('.hg'):
-    hg = hgcommand()
+    hg = findhg()
     cmd = ['log', '-r', '.', '--template', '{tags}\n']
     numerictags = [t for t in hg.run(cmd).split() if t[0].isdigit()]
     hgid = hg.run(['id', '-i']).strip()
@@ -410,7 +453,8 @@ 
         # here no extension enabled, disabled() lists up everything
         code = ('import pprint; from mercurial import extensions; '
                 'pprint.pprint(extensions.disabled())')
-        returncode, out, err = runcmd([sys.executable, '-c', code], gethgenv())
+        returncode, out, err = runcmd([sys.executable, '-c', code],
+                                      localhgenv())
         if err or returncode != 0:
             raise DistutilsExecError(err)