From 93c23ee39f9f0a325f4ccf1f87edd5abf2636d68 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 18 Sep 2025 08:05:11 +0200 Subject: [PATCH] Always use \n line endings for bash, zsh and fish --- .../src/shell-integration/helpers.js | 21 +++++++++++++------ .../supported-shells/bash.js | 13 +++++++++--- .../supported-shells/fish.js | 10 ++++++--- .../shell-integration/supported-shells/zsh.js | 13 +++++++++--- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/safe-chain/src/shell-integration/helpers.js b/packages/safe-chain/src/shell-integration/helpers.js index 7efface..e3320a1 100644 --- a/packages/safe-chain/src/shell-integration/helpers.js +++ b/packages/safe-chain/src/shell-integration/helpers.js @@ -22,15 +22,17 @@ export function doesExecutableExistOnSystem(executableName) { } } -export function removeLinesMatchingPattern(filePath, pattern) { +export function removeLinesMatchingPattern(filePath, pattern, eol) { if (!fs.existsSync(filePath)) { return; } + eol = eol || os.EOL; + const fileContent = fs.readFileSync(filePath, "utf-8"); const lines = fileContent.split(/[\r\n\u2028\u2029]+/); const updatedLines = lines.filter((line) => !shouldRemoveLine(line, pattern)); - fs.writeFileSync(filePath, updatedLines.join(os.EOL), "utf-8"); + fs.writeFileSync(filePath, updatedLines.join(eol), "utf-8"); } const maxLineLength = 100; @@ -43,12 +45,17 @@ function shouldRemoveLine(line, pattern) { if (line.length > maxLineLength) { // safe-chain only adds lines shorter than maxLineLength - // so if the line is longer, it must be from a different + // so if the line is longer, it must be from a different // source and could be dangerous to remove return false; } - if (line.includes("\n") || line.includes("\r") || line.includes("\u2028") || line.includes("\u2029")) { + if ( + line.includes("\n") || + line.includes("\r") || + line.includes("\u2028") || + line.includes("\u2029") + ) { // If the line contains newlines, something has gone wrong in splitting // \u2028 and \u2029 are Unicode line separator characters (line and paragraph separators) return false; @@ -57,12 +64,14 @@ function shouldRemoveLine(line, pattern) { return true; } -export function addLineToFile(filePath, line) { +export function addLineToFile(filePath, line, eol) { if (!fs.existsSync(filePath)) { fs.writeFileSync(filePath, "", "utf-8"); } + eol = eol || os.EOL; + const fileContent = fs.readFileSync(filePath, "utf-8"); - const updatedContent = fileContent + os.EOL + line; + const updatedContent = fileContent + eol + line; fs.writeFileSync(filePath, updatedContent, "utf-8"); } diff --git a/packages/safe-chain/src/shell-integration/supported-shells/bash.js b/packages/safe-chain/src/shell-integration/supported-shells/bash.js index 5f9c54e..6038f95 100644 --- a/packages/safe-chain/src/shell-integration/supported-shells/bash.js +++ b/packages/safe-chain/src/shell-integration/supported-shells/bash.js @@ -9,6 +9,7 @@ import * as os from "os"; const shellName = "Bash"; const executableName = "bash"; const startupFileCommand = "echo ~/.bashrc"; +const eol = "\n"; // When bash runs on Windows (e.g., Git Bash or WSL), it expects LF line endings. function isInstalled() { return doesExecutableExistOnSystem(executableName); @@ -19,13 +20,18 @@ function teardown(tools) { for (const { tool } of tools) { // Remove any existing alias for the tool - removeLinesMatchingPattern(startupFile, new RegExp(`^alias\\s+${tool}=`)); + removeLinesMatchingPattern( + startupFile, + new RegExp(`^alias\\s+${tool}=`), + eol + ); } // Removes the line that sources the safe-chain bash initialization script (~/.aikido/scripts/init-posix.sh) removeLinesMatchingPattern( startupFile, - /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/ + /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/, + eol ); return true; @@ -36,7 +42,8 @@ function setup() { addLineToFile( startupFile, - `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain bash initialization script` + `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain bash initialization script`, + eol ); return true; diff --git a/packages/safe-chain/src/shell-integration/supported-shells/fish.js b/packages/safe-chain/src/shell-integration/supported-shells/fish.js index 7b2c683..4c39ba6 100644 --- a/packages/safe-chain/src/shell-integration/supported-shells/fish.js +++ b/packages/safe-chain/src/shell-integration/supported-shells/fish.js @@ -8,6 +8,7 @@ import { execSync } from "child_process"; const shellName = "Fish"; const executableName = "fish"; const startupFileCommand = "echo ~/.config/fish/config.fish"; +const eol = "\n"; // When fish runs on Windows (e.g., Git Bash or WSL), it expects LF line endings. function isInstalled() { return doesExecutableExistOnSystem(executableName); @@ -20,14 +21,16 @@ function teardown(tools) { // Remove any existing alias for the tool removeLinesMatchingPattern( startupFile, - new RegExp(`^alias\\s+${tool}\\s+`) + new RegExp(`^alias\\s+${tool}\\s+`), + eol ); } // Removes the line that sources the safe-chain fish initialization script (~/.safe-chain/scripts/init-fish.fish) removeLinesMatchingPattern( startupFile, - /^source\s+~\/\.safe-chain\/scripts\/init-fish\.fish/ + /^source\s+~\/\.safe-chain\/scripts\/init-fish\.fish/, + eol ); return true; @@ -38,7 +41,8 @@ function setup() { addLineToFile( startupFile, - `source ~/.safe-chain/scripts/init-fish.fish # Safe-chain Fish initialization script` + `source ~/.safe-chain/scripts/init-fish.fish # Safe-chain Fish initialization script`, + eol ); return true; diff --git a/packages/safe-chain/src/shell-integration/supported-shells/zsh.js b/packages/safe-chain/src/shell-integration/supported-shells/zsh.js index b5167fe..b90f769 100644 --- a/packages/safe-chain/src/shell-integration/supported-shells/zsh.js +++ b/packages/safe-chain/src/shell-integration/supported-shells/zsh.js @@ -8,6 +8,7 @@ import { execSync } from "child_process"; const shellName = "Zsh"; const executableName = "zsh"; const startupFileCommand = "echo ${ZDOTDIR:-$HOME}/.zshrc"; +const eol = "\n"; // When zsh runs on Windows (e.g., Git Bash or WSL), it expects LF line endings. function isInstalled() { return doesExecutableExistOnSystem(executableName); @@ -18,13 +19,18 @@ function teardown(tools) { for (const { tool } of tools) { // Remove any existing alias for the tool - removeLinesMatchingPattern(startupFile, new RegExp(`^alias\\s+${tool}=`)); + removeLinesMatchingPattern( + startupFile, + new RegExp(`^alias\\s+${tool}=`), + eol + ); } // Removes the line that sources the safe-chain zsh initialization script (~/.aikido/scripts/init-posix.sh) removeLinesMatchingPattern( startupFile, - /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/ + /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/, + eol ); return true; @@ -35,7 +41,8 @@ function setup() { addLineToFile( startupFile, - `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain Zsh initialization script` + `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain Zsh initialization script`, + eol ); return true;