diff --git a/.ci/create-static-binary.sh b/.ci/create-static-binary.sh index 27e934b..fc19e44 100755 --- a/.ci/create-static-binary.sh +++ b/.ci/create-static-binary.sh @@ -2,8 +2,8 @@ echo "Building binary in docker" -docker build . -t schlez/nsw-static-binary +docker build . -t schlez/fnm-static-binary -echo "Copying to ./nsw-linux" +echo "Copying to ./fnm-linux" -docker run --rm -v $(pwd):$(pwd) --workdir $(pwd) schlez/nsw-static-binary cp /app/_build/default/executable/NswApp.exe ./nsw-linux +docker run --rm -v $(pwd):$(pwd) --workdir $(pwd) schlez/fnm-static-binary cp /app/_build/default/executable/FnmApp.exe ./fnm-linux diff --git a/.ci/esy-build-steps.yml b/.ci/esy-build-steps.yml index 6f98189..81f754c 100644 --- a/.ci/esy-build-steps.yml +++ b/.ci/esy-build-steps.yml @@ -14,7 +14,7 @@ steps: displayName: 'esy build' - script: esy test displayName: 'esy test' - - script: esy x nsw.exe + - script: esy x fnm.exe displayName: 'Run the main binary' - script: esy ls-libs continueOnError: true diff --git a/.gitignore b/.gitignore index d4d1fb9..78396a0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,8 @@ node_modules/ _build _release _esy/ -nsw.install +fnm.install .DS_Store *.install .tmp +docs/screen_recording \ No newline at end of file diff --git a/README.md b/README.md index ded3026..0878650 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,64 @@

- Node Switcher (nsw) Build Status + Fast Node Manager (fnm) Build Status

