* @brief Compares two semantic version strings. * * Supports versions with optional 'v' prefix and pre-release suffixes * (e.g. "1.2.3-alpha1", "v2.0.0-rc2"). A stable release is always * considered newer than a pre-release of the same version. * * @param remote The remote (available) version string. * @param local The local (installed) version string. * @return @c true if @a remote is ne
| 65 | * @return @c true if @a remote is newer than @a local. |
| 66 | */ |
| 67 | bool QSimpleUpdater::compareVersions(const QString& remote, const QString& local) |
| 68 | { |
| 69 | // Suffix letters and digits are captured separately so that e.g. alpha10 is |
| 70 | // compared numerically against alpha2 (a \w+ suffix would swallow the digits |
| 71 | // and force a lexicographic comparison) |
| 72 | // clang-format off |
| 73 | static QRegularExpression re( |
| 74 | "v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-([A-Za-z]+)(\\d+)?)?" |
| 75 | ); |
| 76 | // clang-format on |
| 77 | |
| 78 | QRegularExpressionMatch remoteMatch = re.match(remote); |
| 79 | QRegularExpressionMatch localMatch = re.match(local); |
| 80 | |
| 81 | if (!remoteMatch.hasMatch() || !localMatch.hasMatch()) |
| 82 | return false; |
| 83 | |
| 84 | // Compare major, minor, and patch components |
| 85 | for (int i = 1; i <= 3; ++i) { |
| 86 | int remoteNum = remoteMatch.captured(i).toInt(); |
| 87 | int localNum = localMatch.captured(i).toInt(); |
| 88 | |
| 89 | if (remoteNum > localNum) |
| 90 | return true; |
| 91 | else if (localNum > remoteNum) |
| 92 | return false; |
| 93 | } |
| 94 | |
| 95 | // Compare pre-release suffixes |
| 96 | QString remoteSuffix = remoteMatch.captured(4); |
| 97 | QString localSuffix = localMatch.captured(4); |
| 98 | |
| 99 | // Remote is stable, local is pre-release |
| 100 | if (remoteSuffix.isEmpty() && !localSuffix.isEmpty()) |
| 101 | return true; |
| 102 | |
| 103 | // Remote is pre-release, local is stable |
| 104 | if (!remoteSuffix.isEmpty() && localSuffix.isEmpty()) |
| 105 | return false; |
| 106 | |
| 107 | // Compare suffixes lexicographically (alpha < beta < rc) |
| 108 | if (remoteSuffix != localSuffix) |
| 109 | return remoteSuffix > localSuffix; |
| 110 | |
| 111 | // Same suffix type — compare numeric part |
| 112 | int remoteSuffixNum = remoteMatch.captured(5).toInt(); |
| 113 | int localSuffixNum = localMatch.captured(5).toInt(); |
| 114 | return remoteSuffixNum > localSuffixNum; |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * @brief Returns @c true if the Updater registered with the given @a url uses |