diff mbox series

[v3,5/7] Compare versions according to semver

Message ID 20200615082702.32693-6-sde@unmatched.eu
State Accepted
Headers show
Series Add semantic versioning support | expand

Commit Message

Stijn Devriendt June 15, 2020, 8:27 a.m. UTC
Still, fallback to legacy versioning scheme if needed.

Signed-off-by: Stijn Devriendt <sde@unmatched.eu>
---
 core/artifacts_versions.c | 48 ++++++++++++++++++++++++++++++++++++++-
 core/parser.c             | 11 ++++-----
 include/util.h            |  2 +-
 3 files changed, 52 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/core/artifacts_versions.c b/core/artifacts_versions.c
index ccc283e..2ccba85 100644
--- a/core/artifacts_versions.c
+++ b/core/artifacts_versions.c
@@ -210,7 +210,7 @@  void cleanup_version(char* str)
  * Also major.minor or major.minor.revision are allowed
  * The conversion generates a 64 bit value that can be compared
  */
-__u64 version_to_number(const char *version_string)
+static __u64 version_to_number(const char *version_string)
 {
 	char **versions = NULL;
 	char **ver;
@@ -235,3 +235,49 @@  __u64 version_to_number(const char *version_string)
 
 	return version;
 }
+
+/*
+ * Compare 2 versions.
+ *
+ * Mind that this function accepts both version types:
+ * - old-style: major.minor.revision.buildinfo
+ * - semantic versioning: major.minor.patch[-prerelease][+buildinfo]
+ *   see https://semver.org
+ *
+ * Returns -1, 0 or 1 of left is respectively lower than, equal to or greater than right.
+ */
+int compare_versions(const char* left_version, const char* right_version)
+{
+	if (is_oldstyle_version(left_version) && is_oldstyle_version(right_version))
+	{
+		__u64 left_u64 = version_to_number(left_version);
+		__u64 right_u64 = version_to_number(right_version);
+
+		if (left_u64 < right_u64)
+			return -1;
+		else if (left_u64 > right_u64)
+			return 1;
+		else
+			return 0;
+	}
+	else
+	{
+		semver_t left_sem = {};
+		semver_t right_sem = {};
+		int comparison;
+
+		/* There's no error checking here.
+		 * Oldstyle code also defaults to treating unparseable version as 0.
+		 * Failed semver_parse also leads to 0.0.0 if properly initialized.
+		 */
+		semver_parse(left_version, &left_sem);
+		semver_parse(right_version, &right_sem);
+
+		comparison = semver_compare(left_sem, right_sem);
+
+		semver_free(&left_sem);
+		semver_free(&right_sem);
+
+		return comparison;
+	}
+}
diff --git a/core/parser.c b/core/parser.c
index e7e68ea..ba0d2a6 100644
--- a/core/parser.c
+++ b/core/parser.c
@@ -172,15 +172,15 @@  static int is_image_higher(struct swver *sw_ver_list,
 		return false;
 
 	LIST_FOREACH(swver, sw_ver_list, next) {
-		__u64 minimum_version = version_to_number(swver->version);
-		__u64 newversion = version_to_number(img->id.version);
+		const char* current_version = swver->version;
+		const char* proposed_version = img->id.version;
 
 		/*
 		 * Check if name are identical and the new version is lower
 		 * or equal.
 		 */
 		if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
-		    (minimum_version >= newversion)) {
+		    (compare_versions(proposed_version, current_version) < 0)) {
 			TRACE("%s(%s) has a higher version installed, skipping...",
 			      img->id.name,
 			      img->id.version);
@@ -306,10 +306,7 @@  int parse(struct swupdate_cfg *sw, const char *descfile)
 	 * newer version
 	 */
 	if (sw->globals.no_downgrading) {
-		__u64 minimum_version = version_to_number(sw->globals.minimum_version);
-		__u64 newversion = version_to_number(sw->version);
-
-		if (newversion < minimum_version) {
+		if (compare_versions(sw->version, sw->globals.minimum_version) < 0) {
 			ERROR("No downgrading allowed: new version %s <= installed %s",
 				sw->version, sw->globals.minimum_version);
 			return -EPERM;
diff --git a/include/util.h b/include/util.h
index 6a027c6..adf585e 100644
--- a/include/util.h
+++ b/include/util.h
@@ -217,7 +217,7 @@  void freeargs (char **argv);
 int get_hw_revision(struct hw_type *hw);
 void get_sw_versions(char *cfgfname, struct swupdate_cfg *sw);
 void cleanup_version(char* str);
-__u64 version_to_number(const char *version_string);
+int compare_versions(const char* left_version, const char* right_version);
 int hwid_match(const char* rev, const char* hwrev);
 int check_hw_compatibility(struct swupdate_cfg *cfg);
 int count_elem_list(struct imglist *list);