ropkg: add command to compare two version strings

This commit is contained in:
2025-07-21 22:47:03 +01:00
parent b11682d55d
commit 231dbe8f7f
2 changed files with 237 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ enum {
CMD_QUERY, CMD_QUERY,
CMD_EXTRACT, CMD_EXTRACT,
CMD_INSTALL, CMD_INSTALL,
CMD_COMPARE_VERSION,
}; };
#endif #endif

236
ropkg/compare-version.c Normal file
View File

@@ -0,0 +1,236 @@
#include "commands.h"
#include "ropkg/version.h"
#include <blue/cmd.h>
#include <stdio.h>
enum {
OPT_VERBOSE,
ARG_VERSION_LEFT,
ARG_OPERATOR,
ARG_VERSION_RIGHT,
};
static enum ropkg_status comparison_op_from_string(
const char *s,
enum ropkg_comparison_op *out)
{
if (!strcmp(s, "==") || !strcmp(s, "eq")) {
*out = ROPKG_OP_EQUAL;
} else if (!strcmp(s, "<") || !strcmp(s, "lt")) {
*out = ROPKG_OP_LESS_THAN;
} else if (!strcmp(s, "<=") || !strcmp(s, "le")) {
*out = ROPKG_OP_LESS_EQUAL;
} else if (!strcmp(s, ">") || !strcmp(s, "gt")) {
*out = ROPKG_OP_GREATER_THAN;
} else if (!strcmp(s, ">=") || !strcmp(s, "ge")) {
*out = ROPKG_OP_GREATER_EQUAL;
} else if (!strcmp(s, "!=") || !strcmp(s, "ne")) {
*out = ROPKG_OP_NOT_EQUAL;
} else {
return ROPKG_ERR_INVALID_ARGUMENT;
}
return ROPKG_SUCCESS;
}
static int compare_version(
const b_command *self,
const b_arglist *opt,
const b_array *args)
{
int ret = -1;
bool verbose = false;
struct ropkg_version *left = NULL, *right = NULL;
enum ropkg_status status = ropkg_version_create(&left);
if (!B_OK(status)) {
goto end;
}
status = ropkg_version_create(&right);
if (!B_OK(status)) {
goto end;
}
const char *left_string = NULL, *right_string = NULL, *op_string = NULL;
b_arglist_get_string(
opt,
B_COMMAND_INVALID_ID,
ARG_VERSION_LEFT,
0,
&left_string);
b_arglist_get_string(
opt,
B_COMMAND_INVALID_ID,
ARG_VERSION_RIGHT,
0,
&right_string);
b_arglist_get_string(
opt,
B_COMMAND_INVALID_ID,
ARG_OPERATOR,
0,
&op_string);
verbose = b_arglist_get_count(opt, OPT_VERBOSE, B_COMMAND_INVALID_ID)
> 0;
if (!left_string) {
b_arglist_report_missing_args(
opt,
B_COMMAND_INVALID_ID,
ARG_VERSION_LEFT,
0);
goto end;
}
if (!right_string) {
b_arglist_report_missing_args(
opt,
B_COMMAND_INVALID_ID,
ARG_VERSION_RIGHT,
0);
goto end;
}
if (!op_string) {
b_arglist_report_missing_args(
opt,
B_COMMAND_INVALID_ID,
ARG_OPERATOR,
0);
goto end;
}
b_result result = ropkg_version_parse(left, left_string);
if (b_result_is_error(result)) {
b_throw(result);
goto end;
}
result = ropkg_version_parse(right, right_string);
if (b_result_is_error(result)) {
b_throw(result);
goto end;
}
enum ropkg_comparison_op op;
status = comparison_op_from_string(op_string, &op);
if (status != ROPKG_SUCCESS) {
b_arglist_report_invalid_arg_value(
opt,
B_COMMAND_INVALID_ID,
ARG_OPERATOR,
op_string);
goto end;
}
bool comparison_result = ropkg_version_compare(left, right, op);
ret = comparison_result ? 0 : 1;
if (verbose) {
char temp[128];
ropkg_version_to_string(left, temp, sizeof temp);
printf("%s ", temp);
switch (op) {
case ROPKG_OP_EQUAL:
printf("== ");
break;
case ROPKG_OP_NOT_EQUAL:
printf("!= ");
break;
case ROPKG_OP_LESS_THAN:
printf("< ");
break;
case ROPKG_OP_LESS_EQUAL:
printf("<= ");
break;
case ROPKG_OP_GREATER_THAN:
printf("> ");
break;
case ROPKG_OP_GREATER_EQUAL:
printf(">= ");
break;
default:
break;
}
ropkg_version_to_string(right, temp, sizeof temp);
printf("%s -> %s\n",
temp,
comparison_result ? "true" : "false");
}
end:
if (left) {
ropkg_version_destroy(left);
}
if (right) {
ropkg_version_destroy(right);
}
return ret;
}
B_COMMAND(CMD_COMPARE_VERSION, CMD_ROOT)
{
B_COMMAND_NAME("compare-version");
B_COMMAND_DESC("compare two package version identifiers.");
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
B_COMMAND_FUNCTION(compare_version);
B_COMMAND_HELP_OPTION();
B_COMMAND_OPTION(OPT_VERBOSE)
{
B_OPTION_SHORT_NAME('v');
B_OPTION_LONG_NAME("verbose");
B_OPTION_DESC(
"print the result of the comparison to "
"standard out.");
}
B_COMMAND_ARG(ARG_VERSION_LEFT)
{
B_ARG_NAME("left-version");
B_ARG_DESC("the left-side of the comparison operation.");
B_ARG_NR_VALUES(1);
}
B_COMMAND_ARG(ARG_OPERATOR)
{
B_ARG_NAME("operator");
B_ARG_DESC("the comparison operator to use.");
B_ARG_ALLOWED_VALUES(
"==",
"!=",
"<",
"<=",
">",
">=",
"eq",
"ne",
"lt",
"le",
"gt",
"ge");
B_ARG_NR_VALUES(1);
}
B_COMMAND_ARG(ARG_VERSION_RIGHT)
{
B_ARG_NAME("right-version");
B_ARG_DESC("the right-side of the comparison operation.");
B_ARG_NR_VALUES(1);
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_ARG(ARG_VERSION_LEFT);
B_COMMAND_USAGE_ARG(ARG_OPERATOR);
B_COMMAND_USAGE_ARG(ARG_VERSION_RIGHT);
}
}