-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an admin command to compare 2 package versions #6124
Conversation
d22c06a
to
2269e35
Compare
64eb403
to
a9049b1
Compare
I recommend following the design of https://manpages.ubuntu.com/manpages/oracular/en/man1/dpkg.1.html
|
Hello @avsm so nice to have you join the conversation! Thank you for pointing out that command, I'll have a look. At quick glance, this can suggest that this new opam command could be named About the design I'd be curious what usage do you have in mind. I sort of see the appeal to re-using existing designs, but in this case, I feel:
The part about empty versions of dpkg just sounds very confusing to me. Is this due to a command parsing technicality, or are there really support for empty package versions out there? Does opam support empty package versions too? |
Adding a note about empty versions:
As of the current tip of this PR: $ ./_build/default/src/client/opamMain.exe admin compare-package-versions '' '1'
opam admin: VERSION argument: Package version can't be empty
Usage: opam admin compare-package-versions [OPTION]… VERSION VERSION
Try 'opam admin compare-package-versions --help' or 'opam admin --help' for more information. So if we wanted to support empty version, some more changes would be required. |
I have no strong opinion, but outputting shell operators like Two other options that are more "unix-like":
|
@avsm Thanks a lot for this input, this is really helpful. I am going to explore ideas base on your suggestions, reverting the PR as a draft for now. |
I don't personally see much value in a ""unix-style"" command. If people wanted that it'd be easier for them to just create a dedicated program using the |
How are they meant to be used, then? The majority of invocations of these commands are part of a sequence of shell commands -- be they interactive, Dockerfiles, obuilder outputs, or whatever else. opam even documents |
@kit-ty-kate I think there could be a middle ground: if we add an optional How about the name 'compare-versions' vs 'compare-package-versions' ? I have renamed locally, let me know if I should push this commit or not. |
Not following the discussion but just note that |
As mentioned in #6118 this would be used as part of a double-check for packages unfamiliar with opam/debian version ordering, so always interactively. What use-case would there be in an automated context? |
I use something similar in my personal opam repo (full of my homebrew shell scripts) to find the latest package revision from a directory to choose which one to install (just from looking at the opam files; there is no initialised opam here for various reasons yet and so no solver). And more generally, I've used almost every command exposed by opam at some point in a shell script while doing something-or-other with the repositories -- it's just how CLIs are used! I'm not saying there's anything wrong with the design proposed in the original PR, except for a preference to not output known-shell-fragments (but even that's probably fine these days). But the ability to sort a list of package names+versions would definitely be something I find useful -- I've written OpamVersionCompare fragments for that several times in different contexts. Thinking about @dbuenzli's comment a bit more -- we never have a meaningful case where two versions are the same opam versions but lexically different, do we? So the ordering logic just needs to sort in ascending order, and then equal versions would be distinguishable by the fact they're the same string. No need for exit codes then. |
we do. For example: |
Bah, good example! I thought those were different, but what I was thinking of was the common mistake of "1.0.0" <> "1.0" in package formula. So checking for equality is significant too, so it's not enough to just output a sorted list of package versions. |
I updated the PR based on the previous comments and will proceed to re-opening for another round of review. Thanks! |
531d4e0
to
5eee963
Compare
Hello. I have rebased the PR. I wanted to add a note about the addition of the This use case involves a setup using a
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otherwise that looks good to me
Thanks a lot @kit-ty-kate for the review and for pointing me to the existing comparison operators. I updated as you suggested. |
That sounds interesting to me. I thought this would be rejected (doesn't it open the door for specs that quickly become ambiguous?). I want to explore this a bit more, in particular see what happens when you "squeeze" optional positional args in the middle of required positional args. I created mbarbin/cmdlang#6 to track. Short of that:
match%bind Arg.count_positional with
| 2 ->
let%map v1 = pos 0 version
and v2 = pos 1 version in
`Compute (v1, v2)
| 3 ->
let%map v1 = pos 0 version
and op = pos 1 operator
and v2 = pos 2 version in
`Assert (v1, op, v2)
As a side note, selecting the mode of a multi-mode commands with a named arguments feels more natural to me rather than by the presence/absence of positional arguments, but I don't think this argument is tenable, as there are probably countless counter-examples in the Unix literature. Plus, @dra27 's input seem to convey the opposite preference, at least in this instance, so I guess I'm happy not to account for my personal preference here. I'm sort of stuck there. Is there another combinator I am not thinking of from |
Isn't that possible with 3 |
That's what I want to explore a bit more. I am used to hitting this limitation when attempting this sort of things. Let me play a bit with it and I'll get back to you. Thanks for your help! |
Mmh, yeah it looks like cmdliner doesn't support that given positional arguments are absolute and do not change depending on optional parameters let test arg1 arg2 arg3 =
Printf.printf "arg1 = %s\narg2 = %s\narg3 = %s\n"
arg1 (match arg2 with None -> "None" | Some x -> "Some "^x) arg3
module Arg = Cmdliner.Arg
module Cmd = Cmdliner.Cmd
module Term = Cmdliner.Term
let arg1 = Arg.(required & pos 0 (some string) None & info [])
let arg2 = Arg.(value & pos 1 (some string) None & info [])
let arg3 = Arg.(required & pos 2 (some string) None & info [])
let cmd =
let info = Cmd.info "test" ~version:"dev" in
Cmd.v info Term.(const test $ arg1 $ arg2 $ arg3)
let main () = Stdlib.exit (Cmd.eval cmd)
let () = main ()
let's keep |
Honestly I think you are all a bit overthinking that :-) Simply ask for three positional arguments make the last one optional, resolve that in code with a proper match and write the |
Thanks for the input @dbuenzli! Personally, I wouldn't know how to defend doing that, versus keeping withing a well supported use case and keeping the
My inclination is for |
Also I often find it that when people try to do subtle things with cli, it's often not in the interest of the end-users. In this particular case, why not simply always require the operator ? I don't think having a default operator brings much here except that I will have to remember it. |
I closed it. The problem is that in general this leads to ambiguous parses. There are already enough of these to confuse users, let's not add more. |
Are you proposing to add a syntax for a special "don't know" operator? Like: $ opam admin compare-versions 0.0.9 '?' 0.0.10
0.0.9 < 0.0.10 |
Rather that you don't need this mode of operation. The operators |
If the command also prints on stderr the corrected inequality, spelled out, in case of an error, I'd be OK with this. This is very close to my initial motivating use case. $ opam admin compare-versions 0.33.0-preview.1 '<' 0.33.0
0.33.0-preview.1 > 0.33.0
[1] |
@kit-ty-kate what do you think? I pushed a preview here (keeping the existing operators). Edit: subsumed by #6196 |
I would find this a rather confusing cli. Why not simply output on stdout |
As a reminder, I was trying to introduce a command that allows comparing versions from the command line, for which you are not sure During the course of this conversation, I have tried avoiding designs that forces me to run the command multiple times, trying to "guess" what the correct result is each time, rather than being able to run a command once, and have the result nicely displayed on my screen. Any design that returns a response with 1 bit of information will suffer from the characteristic that I am trying to avoid, given that the answer I am looking for doesn't fit on 1 bit ( The I am starting to loose faith that I'll be able to provide a proposal that pleases everybody. I'm sorry if I have used too much of the reviewers time and patience, this really wasn't my intention to begin with. |
Mmh sorry I misunderstood what you were trying to provide because I inferred it from the command name you proposed, namely I would rather suggest
Note that |
Thank you for this reply.
I suppose it depends on the perspective you adopt. See for example: $ dune/otherlibs/stdune/src$ grep -RI 'val compare :'unit.mli:val compare : t -> t -> Ordering.t
list.mli:val compare : 'a t -> 'a t -> compare:('a -> 'a -> Ordering.t) -> Ordering.t
env.mli: val compare : t -> t -> Ordering.t
loc0.mli:val compare : t -> t -> Ordering.t
filename.mli:val compare : t -> t -> Ordering.t
path_intf.ml: val compare : 'w t -> 'w t -> Ordering.t
bool.mli:val compare : t -> t -> Ordering.t
sexp.mli:val compare : t -> t -> Ordering.t
char.mli:val compare : t -> t -> Ordering.t
signal.mli:val compare : t -> t -> Ordering.t
string.mli:val compare : t -> t -> Ordering.t
ansi_color.ml: val compare : t -> t -> Ordering.t
ansi_color.ml: val compare : t -> t -> Ordering.t
user_message.mli: val compare : t -> t -> Ordering.t
user_message.mli:val compare : t -> t -> Ordering.t
comparator.mli: val compare : t -> t -> Ordering.t
set_intf.ml: val compare : t -> t -> Ordering.t
ansi_color.mli: val compare : t -> t -> Ordering.t
int.mli:val compare : t -> t -> Ordering.t
option.mli:val compare : ('a -> 'a -> Ordering.t) -> 'a t -> 'a t -> Ordering.t
bit_set.mli: val compare : t -> t -> Ordering.t
path.ml: val compare : t -> t -> Ordering.t
float.mli:val compare : t -> t -> Ordering.t
comparator.ml: val compare : t -> t -> Ordering.t
lexbuf.mli: val compare : t -> t -> Ordering.t
id.ml: val compare : t -> t -> Ordering.t
id.mli: val compare : t -> t -> Ordering.t
loc.mli:val compare : t -> t -> Ordering.t
poly.mli:val compare : 'a -> 'a -> Ordering.t
map_intf.ml: val compare : 'a t -> 'a t -> compare:('a -> 'a -> Ordering.t) -> Ordering.t See also base todo item. I also understand the perspective of using a new terminology for ordering elements.
That makes sense to me. I agree this PR as it is now suffers from trying to fit two conflicting views into a single command. The behavior you describe for |
Sure, I'm not attached to the names I suggested, I just needed another name to make the point about not cramming the two behaviours in the same command. |
I created a new draft trying to account for the various feedback received here. Please see : #6196 Thanks! |
If we prefer non-quoted operators, there's also the possibility of using the operator names as flags (rather than "--assert") and being back to having 1 single command. I created a version based on in #6197 as an additional data point. I'll have some time to look again into this PR and the end of next week. Thanks a lot! |
Looking at all 3 PRs i think i prefer #6197 ( |
In retrospect that's the one I prefer as well so far. Thank you for following up and letting me know about your meeting. I'll be ready to help moving things forward as you see fit. Thanks a lot! |
Dev meeting note: after discussion, #6197 looks preferable for all 3 of us (Raja, David, Kate) |
Great! I'll close the other ones, and do a little pass at it, so we can do a first round of review. Thank you! |
Add a new CLI
opam admin compare-versions
to compare package versions for sanity checks.This command has 2 modes:
In this mode, we provide two versions, and opam outputs a user-friendly expression with the result of the comparison, spelled out. For example:
$ opam admin compare-versions 0.0.9 0.0.10 0.0.9 < 0.0.10
The command exits 0 regardless of the result of the comparison.
--assert=OP
.In this mode, the output is suppressed (the command is silent). The result of the command will be encoded in the exit code, to be used in bash conditionals:
exit 0: the comparison holds
exit 1: it doesn't
For example:
Original notes
This is meant for quick sanity checks for example.
Added some basic tests to cover the command. The tests I added do not duplicate the tests for the actual comparison function, rather that meant to cover the basic cases encountered by the command.
Please update
master_changes.md
file with your changes.This is following a discussion with @kit-ty-kate in #6118.
Note to reviewers:
I wasn't too sure where to expose the new command. It's not really an admin command, but I couldn't find another suitable section.
This is my first PR on opam and I am not familiar with the code base, as well as some dependencies (e.g. cmdliner). Please feel free to request for as many changes as you like. Thank you!