mirror of
https://github.com/usestrix/strix.git
synced 2026-09-30 01:52:18 +00:00
fix(install): only manage strix in the installer's own directory
`check_existing_installation` walked `which -a strix` and deleted every match outside `$INSTALL_DIR`, and `verify_installation` deleted whatever executable won PATH resolution. Path discovery shows that another `strix` exists; it does not show that the installer owns it. A pipx install or a development checkout on `PATH` was removed without being asked about, including a `pipx uninstall strix-agent` triggered purely by the path containing `.local/bin`. The installer now touches only `$INSTALL_DIR`. Other executables are reported, and when one wins PATH resolution the user is told how to reorder `PATH` or remove it themselves. Fixes #1262 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
95e085eb6c
commit
b337a42771
2 changed files with 68 additions and 28 deletions
|
|
@ -99,33 +99,35 @@ print_message() {
|
|||
echo -e "${color}${message}${NC}"
|
||||
}
|
||||
|
||||
describe_removal() {
|
||||
local path=$1
|
||||
|
||||
if [[ "$path" == *".local/bin"* ]] && command -v pipx >/dev/null 2>&1; then
|
||||
echo -e "${MUTED} It looks like a pipx installation. To remove it: ${NC}pipx uninstall strix-agent"
|
||||
else
|
||||
echo -e "${MUTED} To remove it: ${NC}rm $path"
|
||||
fi
|
||||
}
|
||||
|
||||
check_existing_installation() {
|
||||
UNMANAGED_INSTALLATIONS=()
|
||||
|
||||
local found_paths=()
|
||||
while IFS= read -r -d '' path; do
|
||||
found_paths+=("$path")
|
||||
done < <(which -a strix 2>/dev/null | tr '\n' '\0' || true)
|
||||
|
||||
if [ ${#found_paths[@]} -gt 0 ]; then
|
||||
for path in "${found_paths[@]}"; do
|
||||
if [[ ! -e "$path" ]] || [[ "$path" == "$INSTALL_DIR/strix"* ]]; then
|
||||
continue
|
||||
fi
|
||||
for path in "${found_paths[@]:-}"; do
|
||||
if [[ -z "$path" ]] || [[ ! -e "$path" ]] || [[ "$path" == "$INSTALL_DIR/strix"* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -n "$path" ]]; then
|
||||
echo -e "${MUTED}Found existing strix at: ${NC}$path"
|
||||
UNMANAGED_INSTALLATIONS+=("$path")
|
||||
echo -e "${MUTED}Found another strix at: ${NC}$path"
|
||||
done
|
||||
|
||||
if [[ "$path" == *".local/bin"* ]]; then
|
||||
echo -e "${MUTED}Removing old pipx installation...${NC}"
|
||||
if command -v pipx >/dev/null 2>&1; then
|
||||
pipx uninstall strix-agent 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$path" 2>/dev/null || true
|
||||
elif [[ -L "$path" || -f "$path" ]]; then
|
||||
echo -e "${MUTED}Removing old installation...${NC}"
|
||||
rm -f "$path" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ ${#UNMANAGED_INSTALLATIONS[@]} -gt 0 ]; then
|
||||
echo -e "${MUTED}This installer only manages ${NC}$INSTALL_DIR${MUTED}, so it is left alone.${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -296,15 +298,10 @@ verify_installation() {
|
|||
|
||||
if [[ "$which_strix" != "$INSTALL_DIR/strix" && "$which_strix" != "$INSTALL_DIR/strix.exe" ]]; then
|
||||
if [[ -n "$which_strix" ]]; then
|
||||
echo -e "${YELLOW}⚠ Found conflicting strix at: ${NC}$which_strix"
|
||||
echo -e "${MUTED}Attempting to remove...${NC}"
|
||||
|
||||
if rm -f "$which_strix" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Removed conflicting installation${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Could not remove automatically.${NC}"
|
||||
echo -e "${MUTED}Please remove manually: ${NC}rm $which_strix"
|
||||
fi
|
||||
echo -e "${YELLOW}⚠ Another strix wins PATH resolution: ${NC}$which_strix"
|
||||
echo -e "${MUTED}The version just installed lives in ${NC}$INSTALL_DIR${MUTED} and will not run until that changes.${NC}"
|
||||
echo -e "${MUTED}Put ${NC}$INSTALL_DIR${MUTED} earlier on your PATH, or remove the other executable yourself.${NC}"
|
||||
describe_removal "$which_strix"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -152,3 +152,46 @@ def test_installer_rejects_unsupported_architecture(tmp_path: Path) -> None:
|
|||
assert "Unsupported OS/Arch: linux/riscv64" in result.stdout
|
||||
assert not curl_log_path.exists()
|
||||
assert not (home_path / ".strix").exists()
|
||||
|
||||
|
||||
def _install_with_decoy(tmp_path: Path, decoy_directory_name: str) -> tuple[Path, Path, Path]:
|
||||
"""Run the installer with an unrelated `strix` ahead of it on `PATH`."""
|
||||
repository_root = Path(__file__).resolve().parents[1]
|
||||
archive_path = _create_release_archive(tmp_path)
|
||||
mock_bin = _create_mock_commands(tmp_path, machine="aarch64")
|
||||
|
||||
pipx_log_path = tmp_path / "pipx.log"
|
||||
_write_executable(
|
||||
mock_bin / "pipx",
|
||||
f'#!/bin/sh\nprintf \'%s\n\' "$*" >> "{pipx_log_path}"\n',
|
||||
)
|
||||
|
||||
decoy_directory = tmp_path / decoy_directory_name
|
||||
decoy_directory.mkdir(parents=True)
|
||||
decoy_path = decoy_directory / "strix"
|
||||
_write_executable(decoy_path, "#!/bin/sh\nprintf 'other-strix 1.2.3\n'\n")
|
||||
|
||||
environment, home_path, _ = _create_installer_environment(tmp_path, archive_path, mock_bin)
|
||||
environment["PATH"] = f"{decoy_directory}:{environment['PATH']}"
|
||||
|
||||
result = _run_installer(repository_root, environment)
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
return decoy_path, pipx_log_path, home_path
|
||||
|
||||
|
||||
def test_installer_leaves_unrelated_strix_executables_alone(tmp_path: Path) -> None:
|
||||
decoy_path, pipx_log_path, home_path = _install_with_decoy(tmp_path, "other-bin")
|
||||
|
||||
assert decoy_path.exists()
|
||||
assert decoy_path.read_text(encoding="utf-8") == "#!/bin/sh\nprintf 'other-strix 1.2.3\n'\n"
|
||||
assert not pipx_log_path.exists()
|
||||
assert (home_path / ".strix/bin/strix").exists()
|
||||
|
||||
|
||||
def test_installer_does_not_uninstall_a_pipx_managed_strix(tmp_path: Path) -> None:
|
||||
decoy_path, pipx_log_path, home_path = _install_with_decoy(tmp_path, ".local/bin")
|
||||
|
||||
assert decoy_path.exists()
|
||||
assert not pipx_log_path.exists()
|
||||
assert (home_path / ".strix/bin/strix").exists()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue