From 232ccabfa300d4db4015fbb328999a4048ec7c76 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 12 May 2026 22:22:33 +0200 Subject: [PATCH] fix: properly handle invalid and dev versions in version parser, fixes #9014 - `src/borg/__init__.py`: The `setuptools_scm` fallback version `0.1.dev1` was incorrectly bypassing the assertion check (as `0` and `1` are valid integers), which hid the intended helpful error message when building from source without tags. Added an explicit check for the `0.1.dev` prefix. - `src/borg/version.py`: `parse_version` and `format_version` have been updated to correctly understand `setuptools_scm`'s `.dev` or `dev` prefixes. These dev releases are now properly encoded in the version tuple as `-9` (which logically makes them older than alphas `-4`, betas `-3`, rcs `-2`, and final `-1`), and correctly reformatted to `.dev` strings. --- src/borg/__init__.py | 2 +- src/borg/version.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/borg/__init__.py b/src/borg/__init__.py index 459300768e..604b4234f3 100644 --- a/src/borg/__init__.py +++ b/src/borg/__init__.py @@ -10,7 +10,7 @@ # assert that all semver components are integers # this is mainly to show errors when people repackage poorly # and setuptools_scm determines a 0.1.dev... version -assert all(isinstance(v, int) for v in __version_tuple__), \ +assert not __version__.startswith("0.1.dev") and all(isinstance(v, int) for v in __version_tuple__), \ """\ broken borgbackup version metadata: %r diff --git a/src/borg/version.py b/src/borg/version.py index 0f67eb60fc..8a05c228ef 100644 --- a/src/borg/version.py +++ b/src/borg/version.py @@ -17,7 +17,7 @@ def parse_version(version): """ version_re = r""" (?P\d+)\.(?P\d+)\.(?P\d+) # version, e.g. 1.2.33 - (?P(?Pa|b|rc)(?P\d+))? # optional prerelease, e.g. a1 or b2 or rc33 + (?P\.?(?Pa|b|rc|dev)(?P\d+))? # optional prerelease, e.g. a1 or b2 or rc33 or .dev1 """ m = re.match(version_re, version, re.VERBOSE) if m is None: @@ -25,7 +25,7 @@ def parse_version(version): gd = m.groupdict() version = [int(gd['major']), int(gd['minor']), int(gd['patch'])] if m.lastgroup == 'prerelease': - p_type = {'a': -4, 'b': -3, 'rc': -2}[gd['ptype']] + p_type = {'a': -4, 'b': -3, 'rc': -2, 'dev': -9}[gd['ptype']] p_num = int(gd['pnum']) version += [p_type, p_num] else: @@ -44,6 +44,6 @@ def format_version(version): elif part == -1: break else: - f[-1] = f[-1] + {-2: 'rc', -3: 'b', -4: 'a'}[part] + str(next(it)) + f[-1] = f[-1] + {-2: 'rc', -3: 'b', -4: 'a', -9: '.dev'}[part] + str(next(it)) break return '.'.join(f)