From 89c40ed3ed3b6268099099f8c266ca09a16d00f2 Mon Sep 17 00:00:00 2001 From: Ole Herman Schumacher Elgesem Date: Wed, 11 Oct 2023 20:33:50 +0200 Subject: [PATCH 1/3] Added documentation for version_compare() Ticket: CFE-3991 Signed-off-by: Ole Herman Schumacher Elgesem --- reference/functions/cf_version_after.markdown | 2 +- reference/functions/cf_version_at.markdown | 2 +- .../functions/cf_version_before.markdown | 2 +- .../functions/cf_version_between.markdown | 2 +- .../functions/cf_version_maximum.markdown | 2 +- .../functions/cf_version_minimum.markdown | 2 +- reference/functions/version_compare.markdown | 83 +++++++++++++++++++ 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 reference/functions/version_compare.markdown diff --git a/reference/functions/cf_version_after.markdown b/reference/functions/cf_version_after.markdown index 4ccc76811..562efa15c 100644 --- a/reference/functions/cf_version_after.markdown +++ b/reference/functions/cf_version_after.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_after.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. +**See also:** `version_compare()`, `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. **History:** diff --git a/reference/functions/cf_version_at.markdown b/reference/functions/cf_version_at.markdown index e19cd190f..07a8bf9bf 100644 --- a/reference/functions/cf_version_at.markdown +++ b/reference/functions/cf_version_at.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_at.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_between()`. +**See also:** `version_compare()`, `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_between()`. **History:** diff --git a/reference/functions/cf_version_before.markdown b/reference/functions/cf_version_before.markdown index f480f7779..4886746d0 100644 --- a/reference/functions/cf_version_before.markdown +++ b/reference/functions/cf_version_before.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_before.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_at()`, `cf_version_between()`. +**See also:** `version_compare()`, `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_at()`, `cf_version_between()`. **History:** diff --git a/reference/functions/cf_version_between.markdown b/reference/functions/cf_version_between.markdown index e1852017d..8b9b88b35 100644 --- a/reference/functions/cf_version_between.markdown +++ b/reference/functions/cf_version_between.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_between.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`. +**See also:** `version_compare()`, `cf_version_maximum()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`. **History:** diff --git a/reference/functions/cf_version_maximum.markdown b/reference/functions/cf_version_maximum.markdown index 582ebdc27..62f3b0677 100644 --- a/reference/functions/cf_version_maximum.markdown +++ b/reference/functions/cf_version_maximum.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_maximum.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. +**See also:** `version_compare()`, `cf_version_minimum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. **History:** diff --git a/reference/functions/cf_version_minimum.markdown b/reference/functions/cf_version_minimum.markdown index 1eb7c31be..8d7d27ac9 100644 --- a/reference/functions/cf_version_minimum.markdown +++ b/reference/functions/cf_version_minimum.markdown @@ -18,7 +18,7 @@ Output: [%CFEngine_include_snippet(cf_version_minimum.cf, #\+begin_src\s+example_output\s*, .*end_src)%] -**See also:** `cf_version_maximum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. +**See also:** `version_compare()`, `cf_version_maximum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. **History:** diff --git a/reference/functions/version_compare.markdown b/reference/functions/version_compare.markdown new file mode 100644 index 000000000..eb5130140 --- /dev/null +++ b/reference/functions/version_compare.markdown @@ -0,0 +1,83 @@ +--- +layout: default +title: version_compare +published: true +--- + +[%CFEngine_function_prototype(string)%] + +**Description:** Returns `true` if the specified version comparison expression is true. + +[%CFEngine_function_attributes(string)%] + +The `version_compare()` function can be used to compare 2 arbitrary semver version numbers. +This can be useful if you have 2 versions of a package and you want to know if they are the same version, if one is newer than the other etc. + +**Example:** + +[%CFEngine_include_snippet(version_compare.cf, #\+begin_src cfengine3, .*end_src)%] + +Output: + +[%CFEngine_include_snippet(version_compare.cf, #\+begin_src\s+example_output\s*, .*end_src)%] + +**Notes:** + +Internally, `version_compare` uses the same version comparison logic as other version functions (`cf_version_minimum`, etc.). +This means that only the **`major.minor.patch`** parts of the version string are compared, everything after patch is ignored so `1.2.3`, `1.2.3-1`, `1.2.3-2`, `1.2.3+git1234`, `1.2.3a` are all considered the same version. + +In policy you can combine `version_compare()` and `strcmp()` to get more info if desirable: + +```cfengine3 +bundle agent main +{ + reports: + "Same patch version, but not exactly the same version string" + if => and( + version_compare("$(a)", "=", "$(b)"), + not(strcmp("$(a)", "$(b)")) + ); +} +``` + +CFEngine's version comparison functions also support partial version numbers, so if you supply only a major version, or a major and minor version, but no patch version, only the provided parts are compared: + +```cfengine3 +bundle agent main +{ + vars: + "patch_a" + string => "3.21.1"; + "patch_b" + string => "4.0.1"; + + reports: + "patch_a is a part of the 3.21 series: 3.21 == $(patch_a)" + if => version_compare("3.21", "==", "$(patch_a)"); + "patch_b is in major version 4: 4 == $(patch_b)" + if => version_compare("4", "==", "$(patch_b)"); +} +``` + +Beware that using partial version numbers can lead to situations with surprising results, the `>`, `<`, `=`, `!=` operators may not behave exactly as the policy writer expects: + +```cfengine3 +bundle agent main +{ + reports: + "3.22.1 > 3.22" # No, won't be printed + if => version_compare("3.22.1", ">", "3.22"); + "3.22.1 >= 3.22" # Yes, will be printed + if => version_compare("3.22.1", ">=", "3.22"); +} +``` + +Since `3.22` is less specific than `3.22.1` they are considered equal - all of the parts which can be compared are the same. +For the version comparison logic, if you are asking if something is greater than `3.22`, it must be at least `3.23`, `3.22.1` is not enough. +Thus, it is often more intuitive to use the `>=` operator to mean all versions at or after the specified version (regardless of how specific the version numbers are). + +**See also:** `cf_version_minimum()`, `cf_version_maximum()`, `cf_version_after()`, `cf_version_before()`, `cf_version_at()`, `cf_version_between()`. + +**History:** + +* Introduced in 3.23.0 From 3ffe614a7aab93a98805e0c403bd678eb1535b97 Mon Sep 17 00:00:00 2001 From: Ole Herman Schumacher Elgesem <4048546+olehermanse@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:27:12 +0200 Subject: [PATCH 2/3] Macro parameters fixed by @nickanderson in code review Co-authored-by: Nick Anderson --- reference/functions/version_compare.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/functions/version_compare.markdown b/reference/functions/version_compare.markdown index eb5130140..b85d18809 100644 --- a/reference/functions/version_compare.markdown +++ b/reference/functions/version_compare.markdown @@ -4,11 +4,11 @@ title: version_compare published: true --- -[%CFEngine_function_prototype(string)%] +[%CFEngine_function_prototype(version1, comparison, version2)%] **Description:** Returns `true` if the specified version comparison expression is true. -[%CFEngine_function_attributes(string)%] +[%CFEngine_function_attributes(version1, comparison, version2)%] The `version_compare()` function can be used to compare 2 arbitrary semver version numbers. This can be useful if you have 2 versions of a package and you want to know if they are the same version, if one is newer than the other etc. From de9e8ce77d92a67cfe550bd955d59cfc3db17a08 Mon Sep 17 00:00:00 2001 From: Ole Herman Schumacher Elgesem Date: Thu, 12 Oct 2023 13:54:21 +0200 Subject: [PATCH 3/3] cf-check.markdown: Fixed macro invocation, hopefully Signed-off-by: Ole Herman Schumacher Elgesem --- reference/components/cf-check.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/components/cf-check.markdown b/reference/components/cf-check.markdown index 3323accc6..e65844841 100644 --- a/reference/components/cf-check.markdown +++ b/reference/components/cf-check.markdown @@ -10,4 +10,4 @@ Utility for diagnosis and repair of local CFEngine databases. ## Command reference -[%CFEngine_include_snippet(cf-check.help, ^Commands:)%] +[%CFEngine_include_snippet(cf-check.help, [\s]*--[a-z], ^$)%]