Browse Source

Merge branch 'master' into list-filter

remotes/origin/list-filter
Gal Schlezinger 1 year ago committed by GitHub
parent
commit
d587f61407
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/poor-otters-cheer.md
  2. 5
      .changeset/poor-poets-compete.md
  3. 5
      .changeset/show-download-progress.md
  4. 8
      .ci/install.sh
  5. 6
      .ci/record_screen.sh
  6. 151
      .github/workflows/rust.yml
  7. 81
      Cargo.lock
  8. 2
      Cargo.toml
  9. 29
      README.md
  10. 58
      docs/commands.md
  11. 72
      docs/configuration.md
  12. 3
      rust-toolchain.toml
  13. 7
      src/arch.rs
  14. 4
      src/archive/mod.rs
  15. 2
      src/commands/env.rs
  16. 16
      src/commands/install.rs
  17. 2
      src/commands/use.rs
  18. 4
      src/config.rs
  19. 21
      src/downloader.rs
  20. 1
      src/main.rs
  21. 165
      src/progress.rs
  22. 6
      src/shell/bash.rs
  23. 6
      src/shell/fish.rs
  24. 2
      src/shell/infer/mod.rs
  25. 6
      src/shell/powershell.rs
  26. 6
      src/shell/zsh.rs

5
.changeset/poor-otters-cheer.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": patch
---
support `x64-musl` arch by adding a `--arch x64-musl` to fnm env

5
.changeset/poor-poets-compete.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": patch
---
make nicer styling in progress bar (add newline, make it unicode)

5
.changeset/show-download-progress.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": minor
---
Show a progress bar when downloading and extracting node

8
.ci/install.sh

