comparison setup.py @ 33114:8b20338b989e

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.
author Adam Simpkins <simpkins@fb.com>
date Tue, 27 Jun 2017 16:15:32 -0700
parents fc290a39590d
children 6ef5f0c95d64
comparison
equal deleted inserted replaced
33113:fc290a39590d 33114:8b20338b989e
147 stderr=subprocess.PIPE, env=env) 147 stderr=subprocess.PIPE, env=env)
148 out, err = p.communicate() 148 out, err = p.communicate()
149 return p.returncode, out, err 149 return p.returncode, out, err
150 150
151 class hgcommand(object): 151 class hgcommand(object):
152 def __init__(self): 152 def __init__(self, cmd, env):
153 self.cmd = [sys.executable, 'hg'] 153 self.cmd = cmd
154 self.env = gethgenv() 154 self.env = env
155 155
156 def run(self, args): 156 def run(self, args):
157 cmd = self.cmd + args 157 cmd = self.cmd + args
158 returncode, out, err = runcmd(cmd, self.env) 158 returncode, out, err = runcmd(cmd, self.env)
159 # If root is executing setup.py, but the repository is owned by 159 # If root is executing setup.py, but the repository is owned by
169 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) 169 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
170 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr) 170 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
171 return '' 171 return ''
172 return out 172 return out
173 173
174 def gethgenv(): 174 def findhg():
175 """Try to figure out how we should invoke hg for examining the local
176 repository contents.
177
178 Returns an hgcommand object."""
179 # By default, prefer the "hg" command in the user's path. This was
180 # presumably the hg command that the user used to create this repository.
181 #
182 # This repository may require extensions or other settings that would not
183 # be enabled by running the hg script directly from this local repository.
184 hgenv = os.environ.copy()
185 # Use HGPLAIN to disable hgrc settings that would change output formatting,
186 # and disable localization for the same reasons.
187 hgenv['HGPLAIN'] = '1'
188 hgenv['LANGUAGE'] = 'C'
189 hgcmd = ['hg']
190 # Run a simple "hg log" command just to see if using hg from the user's
191 # path works and can successfully interact with this repository.
192 check_cmd = ['log', '-r.', '-Ttest']
193 try:
194 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
195 except EnvironmentError:
196 retcode = -1
197 if retcode == 0:
198 return hgcommand(hgcmd, hgenv)
199
200 # Fall back to trying the local hg installation.
201 hgenv = localhgenv()
202 # Don't source any system hgrc files when using the local hg.
203 hgenv['HGRCPATH'] = ''
204 hgcmd = [sys.executable, 'hg']
205 try:
206 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
207 except EnvironmentError:
208 retcode = -1
209 if retcode == 0:
210 return hgcommand(hgcmd, hgenv)
211
212 raise SystemExit('Unable to find a working hg binary to extract the '
213 'version from the repository tags')
214
215 def localhgenv():
216 """Get an environment dictionary to use for invoking or importing
217 mercurial from the local repository."""
175 # Execute hg out of this directory with a custom environment which takes 218 # Execute hg out of this directory with a custom environment which takes
176 # care to not use any hgrc files and do no localization. 219 # care to not use any hgrc files and do no localization.
177 env = {'HGMODULEPOLICY': 'py', 220 env = {'HGMODULEPOLICY': 'py',
178 'HGRCPATH': '', 221 'HGRCPATH': '',
179 'LANGUAGE': 'C', 222 'LANGUAGE': 'C',
186 env['SystemRoot'] = os.environ['SystemRoot'] 229 env['SystemRoot'] = os.environ['SystemRoot']
187 230
188 version = '' 231 version = ''
189 232
190 if os.path.isdir('.hg'): 233 if os.path.isdir('.hg'):
191 hg = hgcommand() 234 hg = findhg()
192 cmd = ['log', '-r', '.', '--template', '{tags}\n'] 235 cmd = ['log', '-r', '.', '--template', '{tags}\n']
193 numerictags = [t for t in hg.run(cmd).split() if t[0:1].isdigit()] 236 numerictags = [t for t in hg.run(cmd).split() if t[0:1].isdigit()]
194 hgid = hg.run(['id', '-i']).strip() 237 hgid = hg.run(['id', '-i']).strip()
195 if not hgid: 238 if not hgid:
196 # Bail out if hg is having problems interacting with this repository, 239 # Bail out if hg is having problems interacting with this repository,
408 f.write('# empty\n') 451 f.write('# empty\n')
409 452
410 # here no extension enabled, disabled() lists up everything 453 # here no extension enabled, disabled() lists up everything
411 code = ('import pprint; from mercurial import extensions; ' 454 code = ('import pprint; from mercurial import extensions; '
412 'pprint.pprint(extensions.disabled())') 455 'pprint.pprint(extensions.disabled())')
413 returncode, out, err = runcmd([sys.executable, '-c', code], gethgenv()) 456 returncode, out, err = runcmd([sys.executable, '-c', code],
457 localhgenv())
414 if err or returncode != 0: 458 if err or returncode != 0:
415 raise DistutilsExecError(err) 459 raise DistutilsExecError(err)
416 460
417 with open(self._indexfilename, 'w') as f: 461 with open(self._indexfilename, 'w') as f:
418 f.write('# this file is autogenerated by setup.py\n') 462 f.write('# this file is autogenerated by setup.py\n')