...

Text file src/github.com/bazelbuild/bazel-gazelle/internal/bzlmod/semver.bzl

Documentation: github.com/bazelbuild/bazel-gazelle/internal/bzlmod

     1# Copyright 2023 The Bazel Authors. All rights reserved.
     2#
     3# Licensed under the Apache License, Version 2.0 (the "License");
     4# you may not use this file except in compliance with the License.
     5# You may obtain a copy of the License at
     6#
     7#    http://www.apache.org/licenses/LICENSE-2.0
     8#
     9# Unless required by applicable law or agreed to in writing, software
    10# distributed under the License is distributed on an "AS IS" BASIS,
    11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12# See the License for the specific language governing permissions and
    13# limitations under the License.
    14
    15visibility([
    16    "//tests/bzlmod/...",
    17])
    18
    19# Compares lower than any non-numeric identifier.
    20_COMPARES_LOWEST_SENTINEL = ""
    21
    22# Compares higher than any valid non-numeric identifier (containing only [A-Za-z0-9-]).
    23_COMPARES_HIGHEST_SENTINEL = "{"
    24
    25def _identifier_to_comparable(ident, *, numeric_only):
    26    if not ident:
    27        fail("Identifiers in semantic version strings must not be empty")
    28    if ident.isdigit():
    29        if ident[0] == "0" and ident != "0":
    30            fail("Numeric identifiers in semantic version strings must not include leading zeroes")
    31
    32        # 11.4.1:
    33        # "Identifiers consisting of only digits are compared numerically."
    34        # 11.4.3:
    35        # "Numeric identifiers always have lower precedence than non-numeric identifiers."
    36        return (_COMPARES_LOWEST_SENTINEL, int(ident))
    37    elif numeric_only:
    38        fail("Expected a numeric identifier, got: " + ident)
    39    else:
    40        # 11.4.2:
    41        # "Identifiers with letters or hyphens are compared lexically in ASCII sort order."
    42        return (ident,)
    43
    44def _semver_to_comparable(v, *, relaxed = False):
    45    """
    46    Parses a string representation of a semver version into an opaque comparable object.
    47
    48    Args:
    49        v: The string representation of the version.
    50        relaxed: If true, the release version string is allowed to have an arbitrary number of
    51            dot-separated components, each of which is allowed to contain the same set of characters
    52            as a pre-release segment. This is the version string format used by Bazel modules.
    53    """
    54
    55    # Strip build metadata as it is not relevant for comparisons.
    56    v, _, _ = v.partition("+")
    57
    58    release_str, _, prerelease_str = v.partition("-")
    59    if prerelease_str:
    60        # 11.4.4:
    61        # "A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding
    62        #  identifiers are equal."
    63        prerelease = [_identifier_to_comparable(ident, numeric_only = False) for ident in prerelease_str.split(".")]
    64    else:
    65        # 11.3:
    66        # "When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version."
    67        prerelease = [(_COMPARES_HIGHEST_SENTINEL,)]
    68
    69    release = release_str.split(".")
    70    if not relaxed and len(release) != 3:
    71        fail("Semantic version strings must have exactly three dot-separated components, got: " + v)
    72
    73    return (
    74        tuple([_identifier_to_comparable(s, numeric_only = not relaxed) for s in release]),
    75        tuple(prerelease),
    76    )
    77
    78semver = struct(
    79    to_comparable = _semver_to_comparable,
    80)

View as plain text