@ -5,6 +5,10 @@ set -e @@ -5,6 +5,10 @@ set -e
RELEASE="latest"
OS="$(uname -s)"
case "${OS}" in
MINGW* | Win*) OS="Windows" ;;
esac
if [ -d "$HOME/.fnm" ]; then
INSTALL_DIR="$HOME/.fnm"
elif [ -n "$XDG_DATA_HOME" ]; then
@ -70,6 +74,9 @@ set_filename() { @@ -70,6 +74,9 @@ set_filename() {
elif [ "$OS" = "Darwin" ]; then
USE_HOMEBREW="true"
echo "Downloading fnm using Homebrew..."
elif [ "$OS" = "Windows" ] ; then
FILENAME="fnm-windows"
echo "Downloading the latest fnm binary from GitHub..."
else
echo "OS $OS is not supported."
echo "If you think that's a bug - please file an issue to https://github.com/Schniz/fnm/issues"
@ -180,6 +187,7 @@ setup_shell() { @@ -180,6 +187,7 @@ setup_shell() {
echo ' set PATH "'"$INSTALL_DIR"'" $PATH'
echo ' fnm env | source'
echo '' >>$CONF_FILE
echo '# fnm' >>$CONF_FILE
echo 'set PATH "'"$INSTALL_DIR"'" $PATH' >>$CONF_FILE
echo 'fnm env | source' >>$CONF_FILE

6
.ci/record_screen.sh

@ -20,7 +20,11 @@ RECORDING_PATH=$DIRECTORY/screen_recording @@ -20,7 +20,11 @@ RECORDING_PATH=$DIRECTORY/screen_recording
(rm -rf "$RECORDING_PATH" &> /dev/null || true)
asciinema rec -c "$DIRECTORY/recorded_screen_script.sh" "$RECORDING_PATH"
asciinema rec \
--command "$DIRECTORY/recorded_screen_script.sh" \
--cols 70 \
--rows 17 \
"$RECORDING_PATH"
sed "s@$TEMP_DIR@~@g" "$RECORDING_PATH" | \
svg-term \
--window \

151
.github/workflows/rust.yml

@ -10,13 +10,16 @@ concurrency: @@ -10,13 +10,16 @@ concurrency:
group: ci-${{ github.head_ref }}
cancel-in-progress: true
env:
RUST_VERSION: "1.78"
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: cargo fmt
@ -27,7 +30,7 @@ jobs: @@ -27,7 +30,7 @@ jobs:
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: cargo clippy
@ -41,7 +44,7 @@ jobs: @@ -41,7 +44,7 @@ jobs:
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: Run tests
@ -53,7 +56,7 @@ jobs: @@ -53,7 +56,7 @@ jobs:
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: Build release binary
@ -71,7 +74,7 @@ jobs: @@ -71,7 +74,7 @@ jobs:
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: Build release binary
@ -237,7 +240,7 @@ jobs: @@ -237,7 +240,7 @@ jobs:
steps:
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
targets: x86_64-unknown-linux-musl
- uses: Swatinem/rust-cache@v2
with:
@ -278,7 +281,7 @@ jobs: @@ -278,7 +281,7 @@ jobs:
uses: docker/setup-qemu-action@v2
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
rust-version: ${{env.RUST_VERSION}}
- uses: Swatinem/rust-cache@v2
with:
key: arm-binary-${{ matrix.arch }}
@ -358,70 +361,70 @@ jobs: @@ -358,70 +361,70 @@ jobs:
run: |
pnpm run generate-command-docs --check --binary-path=$(which fnm)
run_e2e_benchmarks:
runs-on: ubuntu-latest
name: bench/linux
needs: [build_static_linux_binary]
permissions:
contents: write
pull-requests: write
steps:
- name: install necessary shells
run: sudo apt-get update && sudo apt-get install -y fish zsh bash hyperfine
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: fnm-linux
path: target/release
- name: mark binary as executable
run: chmod +x target/release/fnm
- name: install fnm as binary
run: |
sudo install target/release/fnm /bin
fnm --version
- uses: pnpm/action-setup@v2.2.4
with:
run_install: false
- uses: actions/setup-node@v3
with:
node-version: 18.x
cache: "pnpm"
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install
- name: Run benchmarks
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SHOULD_STORE: ${{ toJson(!github.event.pull_request) }}
id: benchmark
run: |
delimiter="$(openssl rand -hex 8)"
echo "markdown<<${delimiter}" >> "${GITHUB_OUTPUT}"
node benchmarks/run.mjs --store=$SHOULD_STORE >> "${GITHUB_OUTPUT}"
echo "${delimiter}" >> "${GITHUB_OUTPUT}"
- name: Create a PR comment
if: ${{ github.event.pull_request }}
uses: thollander/actions-comment-pull-request@v2
with:
message: |
## Linux Benchmarks for ${{ github.event.pull_request.head.sha }}
${{ steps.benchmark.outputs.markdown }}
comment_tag: "benchy comment"
- name: Create a commit comment
if: ${{ !github.event.pull_request }}
uses: peter-evans/commit-comment@v2
with:
body: |
## Linux Benchmarks
${{ steps.benchmark.outputs.markdown }}
# TODO: use bnz
# run_e2e_benchmarks:
# runs-on: ubuntu-latest
# name: bench/linux
# needs: [build_static_linux_binary]
# permissions:
# contents: write
# pull-requests: write
# steps:
# - name: install necessary shells
# run: sudo apt-get update && sudo apt-get install -y fish zsh bash hyperfine
# - uses: actions/checkout@v3
# - uses: actions/download-artifact@v3
# with:
# name: fnm-linux
# path: target/release
# - name: mark binary as executable
# run: chmod +x target/release/fnm
# - name: install fnm as binary
# run: |
# sudo install target/release/fnm /bin
# fnm --version
# - uses: pnpm/action-setup@v2.2.4
# with:
# run_install: false
# - uses: actions/setup-node@v3
# with:
# node-version: 18.x
# cache: "pnpm"
# - name: Get pnpm store directory
# id: pnpm-cache
# run: |
# echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
# - uses: actions/cache@v3
# name: Setup pnpm cache
# with:
# path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
# key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
# restore-keys: |
# ${{ runner.os }}-pnpm-store-
# - run: pnpm install
# - name: Run benchmarks
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# SHOULD_STORE: ${{ toJson(!github.event.pull_request) }}
# id: benchmark
# run: |
# delimiter="$(openssl rand -hex 8)"
# echo "markdown<<${delimiter}" >> "${GITHUB_OUTPUT}"
# node benchmarks/run.mjs --store=$SHOULD_STORE >> "${GITHUB_OUTPUT}"
# echo "${delimiter}" >> "${GITHUB_OUTPUT}"
# - name: Create a PR comment
# if: ${{ github.event.pull_request }}
# uses: thollander/actions-comment-pull-request@v2
# with:
# message: |
# ## Linux Benchmarks for ${{ github.event.pull_request.head.sha }}
# ${{ steps.benchmark.outputs.markdown }}
# comment_tag: "benchy comment"
#
# - name: Create a commit comment
# if: ${{ !github.event.pull_request }}
# uses: peter-evans/commit-comment@v2
# with:
# body: |
# ## Linux Benchmarks
# ${{ steps.benchmark.outputs.markdown }}

81
Cargo.lock generated

@ -357,6 +357,19 @@ dependencies = [ @@ -357,6 +357,19 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "console"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys 0.45.0",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@ -540,6 +553,12 @@ dependencies = [ @@ -540,6 +553,12 @@ dependencies = [
"winreg",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "encoding_rs"
version = "0.8.32"
@ -638,6 +657,8 @@ dependencies = [ @@ -638,6 +657,8 @@ dependencies = [
"embed-resource",
"encoding_rs_io",
"env_logger",
"http",
"indicatif",
"indoc",
"junction",
"log",
@ -912,6 +933,20 @@ dependencies = [ @@ -912,6 +933,20 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "indicatif"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
dependencies = [
"console",
"instant",
"number_prefix",
"portable-atomic",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "indoc"
version = "2.0.2"
@ -1164,6 +1199,12 @@ dependencies = [ @@ -1164,6 +1199,12 @@ dependencies = [
"libc",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "object"
version = "0.30.4"
@ -1248,6 +1289,12 @@ version = "0.3.27" @@ -1248,6 +1289,12 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "portable-atomic"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e"
[[package]]
name = "pretty_assertions"
version = "1.4.0"
@ -1904,6 +1951,12 @@ dependencies = [ @@ -1904,6 +1951,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-width"
version = "0.1.10"
@ -2112,7 +2165,7 @@ version = "0.48.0" @@ -2112,7 +2165,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
@ -2130,13 +2183,37 @@ dependencies = [ @@ -2130,13 +2183,37 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]

2
Cargo.toml

@ -30,11 +30,13 @@ sysinfo = "0.29.3" @@ -30,11 +30,13 @@ sysinfo = "0.29.3"
thiserror = "1.0.44"
clap_complete = "4.3.1"
anyhow = "1.0.71"
indicatif = { version = "0.17.8", features = ["improved_unicode"] }
[dev-dependencies]
pretty_assertions = "1.4.0"
duct = "0.13.6"
test-log = "0.2.12"
http = "0.2.9"
[build-dependencies]
embed-resource = "1.8.0"

29
README.md

@ -121,7 +121,7 @@ Where `<SHELL>` can be one of the supported shells: @@ -121,7 +121,7 @@ Where `<SHELL>` can be one of the supported shells:
- `bash`
- `zsh`
- `fish`
- `powershell`
- `power-shell`
Please follow your shell instructions to install them.
@ -129,7 +129,10 @@ Please follow your shell instructions to install them. @@ -129,7 +129,10 @@ Please follow your shell instructions to install them.
Environment variables need to be setup before you can start using fnm.
This is done by evaluating the output of `fnm env`.
To automatically run `fnm use` when a directory contains a `.node-version` or `.nvmrc` file, add the `--use-on-cd` option to your shell setup.
> [!NOTE]
> Check out the [Configuration](./docs/configuration.md) section to enable highly
> recommended features, like automatic version switching.
Adding a `.node-version` to your project is as simple as:
@ -174,20 +177,24 @@ fnm env --use-on-cd | Out-String | Invoke-Expression @@ -174,20 +177,24 @@ fnm env --use-on-cd | Out-String | Invoke-Expression
```
- For macOS/Linux, the profile is located at `~/.config/powershell/Microsoft.PowerShell_profile.ps1`
- On Windows, PowerShell comes pre-installed, but there are two versions of it. [Read more about it here](https://learn.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell). The profile is located at different places depending on which version you're using:
- Built in PowerShell (aka "Windows PowerShell"): `~\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`
- The newer, PowerShell >= 7, that's not built in: `~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1`
- On Windows to edit your profile you can run this in a PowerShell
```powershell
notepad $profile
```
#### Windows Command Prompt aka Batch aka WinCMD
fnm is also supported but is not entirely covered. [You can set up a startup script](https://superuser.com/a/144348) and append the following line:
fnm is also supported but is not entirely covered. [You can set up a startup script](https://superuser.com/a/144348) and append the following lines:
```batch
FOR /f "tokens=*" %i IN ('fnm env --use-on-cd') DO CALL %i
@echo off
:: for /F will launch a new instance of cmd so we create a guard to prevent an infnite loop
if not defined FNM_AUTORUN_GUARD (
set "FNM_AUTORUN_GUARD=AutorunGuard"
FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
)
```
If you get the error `i was unexpected at this time`, please make a .cmd file as suggested by the first step in the Usage with Cmder secton add it's path to the `AutoRun` registry key.
#### Usage with Cmder
Usage is very similar to the normal WinCMD install, apart for a few tweaks to allow being called from the cmder startup script. The example **assumes** that the `CMDER_ROOT` environment variable is **set** to the **root directory** of your Cmder installation.
@ -210,6 +217,10 @@ call "%CMDER_ROOT%\bin\fnm_init.cmd" @@ -210,6 +217,10 @@ call "%CMDER_ROOT%\bin\fnm_init.cmd"
You can replace `%CMDER_ROOT%` with any other convenient path too.
## [Configuration](./docs/configuration.md)
[See the available configuration options for an extended configuration documentation](./docs/configuration.md)
## [Usage](./docs/commands.md)
[See the available commands for an extended usage documentation](./docs/commands.md)

58
docs/commands.md

@ -22,7 +22,7 @@ Commands: @@ -22,7 +22,7 @@ Commands:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -55,7 +55,7 @@ Options: @@ -55,7 +55,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -82,7 +82,7 @@ Usage: fnm list-remote [OPTIONS] @@ -82,7 +82,7 @@ Usage: fnm list-remote [OPTIONS]
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -115,7 +115,7 @@ Options: @@ -115,7 +115,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -139,7 +139,7 @@ Usage: fnm list [OPTIONS] @@ -139,7 +139,7 @@ Usage: fnm list [OPTIONS]
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -172,7 +172,7 @@ Options: @@ -172,7 +172,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -203,7 +203,7 @@ Options: @@ -203,7 +203,7 @@ Options:
Install latest LTS
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -216,6 +216,12 @@ Options: @@ -216,6 +216,12 @@ Options:
--latest
Install latest version
--progress <PROGRESS>
Show an interactive progress bar for the download status
[default: auto]
[possible values: auto, never, always]
--log-level <LOG_LEVEL>
The log level of fnm commands
@ -239,7 +245,7 @@ Options: @@ -239,7 +245,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -270,7 +276,7 @@ Options: @@ -270,7 +276,7 @@ Options:
Install the version if it isn't installed yet
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -306,7 +312,7 @@ Options: @@ -306,7 +312,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -334,7 +340,7 @@ Usage: fnm env [OPTIONS] @@ -334,7 +340,7 @@ Usage: fnm env [OPTIONS]
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -378,7 +384,7 @@ Options: @@ -378,7 +384,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -402,7 +408,7 @@ Usage: fnm completions [OPTIONS] @@ -402,7 +408,7 @@ Usage: fnm completions [OPTIONS]
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -440,7 +446,7 @@ Options: @@ -440,7 +446,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -471,7 +477,7 @@ Arguments: @@ -471,7 +477,7 @@ Arguments:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -504,7 +510,7 @@ Options: @@ -504,7 +510,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -532,7 +538,7 @@ Arguments: @@ -532,7 +538,7 @@ Arguments:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -565,7 +571,7 @@ Options: @@ -565,7 +571,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -595,7 +601,7 @@ Arguments: @@ -595,7 +601,7 @@ Arguments:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -628,7 +634,7 @@ Options: @@ -628,7 +634,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -652,7 +658,7 @@ Usage: fnm current [OPTIONS] @@ -652,7 +658,7 @@ Usage: fnm current [OPTIONS]
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -685,7 +691,7 @@ Options: @@ -685,7 +691,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -718,7 +724,7 @@ Arguments: @@ -718,7 +724,7 @@ Arguments:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -754,7 +760,7 @@ Options: @@ -754,7 +760,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]
@ -784,7 +790,7 @@ Arguments: @@ -784,7 +790,7 @@ Arguments:
Options:
--node-dist-mirror <NODE_DIST_MIRROR>
https://nodejs.org/dist/ mirror
<https://nodejs.org/dist/> mirror
[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]
@ -817,7 +823,7 @@ Options: @@ -817,7 +823,7 @@ Options:
- recursive: Use the version of Node defined within the current directory and all parent directories
--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see https://nodejs.org/api/corepack.html
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>
[env: FNM_COREPACK_ENABLED]

72
docs/configuration.md

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
# Configuration
fnm comes with many features out of the box. Some of them are not activated by default as they’re changing your shell default behavior, and some are just a feature flag to avoid breaking changes or just experimental until we decide it is worthwhile to introduce them.
All these features can be configured by adding flags to the `fnm env` call when initializing the shell. For instance, if your shell set up looks like `eval "$(fnm env)"` then you can add a flag to it by changing it to `eval "$(fnm env --my-flag=value)"`
Here’s a list of these features and capabilities:
### `--use-on-cd`
**✅ Highly recommended**
`--use-on-cd` appends output to `fnm env`'s output that will hook into your shell upon changing directories, and will switch the Node.js version based on the requirements of the current directory, based on `.node-version` or `.nvmrc` (or `packages.json#engines#node` if `--resolve-engines` was enabled).
This allows you do avoid thinking about `fnm use`, and only `cd <DIR>` to make it work.
### `--version-file-strategy=recursive`
**✅ Highly recommended**
Makes `fnm use` and `fnm install` take parent directories into account when looking for a version file ("dotfile")--when no argument was given.
So, let's say we have the following directory structure:
```
repo/
├── package.json
├── .node-version <- with content: `20.0.0`
└── packages/
└── my-package/ <- I am here
└── package.json
```
And I'm running the following command:
```sh-session
repo/packages/my-package$ fnm use
```
Then fnm will switch to Node.js v20.0.0.
Without the explicit flag, the value is set to `local`, which will not traverse the directory tree and therefore will print:
```sh-session
repo/packages/my-package$ fnm use
error: Can't find version in dotfiles. Please provide a version manually to the command.
```
### `--enable-corepack`
**🧪 Experimental**
Runs [`corepack enable`](https://nodejs.org/api/corepack.html#enabling-the-feature) when a new version of Node.js is installed. Experimental due to the fact Corepack itself is experimental.
### `--resolve-engines`
**🧪 Experimental**
Treats `package.json#engines#node` as a valid Node.js version file ("dotfile"). So, if you have a package.json with the following content:
```json
{
"engines": {
"node": ">=20 <21"
}
}
```
Then:
- `fnm install` will install the latest satisfying Node.js 20.x version available in the Node.js dist server
- `fnm use` will use the latest satisfying Node.js 20.x version available on your system, or prompt to install if no version matched.

3
rust-toolchain.toml

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
[toolchain]
channel = "1.78"
components = ["rustfmt", "clippy"]

7
src/arch.rs

@ -4,6 +4,7 @@ use crate::version::Version; @@ -4,6 +4,7 @@ use crate::version::Version;
pub enum Arch {
X86,
X64,
X64Musl,
Arm64,
Armv7l,
Ppc64le,
@ -16,10 +17,10 @@ pub enum Arch { @@ -16,10 +17,10 @@ pub enum Arch {
pub fn get_safe_arch<'a>(arch: &'a Arch, version: &Version) -> &'a Arch {
use crate::system_info::{platform_arch, platform_name};
return match (platform_name(), platform_arch(), version) {
match (platform_name(), platform_arch(), version) {
("darwin", "arm64", Version::Semver(v)) if v.major < 16 => &Arch::X64,
_ => arch,
};
}
}
#[cfg(windows)]
@ -43,6 +44,7 @@ impl std::str::FromStr for Arch { @@ -43,6 +44,7 @@ impl std::str::FromStr for Arch {
match s {
"x86" => Ok(Arch::X86),
"x64" => Ok(Arch::X64),
"x64-musl" => Ok(Arch::X64Musl),
"arm64" => Ok(Arch::Arm64),
"armv7l" => Ok(Arch::Armv7l),
"ppc64le" => Ok(Arch::Ppc64le),
@ -58,6 +60,7 @@ impl std::fmt::Display for Arch { @@ -58,6 +60,7 @@ impl std::fmt::Display for Arch {
let arch_str = match self {
Arch::X86 => String::from("x86"),
Arch::X64 => String::from("x64"),
Arch::X64Musl => String::from("x64-musl"),
Arch::Arm64 => String::from("arm64"),
Arch::Armv7l => String::from("armv7l"),
Arch::Ppc64le => String::from("ppc64le"),

4
src/archive/mod.rs

@ -3,5 +3,9 @@ pub mod tar_xz; @@ -3,5 +3,9 @@ pub mod tar_xz;
pub mod zip;
pub use self::extract::{Error, Extract};
#[cfg(unix)]
pub use self::tar_xz::TarXz;
#[cfg(windows)]
pub use self::zip::Zip;

2
src/commands/env.rs

@ -44,7 +44,7 @@ fn make_symlink(config: &FnmConfig) -> Result<std::path::PathBuf, Error> { @@ -44,7 +44,7 @@ fn make_symlink(config: &FnmConfig) -> Result<std::path::PathBuf, Error> {
}
match symlink_dir(config.default_version_dir(), &temp_dir) {
Ok(_) => Ok(temp_dir),
Ok(()) => Ok(temp_dir),
Err(source) => Err(Error::CantCreateSymlink { source, temp_dir }),
}
}

16
src/commands/install.rs

@ -5,6 +5,7 @@ use crate::config::FnmConfig; @@ -5,6 +5,7 @@ use crate::config::FnmConfig;
use crate::downloader::{install_node_dist, Error as DownloaderError};
use crate::lts::LtsType;
use crate::outln;
use crate::progress::ProgressConfig;
use crate::remote_node_index;
use crate::user_version::UserVersion;
use crate::version::Version;
@ -25,6 +26,12 @@ pub struct Install { @@ -25,6 +26,12 @@ pub struct Install {
/// Install latest version
#[clap(long, conflicts_with_all = &["version", "lts"])]
pub latest: bool,
/// Show an interactive progress bar for the download
/// status.
#[clap(long, default_value_t)]
#[arg(value_enum)]
pub progress: ProgressConfig,
}
impl Install {
@ -34,16 +41,19 @@ impl Install { @@ -34,16 +41,19 @@ impl Install {
version: v,
lts: false,
latest: false,
..
} => Ok(v),
Self {
version: None,
lts: true,
latest: false,
..
} => Ok(Some(UserVersion::Full(Version::Lts(LtsType::Latest)))),
Self {
version: None,
lts: false,
latest: true,
..
} => Ok(Some(UserVersion::Full(Version::Latest))),
_ => Err(Error::TooManyVersionsProvided),
}
@ -55,6 +65,7 @@ impl Command for Install { @@ -55,6 +65,7 @@ impl Command for Install {
fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> {
let current_dir = std::env::current_dir().unwrap();
let show_progress = self.progress.enabled(config);
let current_version = self
.version()?
@ -131,12 +142,13 @@ impl Command for Install { @@ -131,12 +142,13 @@ impl Command for Install {
&config.node_dist_mirror,
config.installations_dir(),
safe_arch,
show_progress,
) {
Err(err @ DownloaderError::VersionAlreadyInstalled { .. }) => {
outln!(config, Error, "{} {}", "warning:".bold().yellow(), err);
}
Err(source) => Err(Error::DownloadError { source })?,
Ok(_) => {}
Ok(()) => {}
};
if config.corepack_enabled() {
@ -225,6 +237,7 @@ mod tests { @@ -225,6 +237,7 @@ mod tests {
version: UserVersion::from_str("12.0.0").ok(),
lts: false,
latest: false,
progress: ProgressConfig::Never,
}
.apply(&config)
.expect("Can't install");
@ -250,6 +263,7 @@ mod tests { @@ -250,6 +263,7 @@ mod tests {
version: None,
lts: false,
latest: true,
progress: ProgressConfig::Never,
}
.apply(&config)
.expect("Can't install");

2
src/commands/use.rs

@ -153,7 +153,7 @@ fn install_new_version( @@ -153,7 +153,7 @@ fn install_new_version(
fn replace_symlink(from: &std::path::Path, to: &std::path::Path) -> std::io::Result<()> {
let symlink_deletion_result = fs::remove_symlink_dir(to);
match fs::symlink_dir(from, to) {
ok @ Ok(_) => ok,
ok @ Ok(()) => ok,
err @ Err(_) => symlink_deletion_result.and(err),
}
}

4
src/config.rs

@ -7,7 +7,7 @@ use url::Url; @@ -7,7 +7,7 @@ use url::Url;
#[derive(clap::Parser, Debug)]
pub struct FnmConfig {
/// https://nodejs.org/dist/ mirror
/// <https://nodejs.org/dist/> mirror
#[clap(
long,
env = "FNM_NODE_DIST_MIRROR",
@ -67,7 +67,7 @@ pub struct FnmConfig { @@ -67,7 +67,7 @@ pub struct FnmConfig {
/// Enable corepack support for each new installation.
/// This will make fnm call `corepack enable` on every Node.js installation.
/// For more information about corepack see https://nodejs.org/api/corepack.html
/// For more information about corepack see <https://nodejs.org/api/corepack.html>
#[clap(
long,
env = "FNM_COREPACK_ENABLED",

21
src/downloader.rs

@ -2,8 +2,11 @@ use crate::arch::Arch; @@ -2,8 +2,11 @@ use crate::arch::Arch;
use crate::archive;
use crate::archive::{Error as ExtractError, Extract};
use crate::directory_portal::DirectoryPortal;
use crate::progress::ResponseProgress;
use crate::version::Version;
use indicatif::ProgressDrawTarget;
use log::debug;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use thiserror::Error;
@ -63,10 +66,7 @@ fn download_url(base_url: &Url, version: &Version, arch: &Arch) -> Url { @@ -63,10 +66,7 @@ fn download_url(base_url: &Url, version: &Version, arch: &Arch) -> Url {
.unwrap()
}
pub fn extract_archive_into<P: AsRef<Path>>(
path: P,
response: crate::http::Response,
) -> Result<(), Error> {
fn extract_archive_into(path: impl AsRef<Path>, response: impl Read) -> Result<(), Error> {
#[cfg(unix)]
let extractor = archive::TarXz::new(response);
#[cfg(windows)]
@ -81,6 +81,7 @@ pub fn install_node_dist<P: AsRef<Path>>( @@ -81,6 +81,7 @@ pub fn install_node_dist<P: AsRef<Path>>(
node_dist_mirror: &Url,
installations_dir: P,
arch: &Arch,
show_progress: bool,
) -> Result<(), Error> {
let installation_dir = PathBuf::from(installations_dir.as_ref()).join(version.v_str());
@ -109,7 +110,14 @@ pub fn install_node_dist<P: AsRef<Path>>( @@ -109,7 +110,14 @@ pub fn install_node_dist<P: AsRef<Path>>(
}
debug!("Extracting response...");
extract_archive_into(&portal, response)?;
if show_progress {
extract_archive_into(
&portal,
ResponseProgress::new(response, ProgressDrawTarget::stderr()),
)?;
} else {
extract_archive_into(&portal, response)?;
}
debug!("Extraction completed");
let installed_directory = std::fs::read_dir(&portal)?
@ -171,7 +179,8 @@ mod tests { @@ -171,7 +179,8 @@ mod tests {
let version = Version::parse("12.0.0").unwrap();
let arch = Arch::X64;
let node_dist_mirror = Url::parse("https://nodejs.org/dist/").unwrap();
install_node_dist(&version, &node_dist_mirror, path, &arch).expect("Can't install Node 12");
install_node_dist(&version, &node_dist_mirror, path, &arch, false)
.expect("Can't install Node 12");
let mut location_path = path.join(version.v_str()).join("installation");

1
src/main.rs

@ -22,6 +22,7 @@ mod installed_versions; @@ -22,6 +22,7 @@ mod installed_versions;
mod lts;
mod package_json;
mod path_ext;
mod progress;
mod remote_node_index;
mod shell;
mod system_info;

165
src/progress.rs

@ -0,0 +1,165 @@ @@ -0,0 +1,165 @@
use std::io::Read;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use reqwest::blocking::Response;
pub struct ResponseProgress {
progress: Option<ProgressBar>,
response: Response,
}
#[derive(Default, Clone, Debug, clap::ValueEnum)]
pub enum ProgressConfig {
#[default]
Auto,
Never,
Always,
}
impl ProgressConfig {
pub fn enabled(&self, config: &crate::config::FnmConfig) -> bool {
match self {
Self::Never => false,
Self::Always => true,
Self::Auto => config
.log_level()
.is_writable(&crate::log_level::LogLevel::Info),
}
}
}
fn make_progress_bar(size: u64, target: ProgressDrawTarget) -> ProgressBar {
let bar = ProgressBar::with_draw_target(Some(size), target);
bar.set_style(
ProgressStyle::with_template(
"{elapsed_precise:.white.dim} {wide_bar:.cyan} {bytes}/{total_bytes} ({bytes_per_sec}, {eta})",
)
.unwrap()
.progress_chars("█▉▊▋▌▍▎▏ "),
);
bar
}
impl ResponseProgress {
pub fn new(response: Response, target: ProgressDrawTarget) -> Self {
Self {
progress: response
.content_length()
.map(|len| make_progress_bar(len, target)),
response,
}
}
pub fn finish(&self) {
if let Some(ref bar) = self.progress {
bar.finish();
}
}
}
impl Read for ResponseProgress {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let size = self.response.read(buf)?;
if let Some(ref bar) = self.progress {
bar.inc(size as u64);
}
Ok(size)
}
}
impl Drop for ResponseProgress {
fn drop(&mut self) {
self.finish();
eprintln!();
}
}
#[cfg(test)]
mod tests {
use indicatif::{ProgressDrawTarget, TermLike};
use reqwest::blocking::Response;
use std::{
io::Read,
sync::{Arc, Mutex},
};
use super::ResponseProgress;
const CONTENT_LENGTH: usize = 100;
#[derive(Debug)]
struct MockedTerm {
pub buf: Arc<Mutex<String>>,
}
impl TermLike for MockedTerm {
fn width(&self) -> u16 {
80
}
fn move_cursor_up(&self, _n: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_down(&self, _n: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_right(&self, _n: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_left(&self, _n: usize) -> std::io::Result<()> {
Ok(())
}
fn write_line(&self, s: &str) -> std::io::Result<()> {
self.buf.lock().unwrap().push_str(s);
Ok(())
}
fn write_str(&self, s: &str) -> std::io::Result<()> {
self.buf.lock().unwrap().push_str(s);
Ok(())
}
fn clear_line(&self) -> std::io::Result<()> {
Ok(())
}
fn flush(&self) -> std::io::Result<()> {
Ok(())
}
}
#[test]
fn test_reads_data_and_shows_progress() {
let response: Response = http::Response::builder()
.header("Content-Length", CONTENT_LENGTH)
.body("a".repeat(CONTENT_LENGTH))
.unwrap()
.into();
let mut buf = [0; CONTENT_LENGTH];
let out_buf = Arc::new(Mutex::new(String::new()));
let mut progress = ResponseProgress::new(
response,
ProgressDrawTarget::term_like(Box::new(MockedTerm {
buf: out_buf.clone(),
})),
);
let size = progress.read(&mut buf[..]).unwrap();
drop(progress);
assert_eq!(size, CONTENT_LENGTH);
assert_eq!(buf, "a".repeat(CONTENT_LENGTH).as_bytes());
assert!(out_buf.lock().unwrap().contains(&"█".repeat(40)));
}
}

6
src/shell/bash.rs

@ -28,13 +28,13 @@ impl Shell for Bash { @@ -28,13 +28,13 @@ impl Shell for Bash {
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let autoload_hook = match config.version_file_strategy() {
VersionFileStrategy::Local => indoc!(
r#"
r"
if [[ -f .node-version || -f .nvmrc ]]; then
fnm use --silent-if-unchanged
fi
"#
"
),
VersionFileStrategy::Recursive => r#"fnm use --silent-if-unchanged"#,
VersionFileStrategy::Recursive => r"fnm use --silent-if-unchanged",
};
Ok(formatdoc!(
r#"

6
src/shell/fish.rs

@ -28,13 +28,13 @@ impl Shell for Fish { @@ -28,13 +28,13 @@ impl Shell for Fish {
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let autoload_hook = match config.version_file_strategy() {
VersionFileStrategy::Local => indoc!(
r#"
r"
if test -f .node-version -o -f .nvmrc
fnm use --silent-if-unchanged
end
"#
"
),
VersionFileStrategy::Recursive => r#"fnm use --silent-if-unchanged"#,
VersionFileStrategy::Recursive => r"fnm use --silent-if-unchanged",
};
Ok(formatdoc!(
r#"

2
src/shell/infer/mod.rs

@ -7,7 +7,7 @@ pub use self::unix::infer_shell; @@ -7,7 +7,7 @@ pub use self::unix::infer_shell;
#[cfg(not(unix))]
pub use self::windows::infer_shell;
pub(self) fn shell_from_string(shell: &str) -> Option<Box<dyn super::Shell>> {
fn shell_from_string(shell: &str) -> Option<Box<dyn super::Shell>> {
use super::{Bash, Fish, PowerShell, WindowsCmd, Zsh};
match shell {
"sh" | "bash" => return Some(Box::from(Bash)),

6
src/shell/powershell.rs

@ -28,11 +28,11 @@ impl Shell for PowerShell { @@ -28,11 +28,11 @@ impl Shell for PowerShell {
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let autoload_hook = match config.version_file_strategy() {
VersionFileStrategy::Local => indoc!(
r#"
r"
If ((Test-Path .nvmrc) -Or (Test-Path .node-version)) { & fnm use --silent-if-unchanged }
"#
"
),
VersionFileStrategy::Recursive => r#"fnm use --silent-if-unchanged"#,
VersionFileStrategy::Recursive => r"fnm use --silent-if-unchanged",
};
Ok(formatdoc!(
r#"

6
src/shell/zsh.rs

@ -32,13 +32,13 @@ impl Shell for Zsh { @@ -32,13 +32,13 @@ impl Shell for Zsh {
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let autoload_hook = match config.version_file_strategy() {
VersionFileStrategy::Local => indoc!(
r#"
r"
if [[ -f .node-version || -f .nvmrc ]]; then
fnm use --silent-if-unchanged
fi
"#
"
),
VersionFileStrategy::Recursive => r#"fnm use --silent-if-unchanged"#,
VersionFileStrategy::Recursive => r"fnm use --silent-if-unchanged",
};
Ok(formatdoc!(
r#"

Loading…
Cancel
Save