subrepo: better error messages in _ensuregit
This patch improves the error messages raised when an OSError occurs, since
simply re-raising the exception can be both confusing and misleading. For
example, if "hg identify" is run inside a repository that contains a Git
subrepository and the git binary could not be found, it'll exit with the message
"abort: No such file or directory". That implies "identify" has a problem
reading the repository itself. There's no way for the user to know what the
real problem is unless they dive into the Mercurial source, which is what I
ended up doing after spending hours debugging errors while provisioning a VM
with Ansible (turns out I forgot to install Git on it).
Descriptive errors are especially important on Windows, since it's common for
Windows users to forget to set the "Path" system variable after installing Git.
--- a/mercurial/subrepo.py Sat Jan 23 17:31:31 2016 +0800
+++ b/mercurial/subrepo.py Sun Jan 17 22:53:57 2016 -0500
@@ -1294,10 +1294,25 @@
self._gitexecutable = 'git'
out, err = self._gitnodir(['--version'])
except OSError as e:
- if e.errno != 2 or os.name != 'nt':
- raise
- self._gitexecutable = 'git.cmd'
- out, err = self._gitnodir(['--version'])
+ genericerror = _("error executing git for subrepo '%s': %s")
+ notfoundhint = _("check git is installed and in your PATH")
+ if e.errno != errno.ENOENT:
+ raise error.Abort(genericerror % (self._path, e.strerror))
+ elif os.name == 'nt':
+ try:
+ self._gitexecutable = 'git.cmd'
+ out, err = self._gitnodir(['--version'])
+ except OSError as e2:
+ if e2.errno == errno.ENOENT:
+ raise error.Abort(_("couldn't find 'git' or 'git.cmd'"
+ " for subrepo '%s'") % self._path,
+ hint=notfoundhint)
+ else:
+ raise error.Abort(genericerror % (self._path,
+ e2.strerror))
+ else:
+ raise error.Abort(_("couldn't find git for subrepo '%s'")
+ % self._path, hint=notfoundhint)
versionstatus = self._checkversion(out)
if versionstatus == 'unknown':
self.ui.warn(_('cannot retrieve git version\n'))