Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cuddly-cars-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fnm": patch
---

prefer explicit shell flags in installer-generated shell setup and fix ARM installer CI platform selection
6 changes: 3 additions & 3 deletions .ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ setup_shell() {
if [ "$USE_HOMEBREW" != "true" ]; then
echo ' export PATH="$FNM_PATH:$PATH"'
fi
echo ' eval "`fnm env`"'
echo ' eval "$(fnm env --shell zsh)"'
echo 'fi'
} | tee -a "$CONF_FILE"

Expand All @@ -193,7 +193,7 @@ setup_shell() {
if [ "$USE_HOMEBREW" != "true" ]; then
echo ' set PATH "$FNM_PATH" $PATH'
fi
echo ' fnm env | source'
echo ' fnm env --shell fish | source'
echo 'end'
} | tee -a "$CONF_FILE"

Expand All @@ -213,7 +213,7 @@ setup_shell() {
if [ "$USE_HOMEBREW" != "true" ]; then
echo ' export PATH="$FNM_PATH:$PATH"'
fi
echo ' eval "`fnm env`"'
echo ' eval "$(fnm env --shell bash)"'
echo 'fi'
} | tee -a "$CONF_FILE"

Expand Down
22 changes: 12 additions & 10 deletions .github/workflows/installation_script.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Installation script
on:
on:
pull_request:
paths:
- .ci/install.sh
Expand All @@ -13,9 +13,11 @@ jobs:
test_against_latest_release_arm:
strategy:
matrix:
docker_image:
- arm64v8/ubuntu
- arm32v7/ubuntu
include:
- docker_image: arm64v8/ubuntu
docker_platform: linux/arm64/v8
- docker_image: arm32v7/ubuntu
docker_platform: linux/arm/v7
name: Test against latest release (ARM)
runs-on: ubuntu-latest
steps:
Expand All @@ -25,7 +27,7 @@ jobs:
- uses: actions/checkout@v4
- name: Run installation script in Docker
run: |
docker run --rm -v $(pwd):$(pwd) -e "RUST_LOG=fnm=debug" --workdir $(pwd) ${{matrix.docker_image}} bash -c '
docker run --rm --platform ${{ matrix.docker_platform }} -v $(pwd):$(pwd) -e "RUST_LOG=fnm=debug" --workdir $(pwd) ${{matrix.docker_image}} bash -c '
set -e

apt update && apt install -y unzip curl libatomic1
Expand Down Expand Up @@ -53,13 +55,13 @@ jobs:
strategy:
matrix:
shell: [fish, zsh, bash]
setup:
setup:
- os: ubuntu
script_arguments: ''
script_arguments: ""
- os: macos
script_arguments: ''
script_arguments: ""
- os: macos
script_arguments: '--force-no-brew'
script_arguments: "--force-no-brew"
runs-on: ${{ matrix.setup.os }}-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -84,4 +86,4 @@ jobs:
- run: "env SHELL=$(which ${{ matrix.shell }}) bash ./.ci/install.sh ${{ matrix.setup.script_arguments }}"
name: Run the installation script
- run: ./.ci/test_installation_script.sh ${{ matrix.shell }}
name: 'Test installation script'
name: "Test installation script"
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ 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`.

> [!TIP]
> Prefer passing an explicit shell (for example `fnm env --shell bash`) instead of relying on shell inference at runtime. It is a bit faster and avoids process tree detection.

> [!NOTE]
> Check out the [Configuration](./docs/configuration.md) section to enable highly
> recommended features, like automatic version switching.
Expand Down Expand Up @@ -197,7 +200,7 @@ fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression

#### Windows Command Prompt aka Batch aka WinCMD

fnm is also supported but is not entirely covered. You can set up a startup script for [cmd.exe]( https://superuser.com/a/144348) or [Windows Terminal](https://superuser.com/a/1855283) and append the following lines:
fnm is also supported but is not entirely covered. You can set up a startup script for [cmd.exe](https://superuser.com/a/144348) or [Windows Terminal](https://superuser.com/a/1855283) and append the following lines:

```batch
@echo off
Expand Down
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ Print and set up required environment variables for fnm

This command generates a series of shell commands that should be evaluated by your shell to create a fnm-ready environment.

Each shell has its own syntax of evaluating a dynamic expression. For example, evaluating fnm on Bash and Zsh would look like `eval "$(fnm env)"`. In Fish, evaluating would look like `fnm env | source`
Each shell has its own syntax of evaluating a dynamic expression. For example, evaluating fnm on Bash and Zsh would look like `eval "$(fnm env --shell bash)"`. In Fish, evaluating would look like `fnm env --shell fish | source`

Usage: fnm env [OPTIONS]

Expand Down
65 changes: 65 additions & 0 deletions e2e/repros/issue-1527.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { writeFile } from "node:fs/promises"
import path from "node:path"
import { script } from "../shellcode/script.js"
import { Bash, Fish, PowerShell, Zsh } from "../shellcode/shells.js"
import describe from "../describe.js"
import testCwd from "../shellcode/test-cwd.js"

const findCowsayInPath = `
const fs = require("node:fs")
const path = require("node:path")

const pathEntries = (process.env.PATH || "").split(path.delimiter)
const candidates = process.platform === "win32"
? ["cowsay.cmd", "cowsay.exe", "cowsay"]
: ["cowsay"]

let found = false
for (const entry of pathEntries) {
for (const candidate of candidates) {
if (fs.existsSync(path.join(entry, candidate))) {
found = true
break
}
}

if (found) {
break
}
}

console.log(found ? "found" : "missing")
`

for (const shell of [Bash, Zsh, Fish, PowerShell]) {
describe(shell, () => {
test(`issue #1527: cowsay is not in PATH after uninstall on node 16`, async () => {
const checkPathScript = path.join(testCwd(), "check-cowsay-in-path.js")
await writeFile(checkPathScript, findCowsayInPath)

await script(shell)
.then(shell.env({}))
.then(shell.call("fnm", ["install", "16"]))
.then(shell.call("fnm", ["install", "18"]))
.then(shell.call("fnm", ["use", "16"]))
.then(shell.call("npm", ["install", "-g", "cowsay"]))
.then(shell.call("fnm", ["use", "18"]))
.then(shell.call("npm", ["install", "-g", "cowsay"]))
.then(shell.call("fnm", ["use", "16"]))
.then(
shell.scriptOutputContains(
shell.call("node", ["check-cowsay-in-path.js"]),
"found",
),
)
.then(shell.call("npm", ["uninstall", "-g", "cowsay"]))
.then(
shell.scriptOutputContains(
shell.call("node", ["check-cowsay-in-path.js"]),
"missing",
),
)
.execute(shell)
})
})
}
4 changes: 2 additions & 2 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub enum SubCommand {
/// should be evaluated by your shell to create a fnm-ready environment.
///
/// Each shell has its own syntax of evaluating a dynamic expression.
/// For example, evaluating fnm on Bash and Zsh would look like `eval "$(fnm env)"`.
/// In Fish, evaluating would look like `fnm env | source`
/// For example, evaluating fnm on Bash and Zsh would look like `eval "$(fnm env --shell bash)"`.
/// In Fish, evaluating would look like `fnm env --shell fish | source`
#[clap(name = "env", bin_name = "env")]
Env(commands::env::Env),

Expand Down
Loading