flake_env/lib/flake_env__versions.re
Bryan Bennett 5c01142933
Remove dependency on Janestreet Core
Core doubles the closure size and adds 8mb to the binary size for dubious benefit.
This adds FileUtils to do the file interaction bits that aren't in the
stdlib and removes Core in preference to the bundled Stdlib.

Tests are passing, but I want to investigate the nix build before I
commit to this approach
2024-08-12 12:13:53 -04:00

90 lines
2.5 KiB
ReasonML

module Util = Flake_env__util;
type t = {
major: int,
minor: int,
point: int,
};
/*** Initialize a Versions.t from major, minor, and point versions */
let init = (major, minor, point) => {major, minor, point};
let pprint = (pp_fmt, t) =>
Format.fprintf(pp_fmt, "{ %d.%d.%d }", t.major, t.minor, t.point);
let required_direnv_version = init(2, 21, 3);
let required_nix_version = init(2, 10, 0);
let semver_re = Re.compile(Re.Posix.re({|([0-9]+)\.([0-9]+)\.([0-9]+)|}));
let compare = (a, b) => {
switch (a, b) {
| (a, b) when a.major == b.major && a.minor == b.minor && a.point == b.point => 0
| (a, b) when a.major < b.major => (-1)
| (a, b) when a.major == b.major && a.minor < b.minor => (-1)
| (a, b) when a.major == b.major && a.minor == b.minor && a.point < b.point => (-1)
| _ => 1
};
};
let extract_version_number = cmd => {
switch (Util.run_process(cmd, ["--version"])) {
| (WEXITED(0), stdout) when String.length(stdout) > 0 =>
switch (Re.exec(semver_re, stdout)) {
| exception Stdlib.Not_found =>
Error(
Printf.sprintf(
"Stdout did not contain a version number for `%s --version`",
cmd,
),
)
| substrings =>
let groups = Re.Group.all(substrings);
Ok({
major: groups[1] |> int_of_string,
minor: groups[2] |> int_of_string,
point: groups[3] |> int_of_string,
});
}
| _ => Error(Printf.sprintf("Failed executing '%s'", cmd))
};
};
let is_new_enough = (cur, needed) => {
switch (cur) {
| Ok(cur) =>
switch (compare(cur, needed)) {
| x when x < 0 => Ok(false)
| _ => Ok(true)
}
| Error(e) => Error(e)
};
};
let in_direnv = () =>
/* direnv sets `$direnv` to the executable's full path
If it is empty - we're running tests (ocaml's stdlib doesn't offer unsetenv...)
If it isn't found, we're running outside direnv
*/
switch (Sys.getenv("direnv")) {
| exception Not_found => false
| "" => false
| _ => true
};
let preflight_versions = () => {
let is_nix_new_enough =
is_new_enough(extract_version_number("nix"), required_nix_version);
let is_direnv_new_enough =
is_new_enough(extract_version_number("direnv"), required_direnv_version);
switch (in_direnv(), is_direnv_new_enough, is_nix_new_enough) {
| (false, _, _) => Error("Not in direnv!")
| (_, Ok(false), _) => Error("Direnv version is not new enough")
| (_, _, Ok(false)) => Error("Nix version is not new enough")
| (_, Error(e), _) => Error(e)
| (_, _, Error(e)) => Error(e)
| (true, Ok(true), Ok(true)) => Ok()
};
};