Skip to content

Commit f8828ec

Browse files
setup.py: fail fast if the version can not be determined, fixes #7259
setuptools_scm computes the borg version from git tags. In a shallow clone or a clone without tags it does not fail the build, it just yields a wrong version like 0.1.dev1+gedcff4f - and that is only noticed after cythonizing and compiling everything, which wastes >5min of CI time for nothing. So ask setuptools_scm for the version before building anything, rather than reimplementing its tag lookup here: - shallow repository: use setuptools_scm's own fail_on_shallow pre_parse hook, which also catches a shallow clone that does happen to have a tag (the distance would be wrong there). Passed as a get_version() argument, not put into pyproject.toml, because the "scm" table only exists in recent setuptools-scm and older ones hard-fail on unknown keys there, see #10193. - no tags at all: a full clone with the tags deleted is not shallow, so fail_on_shallow does not catch it. setuptools_scm falls back to a 0.x tag there and borg has no 0.x releases, so that is what we look at. - no version source at all: setuptools_scm raises its own helpful error, just much earlier than before. Builds that get their version from SETUPTOOLS_SCM_PRETEND_VERSION or from a sdist's PKG-INFO are not affected, and neither are ReadTheDocs builds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 9a6d4cf commit f8828ec

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

setup.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import re
55
import sys
6+
import warnings
67
from collections import defaultdict
78

89
try:
@@ -45,6 +46,80 @@
4546
# Are we building on ReadTheDocs?
4647
on_rtd = os.environ.get("READTHEDOCS")
4748

49+
50+
def check_version_detectable():
51+
"""Fail before building anything if the borg version can not be determined.
52+
53+
The version is computed from git tags by setuptools_scm. In a shallow clone or a clone
54+
without tags this does not fail, it just yields a wrong version like 0.1.dev1+gedcff4f -
55+
and that is only noticed after cythonizing and compiling everything, see #7259.
56+
57+
We ask setuptools_scm itself instead of reimplementing its tag lookup here.
58+
"""
59+
if on_rtd:
60+
return # building the docs does not need an exact version.
61+
try:
62+
from setuptools_scm import get_version
63+
except ImportError:
64+
return # can not check. if the version is really needed, setup() will complain later.
65+
66+
here = os.path.dirname(os.path.abspath(__file__))
67+
found_tags = []
68+
69+
def capture_tag(scm_version):
70+
# a custom version_scheme is only used to get at the tag setuptools_scm found,
71+
# the version we return here is not used for anything.
72+
found_tags.append(str(scm_version.tag))
73+
return "0"
74+
75+
def fail(reason):
76+
raise SystemExit(
77+
"Can not determine the borg version: %s\n"
78+
"\n"
79+
"The version is computed from git tags, so building here would silently produce a\n"
80+
"wrong version (like 0.1.dev1+gedcff4f). Use one of these:\n"
81+
"\n"
82+
"- clone the full repository (a shallow clone or a clone without tags will not work):\n"
83+
" git clone https://github.com/borgbackup/borg.git\n"
84+
"- fetch what your existing clone is missing:\n"
85+
" git fetch --unshallow --tags\n"
86+
"- or give the version explicitly, e.g. when building without git:\n"
87+
" SETUPTOOLS_SCM_PRETEND_VERSION=2.0.0b23 pip install -e ." % reason
88+
)
89+
90+
def ask_setuptools_scm(**extra):
91+
del found_tags[:]
92+
with warnings.catch_warnings():
93+
# the real build triggers the same warnings, we do not want to duplicate them.
94+
warnings.simplefilter("ignore")
95+
# raises LookupError (with its own helpful message) if there is no version source at all.
96+
get_version(root=here, version_scheme=capture_tag, local_scheme=lambda scm_version: "", **extra)
97+
98+
try:
99+
# let setuptools_scm fail on a shallow repository instead of computing a version from
100+
# truncated history, see
101+
# https://setuptools-scm.readthedocs.io/en/latest/integrations/#enforce-fail-on-shallow-repositories
102+
# This is not in pyproject.toml on purpose: the "scm" table only exists in recent
103+
# setuptools-scm and older ones hard-fail on unknown keys there, see #10193.
104+
ask_setuptools_scm(scm={"git": {"pre_parse": "fail_on_shallow"}})
105+
except TypeError: # setuptools-scm too old for the "scm" config, check what we can without it.
106+
ask_setuptools_scm()
107+
except ValueError as err: # that is how fail_on_shallow complains.
108+
fail(str(err).splitlines()[0])
109+
110+
if not found_tags:
111+
# no tag was looked at: the version came from SETUPTOOLS_SCM_PRETEND_VERSION or, when
112+
# building from a sdist, from PKG-INFO. Nothing to check in that case.
113+
return
114+
if found_tags[0].startswith("0."):
115+
# borg has no 0.x releases, so this is the fallback tag setuptools_scm uses when it does
116+
# not find any tag at all. Note: a full clone without tags is not shallow, so
117+
# fail_on_shallow does not catch this one.
118+
fail("setuptools_scm did not find a borg release tag.")
119+
120+
121+
check_version_detectable()
122+
48123
# Extra cflags for all extensions, usually just warnings we want to enable explicitly
49124
cflags = ["-Wall", "-Wextra", "-Wpointer-arith"]
50125

0 commit comments

Comments
 (0)