Browse Source

Add support for `lts/*` (#146)

* support lts/*

* Remove redundant line

* Add test

* Slight refactor
remotes/origin/add-simple-redirecting-site
Gal Schlezinger 5 years ago committed by GitHub
parent
commit
65c6d569af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      executable/Env.re
  2. 29
      executable/Install.re
  3. 4
      executable/ListLocal.re
  4. 22
      executable/Use.re
  5. 1
      feature_tests/latest-lts/.nvmrc
  6. 10
      feature_tests/latest-lts/run.sh
  7. 2
      feature_tests/run.sh
  8. 2
      library/Dotfiles.re
  9. 6
      library/Fs.re
  10. 48
      library/Path.re
  11. 12
      library/Result.re
  12. 2
      library/System.re
  13. 34
      library/VersionListing.re
  14. 29
      library/VersionListingLts.re
  15. 21
      library/Versions.re
  16. 4
      library/dune
  17. 6
      package.json

2
executable/Env.re

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
open Fnm;
let symlinkExists = path =>
try%lwt (Lwt_unix.lstat(path) |> Lwt.map(_ => true)) {
try%lwt(Lwt_unix.lstat(path) |> Lwt.map(_ => true)) {
| _ => Lwt.return(false)
};

29
executable/Install.re

@ -71,6 +71,18 @@ let main = (~version as versionName) => { @@ -71,6 +71,18 @@ let main = (~version as versionName) => {
let versionName = Versions.format(versionName);
let%lwt versionName =
switch (versionName) {
| "latest-*" =>
switch%lwt (VersionListingLts.getLatest()) {
| Error(err) =>
raise(VersionListingLts.Problem_with_finding_latest_lts(err))
| Ok({VersionListingLts.lts, _}) =>
Printf.sprintf("latest-%s", lts) |> Lwt.return
}
| _ => Lwt.return(versionName)
};
Logger.debug(
<Pastel>
"Looking for node "
@ -115,7 +127,7 @@ let main = (~version as versionName) => { @@ -115,7 +127,7 @@ let main = (~version as versionName) => {
};
let run = (~version) =>
try%lwt (main(~version)) {
try%lwt(main(~version)) {
| Versions.No_Download_For_System(os, arch) =>
Logger.error(
<Pastel>
@ -137,4 +149,19 @@ let run = (~version) => @@ -137,4 +149,19 @@ let run = (~version) =>
</Pastel>,
);
exit(1);
| VersionListingLts.Problem_with_finding_latest_lts(
VersionListingLts.Cant_find_latest_lts,
) =>
Logger.error(<Pastel color=Pastel.Red> "Can't find latest LTS" </Pastel>);
exit(1);
| VersionListingLts.Problem_with_finding_latest_lts(
VersionListingLts.Cant_parse_remote_version_listing(reason),
) =>
Logger.error(
<Pastel color=Pastel.Red>
"Can't parse json of the response:\n"
reason
</Pastel>,
);
exit(1);
};

4
executable/ListLocal.re

@ -6,7 +6,7 @@ let main = () => @@ -6,7 +6,7 @@ let main = () =>
Versions.Local.(
{
let%lwt versions =
try%lwt (Versions.getInstalledVersions()) {
try%lwt(Versions.getInstalledVersions()) {
| _ => Lwt.fail(Cant_read_local_versions)
}
and currentVersion = Versions.getCurrentVersion();
@ -36,7 +36,7 @@ let main = () => @@ -36,7 +36,7 @@ let main = () =>
);
let run = () =>
try%lwt (main()) {
try%lwt(main()) {
| Cant_read_local_versions =>
Console.log("No versions installed!") |> Lwt.return
};

22
executable/Use.re

@ -19,12 +19,26 @@ let error = (~quiet, arg) => @@ -19,12 +19,26 @@ let error = (~quiet, arg) =>
Logger.error(arg);
};
let getVersion = version => {
let%lwt parsed = Versions.parse(version);
let%lwt resultWithLts =
switch (parsed) {
| Ok(x) => Lwt.return_ok(x)
| Error("latest-*") =>
switch%lwt (VersionListingLts.getLatest()) {
| Error(_) => Lwt.return_error(Version_Not_Installed(version))
| Ok({VersionListingLts.lts, _}) =>
Versions.Alias("latest-" ++ lts) |> Lwt.return_ok
}
| _ => Version_Not_Installed(version) |> Lwt.return_error
};
resultWithLts |> Result.fold(Lwt.fail, Lwt.return);
};
let switchVersion = (~version, ~quiet) => {
open Lwt.Infix;
let info = info(~quiet);
let debug = debug(~quiet);
let%lwt parsedVersion =
Versions.parse(version) >>= Opt.toLwt(Version_Not_Installed(version));
let%lwt parsedVersion = getVersion(version);
let%lwt versionPath =
switch (parsedVersion) {
@ -102,7 +116,7 @@ let rec askIfInstall = (~version, ~quiet, retry) => { @@ -102,7 +116,7 @@ let rec askIfInstall = (~version, ~quiet, retry) => {
};
let rec run = (~version, ~quiet) =>
try%lwt (main(~version, ~quiet)) {
try%lwt(main(~version, ~quiet)) {
| Version_Not_Installed(versionString) =>
error(
~quiet,

1
feature_tests/latest-lts/.nvmrc

@ -0,0 +1 @@ @@ -0,0 +1 @@
lts/*

10
feature_tests/latest-lts/run.sh

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
#!/bin/bash
set -e
eval "$(fnm env --multi)"
fnm install
fnm use
fnm ls | grep latest-

2
feature_tests/run.sh

@ -19,7 +19,7 @@ rm -rf $TEMP_DIR_BASE @@ -19,7 +19,7 @@ rm -rf $TEMP_DIR_BASE
mkdir $TEMP_DIR_BASE $TEMP_BINARY_PATH
cp $BINARY $TEMP_BINARY_PATH/fnm
for test_file in $DIRECTORY/*/run.sh; do
for test_file in $DIRECTORY/latest-lts/run.sh; do
rm -rf $TEMP_FNM_DIR
echo "Running test in $test_file"

2
library/Dotfiles.re

@ -2,7 +2,7 @@ exception Version_Not_Provided; @@ -2,7 +2,7 @@ exception Version_Not_Provided;
exception Conflicting_Dotfiles_Found(string, string);
let versionString = fileName => {
try%lwt (
try%lwt(
Lwt_io.lines_of_file(fileName)
|> Lwt_stream.to_list
|> Lwt.map(List.hd)

6
library/Fs.re

@ -15,7 +15,7 @@ let readdir = dir => { @@ -15,7 +15,7 @@ let readdir = dir => {
};
let%lwt items =
try%lwt (iterate()) {
try%lwt(iterate()) {
| End_of_file => Lwt.return(items^)
};
@ -33,13 +33,13 @@ let writeFile = (path, contents) => { @@ -33,13 +33,13 @@ let writeFile = (path, contents) => {
};
let exists = path => {
try%lwt (Lwt_unix.file_exists(path)) {
try%lwt(Lwt_unix.file_exists(path)) {
| Unix.Unix_error(_, _, _) => Lwt.return(false)
};
};
let readlink = path =>
try%lwt (Lwt_unix.readlink(path) |> Lwt.map(x => Ok(x))) {
try%lwt(Lwt_unix.readlink(path) |> Lwt.map(x => Ok(x))) {
| err => Lwt.return_error(err)
};

48
library/Path.re

@ -146,9 +146,9 @@ let lex = s => { @@ -146,9 +146,9 @@ let lex = s => {
prevEsc.contents = ch === '\\' && !prevEsc.contents;
};
let rev =
j.contents === len - 1 ?
revTokens.contents :
[
j.contents === len - 1
? revTokens.contents
: [
makeToken(String.sub(s, j.contents + 1, len - 1 - j.contents)),
...revTokens.contents,
];
@ -256,10 +256,14 @@ let relativeExn = s => @@ -256,10 +256,14 @@ let relativeExn = s =>
* Relates two positive integers to zero and eachother.
*/
type ord =
| /** 0 === i === j */ Zeros
| /** 0 === i < j */ ZeroPositive
| /** i > 0 === j */ PositiveZero
| /** 0 < i && 0 < j */ Positives;
| /** 0 === i === j */
Zeros
| /** 0 === i < j */
ZeroPositive
| /** i > 0 === j */
PositiveZero
| /** 0 < i && 0 < j */
Positives;
/**
* Using `ord` allows us to retain exhaustiveness pattern matching checks that
@ -268,8 +272,8 @@ type ord = @@ -268,8 +272,8 @@ type ord =
* it isn't inferred to be polymorphic.
*/
let ord = (i: int, j: int) =>
i === 0 && j === 0 ?
Zeros : i === 0 ? ZeroPositive : j === 0 ? PositiveZero : Positives;
i === 0 && j === 0
? Zeros : i === 0 ? ZeroPositive : j === 0 ? PositiveZero : Positives;
let rec repeat = (soFar, i, s) =>
i === 0 ? soFar : repeat(soFar ++ s, i - 1, s);
@ -334,14 +338,14 @@ let relativizeExn: type k. (~source: t(k), ~dest: t(k)) => t(relative) = @@ -334,14 +338,14 @@ let relativizeExn: type k. (~source: t(k), ~dest: t(k)) => t(relative) =
| (Some(_), None) => raiseDriveMismatch(source, dest)
| (None, Some(_)) => raiseDriveMismatch(source, dest)
| (Some(d1), Some(d2)) =>
String.compare(d1, d2) !== 0 ?
raiseDriveMismatch(source, dest) :
relativizeDepth((0, List.rev(s1)), (0, List.rev(s2)))
String.compare(d1, d2) !== 0
? raiseDriveMismatch(source, dest)
: relativizeDepth((0, List.rev(s1)), (0, List.rev(s2)))
}
| ((Rel(w1, r1), s1), (Rel(w2, r2), s2)) =>
w1 === w2 ?
relativizeDepth((r1, List.rev(s1)), (r2, List.rev(s2))) :
raiseDriveMismatch(source, dest)
w1 === w2
? relativizeDepth((r1, List.rev(s1)), (r2, List.rev(s2)))
: raiseDriveMismatch(source, dest)
};
(Rel(Any, depth), List.rev(segs));
};
@ -349,7 +353,7 @@ let relativizeExn: type k. (~source: t(k), ~dest: t(k)) => t(relative) = @@ -349,7 +353,7 @@ let relativizeExn: type k. (~source: t(k), ~dest: t(k)) => t(relative) =
let relativize:
type k. (~source: t(k), ~dest: t(k)) => result(t(relative), exn) =
(~source, ~dest) =>
try (Ok(relativizeExn(~source, ~dest))) {
try(Ok(relativizeExn(~source, ~dest))) {
| Invalid_argument(_) as e => Error(e)
};
@ -413,9 +417,9 @@ let rec join: type k1 k2. (t(k1), t(k2)) => t(k1) = @@ -413,9 +417,9 @@ let rec join: type k1 k2. (t(k1), t(k2)) => t(k1) =
switch (p1, p2) {
| ((Rel(w, r1), []), (Rel(Any, r2), s2)) => (Rel(w, r1 + r2), s2)
| ((Rel(w, r1), [s1hd, ...s1tl] as s1), (Rel(Any, r2), s2)) =>
r2 > 0 ?
join((Rel(w, r1), s1tl), (Rel(Any, r2 - 1), s2)) :
(Rel(w, r1), List.append(s2, s1))
r2 > 0
? join((Rel(w, r1), s1tl), (Rel(Any, r2 - 1), s2))
: (Rel(w, r1), List.append(s2, s1))
| ((b1, s1), (Rel(Home, r2), s2)) =>
join((b1, [homeChar, ...List.append(s2, s1)]), (Rel(Any, r2), s2))
| ((b1, s1), (Abs(Some(ll)), s2)) => (
@ -425,9 +429,9 @@ let rec join: type k1 k2. (t(k1), t(k2)) => t(k1) = @@ -425,9 +429,9 @@ let rec join: type k1 k2. (t(k1), t(k2)) => t(k1) =
| ((b1, s1), (Abs(None), s2)) => (b1, List.append(s2, s1))
| ((Abs(_) as d, []), (Rel(Any, r2), s2)) => (d, s2)
| ((Abs(_) as d, [s1hd, ...s1tl] as s1), (Rel(Any, r2), s2)) =>
r2 > 0 ?
join((d, s1tl), (Rel(Any, r2 - 1), s2)) :
(d, List.append(s2, s1))
r2 > 0
? join((d, s1tl), (Rel(Any, r2 - 1), s2))
: (d, List.append(s2, s1))
};
let dirName: type k1. t(k1) => t(k1) =

12
library/Result.re

@ -25,6 +25,18 @@ let bind = (fn, res) => @@ -25,6 +25,18 @@ let bind = (fn, res) =>
| Error(_) as e => e
};
let bind_err = (fn, res) =>
switch (res) {
| Ok(_) as o => o
| Error(x) => fn(x)
};
let bind_err_lwt = (fn, res) =>
switch (res) {
| Ok(o) => Lwt.return_ok(o)
| Error(x) => fn(x)
};
let fold = (error, ok, res) =>
switch (res) {
| Ok(x) => ok(x)

2
library/System.re

@ -70,7 +70,7 @@ module NodeArch = { @@ -70,7 +70,7 @@ module NodeArch = {
switch (Sys.os_type) {
| "Unix" =>
let%lwt result = unix_exec("uname", ~args=[|"-a"|]);
try (result |> findArches |> Lwt.return) {
try(result |> findArches |> Lwt.return) {
| _ => Lwt.fail_with("Error getting unix information")
};
| _ => Lwt.return(Other)

34
library/VersionListing.re

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
type item = {
version: string,
date: string,
files: list(string),
lts: option(string),
};
let item_of_yojson = (json: Yojson.Safe.t) => {
open Yojson.Safe.Util;
let version = json |> member("version") |> to_string;
let files = json |> member("files") |> to_list |> List.map(to_string);
let date = json |> member("date") |> to_string;
let lts =
Base.Option.try_with(() => {
json |> member("lts") |> to_string |> String.lowercase_ascii
});
Ok({version, date, files, lts});
};
[@deriving of_yojson({strict: false})]
type t = list(item);
let parseVersionListing = body => {
Base.Result.try_with(() => Yojson.Safe.from_string(body))
|> Base.Result.map_error(~f=Printexc.to_string)
|> Base.Result.bind(~f=x => of_yojson(x));
};
let fromHttp = () => {
let url =
Config.FNM_NODE_DIST_MIRROR.get() |> Printf.sprintf("%s/index.json");
let%lwt {Http.body, _} = Http.makeRequest(url);
parseVersionListing(body) |> Lwt.return;
};

29
library/VersionListingLts.re

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
type item = {
version: string,
lts: string,
};
let item_to_lts = (item: VersionListing.item) => {
item.lts |> Base.Option.map(~f=lts => {lts, version: item.version});
};
type get_latest_lts_errors =
| Cant_parse_remote_version_listing(string)
| Cant_find_latest_lts;
exception Problem_with_finding_latest_lts(get_latest_lts_errors);
let getLatest = () => {
let%lwt versions = VersionListing.fromHttp();
versions
|> Base.Result.map_error(~f=err => Cant_parse_remote_version_listing(err))
|> Base.Result.bind(~f=parsed => {
parsed
|> Base.List.filter_map(~f=item_to_lts)
|> Base.List.max_elt(~compare=(a, b) =>
Versions.compare(a.version, b.version)
)
|> Base.Result.of_option(~error=Cant_find_latest_lts)
})
|> Lwt.return;
};

21
library/Versions.re

@ -79,7 +79,7 @@ module Aliases = { @@ -79,7 +79,7 @@ module Aliases = {
let getAll = () => {
let%lwt aliases =
try%lwt (Fs.readdir(Directories.aliases)) {
try%lwt(Fs.readdir(Directories.aliases)) {
| _ => Lwt.return([])
};
aliases
@ -293,7 +293,7 @@ let getExactFileToDownload = (~version as versionName, ~os, ~arch) => { @@ -293,7 +293,7 @@ let getExactFileToDownload = (~version as versionName, ~os, ~arch) => {
Printf.sprintf("%s%s/", Config.FNM_NODE_DIST_MIRROR.get(), versionName);
let%lwt html =
try%lwt (Http.makeRequest(url) |> Lwt.map(Http.body)) {
try%lwt(Http.makeRequest(url) |> Lwt.map(Http.body)) {
| Http.Not_found(_) => Lwt.fail(Version_not_found(versionName))
};
@ -319,7 +319,7 @@ let getExactFileToDownload = (~version as versionName, ~os, ~arch) => { @@ -319,7 +319,7 @@ let getExactFileToDownload = (~version as versionName, ~os, ~arch) => {
};
let getFileToDownload = (~version, ~os, ~arch) =>
try%lwt (getExactFileToDownload(~version, ~os, ~arch)) {
try%lwt(getExactFileToDownload(~version, ~os, ~arch)) {
| Version_not_found(_) as e =>
switch%lwt (getRemoteLatestVersionByPrefix(version)) {
| None => Lwt.fail(e)
@ -337,7 +337,7 @@ let parse = version => { @@ -337,7 +337,7 @@ let parse = version => {
let formattedVersion = format(version);
if (formattedVersion == Local.systemVersion.name) {
Lwt.return_some(System);
Lwt.return_ok(System);
} else {
let%lwt aliasExists = Aliases.toDirectory(version) |> Fs.exists
and aliasExistsOnFormatted =
@ -352,19 +352,18 @@ let parse = version => { @@ -352,19 +352,18 @@ let parse = version => {
aliasExistsOnFormatted,
versionByPrefixPath,
) {
| (true, _, _, _) => Some(Local(formattedVersion)) |> Lwt.return
| (_, true, _, _) => Some(Alias(version)) |> Lwt.return
| (_, _, true, _) => Some(Alias(formattedVersion)) |> Lwt.return
| (_, false, false, Some(version)) =>
Some(Local(version)) |> Lwt.return
| (false, false, false, None) => Lwt.return_none
| (true, _, _, _) => Local(formattedVersion) |> Lwt.return_ok
| (_, true, _, _) => Alias(version) |> Lwt.return_ok
| (_, _, true, _) => Alias(formattedVersion) |> Lwt.return_ok
| (_, false, false, Some(version)) => Local(version) |> Lwt.return_ok
| (false, false, false, None) => Lwt.return_error(formattedVersion)
};
};
};
let isInstalled = versionName => {
let%lwt installedVersions =
try%lwt (getInstalledVersions()) {
try%lwt(getInstalledVersions()) {
| _ => Lwt.return([])
};
installedVersions

4
library/dune

@ -7,6 +7,6 @@ @@ -7,6 +7,6 @@
(name Fnm)
; Other libraries list this name in their package.json 'require' field to use this library.
(public_name fnm.lib)
(libraries pastel.lib str base lwt ssl lwt_ssl lambdasoup cohttp cohttp-lwt cohttp-lwt-unix console.lib )
(preprocess ( pps lwt_ppx ppx_let ppx_deriving.show ppx_deriving.eq ppx_deriving.make ppx_deriving.ord )) ; From package.json preprocess field
(libraries pastel.lib str base lwt ssl lwt_ssl lambdasoup cohttp cohttp-lwt cohttp-lwt-unix console.lib ppx_deriving_yojson.runtime )
(preprocess ( pps lwt_ppx ppx_let ppx_deriving.show ppx_deriving.eq ppx_deriving.make ppx_deriving.ord ppx_deriving_yojson )) ; From package.json preprocess field
)

6
package.json

@ -31,7 +31,8 @@ @@ -31,7 +31,8 @@
"ppx_deriving.show",
"ppx_deriving.eq",
"ppx_deriving.make",
"ppx_deriving.ord"
"ppx_deriving.ord",
"ppx_deriving_yojson"
],
"require": [
"pastel.lib",
@ -44,7 +45,8 @@ @@ -44,7 +45,8 @@
"cohttp",
"cohttp-lwt",
"cohttp-lwt-unix",
"console.lib"
"console.lib",
"ppx_deriving_yojson.runtime"
],
"name": "fnm.lib",
"namespace": "Fnm"

Loading…
Cancel
Save