setup: further improve the error path for version retrieval
This is a new take at the problem that 8d390a13474d tried to tackle. There was
two issues after that previous improvement:
- the 0.0+ version could survive a bit too long and reaching the installer
version and staying there.
- multiple use case where still failing.
So the new code is better at:
- always succeeding when running `make local` so that we can
bootstrap a local version
- no using that fallback outside of `make local` to avoid distribution of
version with the buggy version number.
The setup.py is a gigantic pile of spaghetti code, to the point where
pastafarian pilgrim started knocking at its core.
However I refrained from cleaning that up since the more to a `setup.cfg` means
this code should be deleted soon?.
--- a/Makefile Fri Feb 17 14:00:39 2023 +0100
+++ b/Makefile Fri Feb 17 16:45:36 2023 +0100
@@ -58,7 +58,7 @@
all: build doc
local:
- $(PYTHON) setup.py $(PURE) \
+ MERCURIAL_SETUP_MAKE_LOCAL=1 $(PYTHON) setup.py $(PURE) \
build_py -c -d . \
build_ext $(COMPILERFLAG) -i \
build_hgexe $(COMPILERFLAG) -i \
--- a/setup.py Fri Feb 17 14:00:39 2023 +0100
+++ b/setup.py Fri Feb 17 16:45:36 2023 +0100
@@ -21,6 +21,11 @@
return s.decode('latin-1')
+def eprint(*args, **kwargs):
+ kwargs['file'] = sys.stderr
+ print(*args, **kwargs)
+
+
import ssl
# ssl.HAS_TLSv1* are preferred to check support but they were added in Python
@@ -292,10 +297,11 @@
if retcode == 0 and not filterhgerr(err):
return hgcommand(hgcmd, hgenv)
- raise SystemExit(
- 'Unable to find a working hg binary to extract the '
- 'version from the repository tags'
- )
+ eprint("/!\\")
+ eprint(r"/!\ Unable to find a working hg binary")
+ eprint(r"/!\ Version cannot be extract from the repository")
+ eprint(r"/!\ Re-run the setup once a first version is built")
+ return None
def localhgenv():
@@ -320,33 +326,46 @@
version = ''
-if os.path.isdir('.hg'):
+
+def _try_get_version():
hg = findhg()
+ if hg is None:
+ return ''
+ hgid = None
+ numerictags = []
cmd = ['log', '-r', '.', '--template', '{tags}\n']
- numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
+ pieces = sysstr(hg.run(cmd)).split()
+ numerictags = [t for t in pieces if t[0:1].isdigit()]
hgid = sysstr(hg.run(['id', '-i'])).strip()
if not hgid:
- # Bail out if hg is having problems interacting with this repository,
- # rather than falling through and producing a bogus version number.
- # Continuing with an invalid version number will break extensions
- # that define minimumhgversion.
- raise SystemExit('Unable to determine hg version from local repository')
+ eprint("/!\\")
+ eprint(r"/!\ Unable to determine hg version from local repository")
+ eprint(r"/!\ Failed to retrieve current revision tags")
+ return ''
if numerictags: # tag(s) found
version = numerictags[-1]
if hgid.endswith('+'): # propagate the dirty status to the tag
version += '+'
- else: # no tag found
+ else: # no tag found on the checked out revision
ltagcmd = ['parents', '--template', '{latesttag}']
ltag = sysstr(hg.run(ltagcmd))
if not ltag:
- ltag = 'null'
+ eprint("/!\\")
+ eprint(r"/!\ Unable to determine hg version from local repository")
+ eprint(
+ r"/!\ Failed to retrieve current revision distance to lated tag"
+ )
+ return ''
changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
changessince = len(hg.run(changessincecmd).splitlines())
- if ltag == 'null':
- ltag = '0.0'
version = '%s+hg%s.%s' % (ltag, changessince, hgid)
if version.endswith('+'):
version = version[:-1] + 'local' + time.strftime('%Y%m%d')
+ return version
+
+
+if os.path.isdir('.hg'):
+ version = _try_get_version()
elif os.path.exists('.hg_archival.txt'):
kw = dict(
[[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
@@ -366,21 +385,35 @@
with open('mercurial/__version__.py') as f:
data = f.read()
version = re.search('version = b"(.*)"', data).group(1)
-
-if version:
- versionb = version
- if not isinstance(versionb, bytes):
- versionb = versionb.encode('ascii')
+if not version:
+ if os.environ.get("MERCURIAL_SETUP_MAKE_LOCAL") == "1":
+ version = "0.0+0"
+ eprint("/!\\")
+ eprint(r"/!\ Using '0.0+0' as the default version")
+ eprint(r"/!\ Re-run make local once that first version is built")
+ eprint("/!\\")
+ else:
+ eprint("/!\\")
+ eprint(r"/!\ Could not determine the Mercurial version")
+ eprint(r"/!\ You need to build a local version first")
+ eprint(r"/!\ Run `make local` and try again")
+ eprint("/!\\")
+ msg = "Run `make local` first to get a working local version"
+ raise SystemExit(msg)
- write_if_changed(
- 'mercurial/__version__.py',
- b''.join(
- [
- b'# this file is autogenerated by setup.py\n'
- b'version = b"%s"\n' % versionb,
- ]
- ),
- )
+versionb = version
+if not isinstance(versionb, bytes):
+ versionb = versionb.encode('ascii')
+
+write_if_changed(
+ 'mercurial/__version__.py',
+ b''.join(
+ [
+ b'# this file is autogenerated by setup.py\n'
+ b'version = b"%s"\n' % versionb,
+ ]
+ ),
+)
class hgbuild(build):