-
Notifications
You must be signed in to change notification settings - Fork 8
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
Use the opam library (for read_only operations) #75
base: main
Are you sure you want to change the base?
Conversation
Using the library instead of the binary avoids parsing the output of the binary, yields a cleaner code and should spead up the time needed for the queries.
About my sentence
Actually, I guess it's better to try that locally instead of relying on the CI server... If this point is relevant for you to decide, let me know and I try locally. |
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.
Here is a first set of comments. In addition to the comment in the code:
- I do not agree with changing all the
Ocaml_version.t
toOpamPackage.t
, the former is what we need, and it avoids having to call for the version of a package several times... - Why not having the
with_*
functions wrapped into more standalone functions? It seems that theswitch_state
is never used more than once, so that won't really make it longer... (for now, so maybe we should keep it as it is) (EDIT: I do not think we should modify this anymore)
match Fpath.of_string path with | ||
| Error (`Msg s) -> Error (`Msg s) |
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.
Why changing the type of path
from Fpath.t
to string
And if you do so, why not using the let*
syntax?
|> List.fold_left | ||
(fun acc file -> | ||
match file with | ||
| filename, _ -> OpamFilename.to_string filename :: acc) |
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.
Let's Fpath.parse
it!
| filename, _ -> OpamFilename.to_string filename :: acc) | |
| filename, _ -> filename |> OpamFilename.to_string |> Fpath.parse :: acc) |
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.
I think you meant Fpath.of_string
, which does error checking. But I think we can get away with Fpath.v
and expect OpamFilename
to give us valid paths.
| filename, _ -> OpamFilename.to_string filename :: acc) | |
| filename, _ -> OpamFilename.to_string filename |> Fpath.v :: acc) |
Opam.Queries.( | ||
with_switch_state | ||
~dir_name:(Sandbox_switch.get_sandbox_root sandbox) | ||
(files_installed_by_pkg query_name)) | ||
>>= fun paths -> |
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.
Why not wrap all of this into a list_files
function again?
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.
Yes! I'd prefer to keep the Opam
module API close to what it was (of course not exactly the same).
This was useful for maintenance as it avoids inconsistent uses of the same API in different places and adds types, for example, it certainly helped to write this patch.
let latest_version ~metadata_universe ~pkg_universe ~ocaml package = | ||
let package = OpamPackage.Name.of_string package in |
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.
If we want to stop carrying strings around, package
should be of type OpamPackage.Name.t
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.
Actually that's one of your points!
let compatible_ones = | ||
OpamPackage.Set.filter | ||
(fun pkg -> | ||
OpamPackage.Name.equal (OpamPackage.name pkg) package | ||
&& | ||
let pkg_opam_file = OpamPackage.Map.find pkg metadata_universe in | ||
let dependencies = OpamFile.OPAM.depends pkg_opam_file in | ||
let env _ = None in | ||
OpamFormula.verifies | ||
(OpamPackageVar.filter_depends_formula ~env dependencies) | ||
ocaml) | ||
pkg_universe | ||
in |
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.
This seems not very efficient to me: it will have to see all package and check if the name is the right one.
Would there be a way to get all versions of package
, and replace pkg_universe
with this list, and then filter with the formula?
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.
(but maybe it is not long, I should try it out, there are not so many opam package for a computer!)
try Some (OpamPackage.max_version compatible_ones package) | ||
with Not_found -> None | ||
|
||
let installed_versions pkg_names |
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.
pkg_names
should be of type OpamPackage.Name.t list
here
(name, version)) | ||
pkg_names | ||
|
||
let files_installed_by_pkg pkg_name |
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.
pkg_name
should be of type OpamPackage.Name.t
here
let get_metadata_universe (switch_state : 'lock OpamStateTypes.switch_state) = | ||
switch_state.opams | ||
|
||
let get_switch = function |
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.
format error ? :)
From a few experiments, in terms of "inferring tools version", it speeds things up a lot when dealing with old versions of the compiler (which is not uncommon at all, as opam by default inits a system switch which tend to be old), but it also slows things down on a recent switch, with some tools already installed... |
About my last review:
I don't have a strong opinion on that, the "I do not agree" does not reflect that...
Now I think that it is good as it is, it allows us to have more control on how long we want to keep the states loaded. So ignore this comment! |
I disagree with these two points:
If the magical single fast query I was talking about exists, I would prefer to stick with the CLI, which is also simpler to call (except the part where we need an angstrom parser). Otherwise, I agree that the code is better with more types and less command outputs to parse. |
Hey @Julow , after @panglesd's comments I've already started (and pretty much finished) the second part of this PR that I mentioned of making our code more type safe by making use of the opam library types. But now, after reading your comments, I'm doubting if I should finish that. About your comments about performance: tbh, I'm still not sure if library or binary would be better in terms of performance. In fact, it's possible that it will be similar in the end. If it's similar, I think the library would be clearly the better choice, simply because I prefer compile time errors over runtime errors. Concretely, with the library we can make the code far more type save (instead of having strings everywhere, we use concrete types) and because we don't need to parse the output of the binary anymore. Type safeness is one of the many cool features OCaml can leverage when we want it to! And similarly about your second comment:
The problem about the binary output possibly being unstable is that we'll most likely notice a change there at runtime. I mean, we make some opam binary query, parse its output into a string, pass that string around and at the end make another call to the opam binary with that string, hoping that that string represents a tool name. However, if we use the library and there's a change in the library, we'll notice at compile time, adapt the code to the new version (like always when a dependency of ours cuts a breaking release) and that's it. So, I'm pretty much saying the opposite of your statement:
The reasons you give for that statement are:
I'll need to understand what you mean with those points to answer to them.
Do you maybe already want me to push the changes I've made to improve type safeness so that you can have a look at what that would look like (even though it isn't perfect yet)? |
About performances, I think the "one magical query" might run in ~1s (the time to start an
The binary API is defined and a lot of work in put into Opam for not breaking the API and versionning. The library don't have this concern but as you say, it doesn't really matter because breakings are detected at compile time.
Yes please! |
Using the library instead of the binary has four advantages: it avoids parsing the printed output of the binary, it yields a cleaner code, it should speed up the time needed for the queries, and it makes us depend less on a binary whose future is uncertain. For the pen-ultimate statement about the speed-up, let's have a look at the CI and how long it takes for each step compared to before to see if that's actually true.
I'm already opening the PR to discuss if this is something we want to go forward with before doing the last things I'd do:
env
does when querying dependency state and possibly adapt it to what we needOpam.GlobalObts
should still be used, also when making the queries via the library (it was used before and currently I'm not using it anymore)string
s all the time and pass around more specific types instead (e.g.OpamPackage.Name.t
).If I remember correctly, the last time you tried using the library, you discarded doing that for the following reasons:
Let me know what you think about this PR in general please to see if it's worth spending the time to improve the things mentioned above!