diff --git a/doc/man/opam-admin-topics.inc b/doc/man/opam-admin-topics.inc index c2618ecb6cf..ffbb4aed863 100644 --- a/doc/man/opam-admin-topics.inc +++ b/doc/man/opam-admin-topics.inc @@ -60,6 +60,16 @@ (diff opam-admin-list.err %{dep:opam-admin-list.0}))) (package opam)) +(rule + (with-stdout-to opam-admin-compare-versions.0 (echo ""))) +(rule + (targets opam-admin-compare-versions.1 opam-admin-compare-versions.err) + (deps using-built-opam) + (action (progn (with-stderr-to opam-admin-compare-versions.err + (with-stdout-to opam-admin-compare-versions.1 (run %{bin:opam} admin compare-versions --help=groff))) + (diff opam-admin-compare-versions.err %{dep:opam-admin-compare-versions.0}))) + (package opam)) + (rule (with-stdout-to opam-admin-check.0 (echo ""))) (rule @@ -130,6 +140,7 @@ opam-admin-add-constraint.1 opam-admin-filter.1 opam-admin-list.1 + opam-admin-compare-versions.1 opam-admin-check.1 opam-admin-lint.1 opam-admin-upgrade.1 diff --git a/master_changes.md b/master_changes.md index 47973be912d..886b124de04 100644 --- a/master_changes.md +++ b/master_changes.md @@ -15,6 +15,7 @@ users) * Bump opam-root-version to 2.2 [#5980 @kit-ty-kate] ## Global CLI + * ◈ Add `opam admin compare-versions` to compare package versions for sanity checks [#6124 @mbarbin] * Add cli version 2.3 [#6045 #6151 @rjbou] ## Plugins diff --git a/src/client/opamAdminCommand.ml b/src/client/opamAdminCommand.ml index 38954d1c6b1..1433c798e59 100644 --- a/src/client/opamAdminCommand.ml +++ b/src/client/opamAdminCommand.ml @@ -830,6 +830,72 @@ let check_command cli = Term.(const cmd $ global_options cli $ ignore_test_arg $ print_short_arg $ installability_arg $ cycles_arg $ obsolete_arg) +let compare_versions_command_doc = "Compare 2 package versions" +let compare_versions_command cli = + let operators = + List.map (fun op -> OpamFormula.string_of_relop op, op) + OpamFormula.all_relop + in + let assert_result = + let doc = + Arg.info + ~docv:"OP" + ~doc:(Printf.sprintf + "When supplied, the output is suppressed and the result of \ + the comparison is checked againts the provided operator. \ + The command exits 0 if the comparison holds, and 1 otherwise. \ + $(docv) must be %s.\n" (Arg.doc_alts_enum ~quoted:true operators)) + [ "assert" ] + in + Arg.(value & opt (some (enum operators)) None doc) + in + let version_arg n = + let doc = + Arg.info + ~docv:(Printf.sprintf "VERSION%d" (n+1)) + ~doc:"Package version to compare" [] + in + Arg.(required & pos n (some OpamArg.package_version) None & doc) + in + let command = "compare-versions" in + let doc = compare_versions_command_doc in + let man = [ + `S Manpage.s_description; + `P "This command compares 2 package versions for quick sanity checks. \ + By default it prints the result of the comparison to the console. \ + You may optionally control the exit-code with '--assert=OP'. \ + For example:"; + `Pre "\n\ + \\$ opam admin compare-versions 0.0.9 0.0.10\n\ + 0.0.9 < 0.0.10\n\ + \n\ + \\$ opam admin compare-versions 0.0.9 0.0.10 --assert='<'\n\ + [0]\n\ + \n\ + \\$ opam admin compare-versions 0.0.9 0.0.10 --assert='>='\n\ + [1]"; + `S Manpage.s_arguments; + `S Manpage.s_options; + ] + in + let cmd global_options v1 v2 assert_result () = + OpamArg.apply_global_options cli global_options; + match assert_result with + | None -> + let result = OpamPackage.Version.compare v1 v2 in + OpamConsole.formatted_msg "%s %s %s\n" + (OpamPackage.Version.to_string v1) + (if result < 0 then "<" else if result = 0 then "=" else ">") + (OpamPackage.Version.to_string v2) + | Some op -> + OpamStd.Sys.exit_because + (if OpamFormula.eval_relop op v1 v2 + then `Success + else `False) + in + OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man + Term.(const cmd $ global_options cli $ version_arg 0 $ version_arg 1 $ assert_result) + let pattern_list_arg = OpamArg.arg_list "PATTERNS" "Package patterns with globs. matching against $(b,NAME) or \ @@ -1227,6 +1293,7 @@ let admin_subcommands cli = upgrade_command cli; lint_command cli; check_command cli; + compare_versions_command cli; list_command cli; filter_command cli; add_constraint_command cli; diff --git a/src/format/opamFormula.ml b/src/format/opamFormula.ml index 96e651175e7..84e6857b090 100644 --- a/src/format/opamFormula.ml +++ b/src/format/opamFormula.ml @@ -21,6 +21,8 @@ let neg_relop = function let string_of_relop = OpamPrinter.FullPos.relop_kind +let all_relop = [ `Eq ; `Neq ; `Geq ; `Gt ; `Leq ; `Lt ] + type version_constraint = relop * OpamPackage.Version.t type atom = OpamPackage.Name.t * version_constraint option diff --git a/src/format/opamFormula.mli b/src/format/opamFormula.mli index 6b5539eb093..65d1dba4879 100644 --- a/src/format/opamFormula.mli +++ b/src/format/opamFormula.mli @@ -17,6 +17,13 @@ type relop = OpamParserTypes.FullPos.relop_kind (* = [ `Eq | `Neq | `Geq | `Gt | val compare_relop : relop -> relop -> int +(** A list containing each available operator once. *) +val all_relop : relop list + +(** Returns a string representing the operator in infix syntax, as + used in opam files (">", "=", etc.) *) +val string_of_relop : relop -> string + (** Version constraints for OPAM *) type version_constraint = relop * OpamPackage.Version.t diff --git a/tests/reftests/compare-versions.test b/tests/reftests/compare-versions.test new file mode 100644 index 00000000000..1170ebc94c4 --- /dev/null +++ b/tests/reftests/compare-versions.test @@ -0,0 +1,22 @@ +N0REP0 +### opam admin compare-versions 0.0.9 0.0.10 +0.0.9 < 0.0.10 +### opam admin compare-versions 1.2.3 1.2.3~preview +1.2.3 > 1.2.3~preview +### opam admin compare-versions 0.1.0 0.01.0 +0.1.0 = 0.01.0 +### opam admin compare-versions 0.1.0 0.01.0 --assert '=' +### opam admin compare-versions 0.0.9 0.0.10 --assert '<' +### opam admin compare-versions 0.0.9 0.0.10 --assert '<=' +### opam admin compare-versions 1.2.3 1.2.3~preview --assert '>' +### opam admin compare-versions 1.2.3 1.2.3~preview --assert '>=' +### opam admin compare-versions 0.0.9 0.0.10 --assert '=' +# Return code 1 # +### opam admin compare-versions 1.2.3 1.2.3~preview --assert '<' +# Return code 1 # +### opam admin compare-versions 1.2.3-option 1.2.3 --assert '<=' +# Return code 1 # +### opam admin compare-versions 0.0.9 0.0.10 --assert '>' +# Return code 1 # +### opam admin compare-versions 0.0.9 0.0.10 --assert '>=' +# Return code 1 # diff --git a/tests/reftests/dune.inc b/tests/reftests/dune.inc index 9496f04fec6..cc4f3ccf8af 100644 --- a/tests/reftests/dune.inc +++ b/tests/reftests/dune.inc @@ -188,6 +188,24 @@ %{targets} (run ./run.exe %{exe:../../src/client/opamMain.exe.exe} %{dep:cli-versioning.test} %{read-lines:testing-env})))) +(rule + (alias reftest-compare-versions) + (action + (diff compare-versions.test compare-versions.out))) + +(alias + (name reftest) + (deps (alias reftest-compare-versions))) + +(rule + (targets compare-versions.out) + (deps root-N0REP0) + (package opam) + (action + (with-stdout-to + %{targets} + (run ./run.exe %{exe:../../src/client/opamMain.exe.exe} %{dep:compare-versions.test} %{read-lines:testing-env})))) + (rule (alias reftest-config) (enabled_if (and (or (<> %{env:TESTALL=1} 0) (= %{env:TESTN0REP0=0} 1))))