-> A blazing fast and simple `nvm` replacement, built in native ReasonML. :rocket: +> :rocket: Fast and simple Node.js version manager, built in ReasonML
- Blazing fast! + Blazing fast!
## Features -- Single file, easy installation :sparkles: -- Fast fast fast fast :rocket: -- Install multiple node versions without a hassle! :clap: -- [Project-specific `.nvmrc` file support](./features_tests/nvmrc) +:sparkles: Single file, easy installation + +:rocket: Built with speed in mind + +:thinking: Works with `.nvmrc` files ## Installation -* Download the [latest release binary](https://github.com/Schniz/nsw/releases) for your system +* Download the [latest release binary](https://github.com/Schniz/fnm/releases) for your system * Make it available globally on `$PATH` * Add the following line to your `.bashrc`/`.zshrc` file: ```bash - eval `nsw env` + eval `fnm env` ``` -## TODO +## Future Plans +- [ ] Add a simpler way of installing it (`curl | bash`?) - [ ] Feature: make versions complete the latest: `10` would infer the latest minor and patch versions of node 10. `10.1` would infer the latest patch version of node 10.1 -- [ ] Feature: `nsw use --install`, `nsw use --quiet` -- [ ] Feature: `nsw install lts`? -- [ ] Feature: `nsw alias`? +- [ ] Feature: `fnm use --install`, `fnm use --quiet` +- [ ] Feature: `fnm install lts`? +- [ ] Feature: `fnm alias`? - [ ] Feature: Consider nvm-like per-shell usage with symlinks on `/tmp` directory - [ ] OSX: Add to homebrew? - [ ] Windows Support? - [ ] Linux: Replace `curl` usage with `cohttp`/`ocurl` or something else which is statically-linkable - [ ] Linux: Replace `tar` with a statically linked library too (for ungzip + untar) -## Developing: +## Contributing + +PRs welcome :tada: + +### Developing: ``` npm install -g esy -git clone https://github.com/Schniz/nsw.git +git clone https://github.com/Schniz/fnm.git esy install esy build ``` -## Running Binary: +### Running Binary: After building the project, you can run the main binary that is produced. ``` -esy x nsw.exe +esy x fnm.exe ``` -## Running Tests: +### Running Tests: ``` # Runs some smoke-unity test diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5b0aee1..81e855b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,15 +18,15 @@ jobs: # TODO: Uncomment both this and 'publish-build-cache' below to enable build caching for Linux. # - template: .ci/restore-build-cache.yml - script: .ci/create-static-binary.sh - - script: ./feature_tests/run.sh $(pwd)/nsw-linux + - script: ./feature_tests/run.sh $(pwd)/fnm-linux # - script: bash .ci/prepare-static-build.sh # - template: .ci/esy-build-steps.yml # - template: .ci/publish-build-cache.yml - task: PublishBuildArtifacts@1 displayName: 'Save artifact' inputs: - PathtoPublish: 'nsw-linux' - ArtifactName: nsw-linux + PathtoPublish: 'fnm-linux' + ArtifactName: fnm-linux - job: MacOS timeoutInMinutes: 0 @@ -41,14 +41,14 @@ jobs: # TODO: Uncomment both this and 'publish-build-cache' below to enable build caching for Mac. # - template: .ci/restore-build-cache.yml - template: .ci/esy-build-steps.yml - - script: cp _build/default/executable/NswApp.exe _build/nsw - - script: ./feature_tests/run.sh $(pwd)/_build/nsw + - script: cp _build/default/executable/FnmApp.exe _build/fnm + - script: ./feature_tests/run.sh $(pwd)/_build/fnm # - template: .ci/publish-build-cache.yml - task: PublishBuildArtifacts@1 displayName: 'Save artifact' inputs: - PathtoPublish: '_build/nsw' - ArtifactName: nsw-macos + PathtoPublish: '_build/fnm' + ArtifactName: fnm-macos # - job: Windows # timeoutInMinutes: 0 diff --git a/docs/fnm.svg b/docs/fnm.svg new file mode 100644 index 0000000..6114e75 --- /dev/null +++ b/docs/fnm.svg @@ -0,0 +1 @@ +evaleval`fnmenv`ffnfnmfnm--version1.0.0catcat.nvmrc10.9.0fnminstallLookingfornodev10.9.0fordarwinx64Downloadinghttps://nodejs.org/dist/v10.9.0/node-v10.9.0-darwin-x64.tar.gzto~/.fnm/downloads/v10.9.0.tar.gzExtracting~/.fnm/downloads/v10.9.0.tar.gzto~/.fnm/node-versions/v10.9.0fnmuseLinking~/.fnm/currentto~/.fnm/node-versions/v10.9.0/installationUsingv10.9.0nodenode-vv10.9.0eevevaeval`eval`feval`fneval`fnmeval`fnmeeval`fnmeneval`fnmenvfnm-fnm--fnm--vfnm--vefnm--verfnm--versifnm--versioccacat.ncat.nvcat.nvmcat.nvmrfnmifnminfnminsfnminstfnminstafnminstalfnmufnmusnnonodnode- \ No newline at end of file diff --git a/docs/nsw.gif b/docs/nsw.gif deleted file mode 100644 index 885b441..0000000 Binary files a/docs/nsw.gif and /dev/null differ diff --git a/docs/record_screen.sh b/docs/record_screen.sh new file mode 100755 index 0000000..aa61a61 --- /dev/null +++ b/docs/record_screen.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +DIRECTORY=`dirname $0` + +function setup_binary() { + export TEMP_DIR=$(mktemp -d -t fnm) + cp _build/default/executable/FnmApp.exe $TEMP_DIR/fnm + export PATH=$TEMP_DIR:$PATH + export FNM_DIR=$TEMP_DIR/.fnm +} + +setup_binary + +RECORDING_PATH=$DIRECTORY/screen_recording + +(rm -rf $RECORDING_PATH &> /dev/null || true) + +asciinema rec -c $DIRECTORY/recorded_screen_script.sh $RECORDING_PATH +cat $RECORDING_PATH | sed "s@$TEMP_DIR@~@g" | svg-term --window --out $DIRECTORY/fnm.svg --height=17 --width=70 \ No newline at end of file diff --git a/docs/recorded_screen_script.sh b/docs/recorded_screen_script.sh new file mode 100755 index 0000000..2a5cf63 --- /dev/null +++ b/docs/recorded_screen_script.sh @@ -0,0 +1,33 @@ +#!/bin/zsh + +set -e + +GAL_PROMPT_PREFIX='\e[34m✡ \e[0m' + +function type() { + printf $GAL_PROMPT_PREFIX + echo $* | pv -qL $[10+(-2 + RANDOM%5)] +} + +cd ./feature_tests/nvmrc + +type 'eval `fnm env`' +eval `fnm env` + +type 'fnm --version' +fnm --version + +type 'cat .nvmrc' +cat .nvmrc + +type 'fnm install' +fnm install + +type 'fnm use' +fnm use + +type 'node -v' +node -v + +sleep 2 +echo "" \ No newline at end of file diff --git a/dune-project b/dune-project index 50749c7..28bf472 100644 --- a/dune-project +++ b/dune-project @@ -1,2 +1,2 @@ (lang dune 1.6) - (name nsw) \ No newline at end of file + (name fnm) diff --git a/esy.lock/index.json b/esy.lock/index.json index fa96723..d326f59 100644 --- a/esy.lock/index.json +++ b/esy.lock/index.json @@ -1,6 +1,6 @@ { "checksum": "bc7707f147bdaf3b3f87430bb4b3f0cd", - "root": "nsw@link:./package.json", + "root": "fnm@link:./package.json", "node": { "refmterr@3.1.10@d41d8cd9": { "id": "refmterr@3.1.10@d41d8cd9", @@ -47,9 +47,9 @@ "dependencies": [], "devDependencies": [] }, - "nsw@link:./package.json": { - "id": "nsw@link:./package.json", - "name": "nsw", + "fnm@link:./package.json": { + "id": "fnm@link:./package.json", + "name": "fnm", "version": "link:./package.json", "source": { "type": "link", "path": ".", "manifest": "package.json" }, "overrides": [], diff --git a/executable/Env.re b/executable/Env.re index 0571385..4446e0a 100644 --- a/executable/Env.re +++ b/executable/Env.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let run = () => { Console.log( diff --git a/executable/NswApp.re b/executable/FnmApp.re similarity index 85% rename from executable/NswApp.re rename to executable/FnmApp.re index b883bf5..64c925a 100644 --- a/executable/NswApp.re +++ b/executable/FnmApp.re @@ -12,12 +12,22 @@ open Cmdliner; let help_secs = [ `S(Manpage.s_common_options), + `S(Manpage.s_environment), `P("These options are common to all commands."), `S("MORE HELP"), `P("Use `$(mname) $(i,COMMAND) --help' for help on a single command."), `Noblank, `S(Manpage.s_bugs), - `P("File bug reports at https://github.com/Schniz/nsw"), + `P("File bug reports at https://github.com/Schniz/fnm"), +]; + +let envs = [ + Term.env_info( + ~doc= + "The root directory of fnm installations. Defaults to: " + ++ Fnm.Directories.sfwRoot, + "FNM_DIR", + ), ]; let install = { @@ -90,10 +100,18 @@ let defaultCmd = { let man = help_secs; ( Term.(ret(const(_ => `Help((`Pager, None))) $ const())), - Term.info("nsw", ~version, ~doc, ~exits=Term.default_exits, ~man, ~sdocs), + Term.info( + "fnm", + ~envs, + ~version, + ~doc, + ~exits=Term.default_exits, + ~man, + ~sdocs, + ), ); }; let _ = Term.eval_choice(defaultCmd, [install, use, listLocal, listRemote, env]) - |> Term.exit; + |> Term.exit; \ No newline at end of file diff --git a/executable/Install.re b/executable/Install.re index c5a090a..1ab2f0c 100644 --- a/executable/Install.re +++ b/executable/Install.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let mkDownloadsDir = () => { let exists = Lwt_unix.file_exists(Directories.downloads); @@ -98,4 +98,4 @@ let run = (~version) => , ) |> Lwt.return - }; \ No newline at end of file + }; diff --git a/executable/ListInstallations.re b/executable/ListInstallations.re index 15558f9..98a1543 100644 --- a/executable/ListInstallations.re +++ b/executable/ListInstallations.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let colorizeVersions = (~current, ~versions) => { let strings = diff --git a/executable/ListLocal.re b/executable/ListLocal.re index 1d95c10..5647cd9 100644 --- a/executable/ListLocal.re +++ b/executable/ListLocal.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let run = () => Versions.Local.( diff --git a/executable/ListRemote.re b/executable/ListRemote.re index 4b013c6..0fdd11e 100644 --- a/executable/ListRemote.re +++ b/executable/ListRemote.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let run = () => { Console.log("Looking for some node versions upstream..."); diff --git a/executable/Use.re b/executable/Use.re index df11b2e..3b34647 100644 --- a/executable/Use.re +++ b/executable/Use.re @@ -1,4 +1,4 @@ -open Nsw; +open Fnm; let lwtIgnore = lwt => Lwt.catch(() => lwt, _ => Lwt.return()); diff --git a/executable/dune b/executable/dune index a4234b3..7a4ff02 100644 --- a/executable/dune +++ b/executable/dune @@ -1,12 +1,12 @@ ; !!!! This dune file is generated from the package.json file by pesy. If you modify it by hand ; !!!! your changes will be undone! Instead, edit the package.json and then rerun 'esy pesy' at the project root. -; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p nsw +; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p fnm (executable ; The entrypoint module - (name NswApp) ; From package.json main field - ; The name of the executable (runnable via esy x nsw.exe) - (public_name nsw.exe) ; From package.json name field - (libraries core cmdliner lwt lwt.unix lambdasoup console.lib pastel.lib nsw.lib ) ; From package.json require field (array of strings) + (name FnmApp) ; From package.json main field + ; The name of the executable (runnable via esy x fnm.exe) + (public_name fnm.exe) ; From package.json name field + (libraries core cmdliner lwt lwt.unix lambdasoup console.lib pastel.lib fnm.lib ) ; From package.json require field (array of strings) (preprocess ( pps lwt_ppx ppx_let )) ; From package.json preprocess field ) \ No newline at end of file diff --git a/feature_tests/basic/run.sh b/feature_tests/basic/run.sh index 95b34e9..f21db10 100644 --- a/feature_tests/basic/run.sh +++ b/feature_tests/basic/run.sh @@ -1,8 +1,10 @@ -eval $(nsw env) -nsw install v8.11.3 -nsw use v8.11.3 +#!/bin/bash + +eval $(fnm env) +fnm install v8.11.3 +fnm use v8.11.3 if [ "$(node --version)" != "v8.11.3" ]; then echo "Node version is not v8.11.3!" exit 1 -fi \ No newline at end of file +fi diff --git a/feature_tests/nvmrc/.nvmrc b/feature_tests/nvmrc/.nvmrc index e3cbcda..fe6d2ac 100644 --- a/feature_tests/nvmrc/.nvmrc +++ b/feature_tests/nvmrc/.nvmrc @@ -1 +1 @@ -10.9.0 \ No newline at end of file +10.9.0 diff --git a/feature_tests/nvmrc/run.sh b/feature_tests/nvmrc/run.sh index 206a8ad..4940e73 100644 --- a/feature_tests/nvmrc/run.sh +++ b/feature_tests/nvmrc/run.sh @@ -1,10 +1,10 @@ #!/bin/bash -eval $(nsw env) -nsw install -nsw use +eval $(fnm env) +fnm install +fnm use if [ "$(node --version)" != "v10.9.0" ]; then echo "Node version is not v10.9.0!" exit 1 -fi \ No newline at end of file +fi diff --git a/feature_tests/run.sh b/feature_tests/run.sh index 683f522..8ecdcb4 100755 --- a/feature_tests/run.sh +++ b/feature_tests/run.sh @@ -6,27 +6,27 @@ DIRECTORY=`dirname $0` BINARY=$1 TEMP_DIR_BASE=$(pwd)/$DIRECTORY/.tmp TEMP_BINARY_PATH=$TEMP_DIR_BASE/bin -TEMP_NSW_DIR=$TEMP_DIR_BASE/.nsw +TEMP_FNM_DIR=$TEMP_DIR_BASE/.fnm if [ "$BINARY" == "" ]; then echo "No binary supplied!" exit 1 fi -echo "using nvm=$BINARY" +echo "using fnm=$BINARY" rm -rf $TEMP_DIR_BASE mkdir $TEMP_DIR_BASE $TEMP_BINARY_PATH -cp $BINARY $TEMP_BINARY_PATH/nsw +cp $BINARY $TEMP_BINARY_PATH/fnm for test_file in $DIRECTORY/*/run.sh; do - rm -rf $TEMP_NSW_DIR + rm -rf $TEMP_FNM_DIR echo "Running test in $test_file" echo "Running test in $test_file" | sed "s/./-/g" - (cd $(dirname $test_file) && NSW_DIR=$TEMP_NSW_DIR PATH=$TEMP_BINARY_PATH:$PATH bash $(basename $test_file)) + (cd $(dirname $test_file) && FNM_DIR=$TEMP_FNM_DIR PATH=$TEMP_BINARY_PATH:$PATH bash $(basename $test_file)) echo "" echo " -> Finished!" - rm -rf $TEMP_NSW_DIR + rm -rf $TEMP_FNM_DIR done diff --git a/nsw.opam b/fnm.opam similarity index 100% rename from nsw.opam rename to fnm.opam diff --git a/library/Directories.re b/library/Directories.re index 179a695..f0d4803 100644 --- a/library/Directories.re +++ b/library/Directories.re @@ -1,13 +1,13 @@ let sfwRoot = Opt.( - Sys.getenv_opt("NSW_DIR") + Sys.getenv_opt("FNM_DIR") or { let home = Sys.getenv_opt("HOME") |> Opt.orThrow("There isn't $HOME environment variable set."); - Filename.concat(home, ".nsw"); + Filename.concat(home, ".fnm"); } ); let nodeVersions = Filename.concat(sfwRoot, "node-versions"); let currentVersion = Filename.concat(sfwRoot, "current"); -let downloads = Filename.concat(sfwRoot, "downloads"); \ No newline at end of file +let downloads = Filename.concat(sfwRoot, "downloads"); diff --git a/library/dune b/library/dune index ac7c1d6..665e213 100644 --- a/library/dune +++ b/library/dune @@ -1,12 +1,12 @@ ; !!!! This dune file is generated from the package.json file by pesy. If you modify it by hand ; !!!! your changes will be undone! Instead, edit the package.json and then rerun 'esy pesy' at the project root. -; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p nsw +; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p fnm (library ; The namespace that other packages/libraries will access this library through - (name Nsw) + (name Fnm) ; Other libraries list this name in their package.json 'require' field to use this library. - (public_name nsw.lib) + (public_name fnm.lib) (libraries str core lwt lwt.unix lambdasoup semver ) (preprocess ( pps lwt_ppx ppx_let )) ; From package.json preprocess field ) \ No newline at end of file diff --git a/package.json b/package.json index a4c814f..40dc69e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "nsw", + "name": "fnm", "version": "0.0.0", "description": "My Project", "esy": { @@ -7,33 +7,33 @@ "buildsInSource": "_build", "release": { "releasedBinaries": [ - "nsw.exe" + "fnm.exe" ] } }, "buildDirs": { "test": { - "require": ["nsw.lib", "rely.lib"], - "main": "TestNsw", - "name": "TestNsw.exe", + "require": ["fnm.lib", "rely.lib"], + "main": "TestFnm", + "name": "TestFnm.exe", "ocamloptFlags": ["-linkall", "-g"] }, "library": { "preprocess": ["pps", "lwt_ppx", "ppx_let"], "require": ["str", "core", "lwt", "lwt.unix", "lambdasoup", "semver"], - "name": "nsw.lib", - "namespace": "Nsw" + "name": "fnm.lib", + "namespace": "Fnm" }, "executable": { "preprocess": ["pps", "lwt_ppx", "ppx_let"], - "require": ["core", "cmdliner", "lwt", "lwt.unix", "lambdasoup", "console.lib", "pastel.lib", "nsw.lib"], - "main": "NswApp", - "name": "nsw.exe" + "require": ["core", "cmdliner", "lwt", "lwt.unix", "lambdasoup", "console.lib", "pastel.lib", "fnm.lib"], + "main": "FnmApp", + "name": "fnm.exe" } }, "scripts": { "pesy": "bash -c 'env PESY_MODE=update pesy'", - "test": "esy x TestNsw.exe", + "test": "esy x TestFnm.exe", "fmt": "bash -c 'refmt --in-place {library,executable,test}/*.re'" }, "dependencies": { diff --git a/test/TestNsw.re b/test/TestFnm.re similarity index 100% rename from test/TestNsw.re rename to test/TestFnm.re diff --git a/test/TestFramework.re b/test/TestFramework.re index d72f7f5..400fd07 100644 --- a/test/TestFramework.re +++ b/test/TestFramework.re @@ -1,5 +1,5 @@ let projectDir = Sys.getcwd(); -let tmpDir = Filename.concat(projectDir, ".nswTmp"); +let tmpDir = Filename.concat(projectDir, ".fnmTmp"); include Rely.Make({ let config = @@ -15,8 +15,8 @@ include Rely.Make({ let run = args => { let arguments = - args |> Array.append([|"./_build/default/executable/NswApp.exe"|]); - let env = Unix.environment() |> Array.append([|"NSW_DIR=" ++ tmpDir|]); + args |> Array.append([|"./_build/default/executable/FnmApp.exe"|]); + let env = Unix.environment() |> Array.append([|"FNM_DIR=" ++ tmpDir|]); let result = Lwt_process.pread_chars(~env, ("", arguments)) |> Lwt_stream.to_string; Lwt_main.run(result); @@ -28,4 +28,4 @@ let clearTmpDir = () => { }; let redactSfwRoot = - Str.global_replace(Str.regexp_string(tmpDir), ""); \ No newline at end of file + Str.global_replace(Str.regexp_string(tmpDir), ""); diff --git a/test/dune b/test/dune index 331f7cf..dbab342 100644 --- a/test/dune +++ b/test/dune @@ -1,12 +1,12 @@ ; !!!! This dune file is generated from the package.json file by pesy. If you modify it by hand ; !!!! your changes will be undone! Instead, edit the package.json and then rerun 'esy pesy' at the project root. -; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p nsw +; !!!! If you want to stop using pesy and manage this file by hand, change pacakge.json's 'esy.build' command to: refmterr dune build -p fnm (executable ; The entrypoint module - (name TestNsw) ; From package.json main field - ; The name of the executable (runnable via esy x TestNsw.exe) - (public_name TestNsw.exe) ; From package.json name field - (libraries nsw.lib rely.lib ) ; From package.json require field (array of strings) + (name TestFnm) ; From package.json main field + ; The name of the executable (runnable via esy x TestFnm.exe) + (public_name TestFnm.exe) ; From package.json name field + (libraries fnm.lib rely.lib ) ; From package.json require field (array of strings) (ocamlopt_flags ( -linkall -g )) ; From package.json ocamloptFlags field ) \ No newline at end of file