#!/usr/bin/env bash # ============================================================================= # conda 环境切换的公共逻辑。被 scripts/env.sh 与 scripts/sim_env.sh 共用。 # # 为什么需要这个:conda 的 activate 是**堆叠**的。在同一个 shell 里反复 # activate / 切换不同环境,会不断往 PATH、PYTHONPATH 里追加条目,而不会 # 清掉前一个环境留下的。实测的后果非常隐蔽: # # 在同一个 shell 里先 activate ros_gz_sim 再切 ros_flexiv 之后, # `which python` 指向 ros_flexiv/bin/python, # 但 `python -m pip` 却解析到 ros_gz_sim 的 pip! # 于是 colcon --symlink-install 报: # error: option --editable not recognized # 这个报错和真实原因(shell 脏了)毫无关系,极易被误判成 # "环境被搞坏了 / setuptools 版本不对",进而去做一堆无用的修复。 # # 对策:切换前先把堆叠的激活全部退掉(退到 base),再激活目标环境。 # ============================================================================= # conda_deactivate_all: 退到 base(CONDA_SHLVL=1)。任何环境下调用都安全。 conda_deactivate_all() { local guard=0 # CONDA_SHLVL 是 conda 自己维护的激活层数;base 为 1。 # 加 guard 是为了防止某些畸形状态下无限循环。 while [[ "${CONDA_SHLVL:-1}" -gt 1 && "${guard}" -lt 20 ]]; do conda deactivate 2>/dev/null || break guard=$((guard + 1)) done return 0 } # conda_switch_clean [] # 干净地激活 ;若当前已在 里,先退到 base 再切, # 并提示用户最好开新 shell。 # 返回 0 = 成功;非 0 = 目标环境不存在。 conda_switch_clean() { local target="$1" local other="${2:-}" if [[ -n "${other}" && "${CONDA_DEFAULT_ENV:-}" == "${other}" ]]; then echo "提示: 当前 shell 激活的是 ${other},即将切到 ${target}。" >&2 echo " conda 的激活是堆叠的,同一 shell 里来回切会残留 PATH/PYTHONPATH," >&2 echo " 典型症状是构建报 \"--editable not recognized\" 这类与真实原因无关的错。" >&2 echo " 这里会先退到 base 再切以规避;但最稳妥仍是开一个新 shell。" >&2 fi conda_deactivate_all if ! conda activate "${target}" 2>/dev/null; then return 1 fi return 0 } # 供调用方按需取消设置,避免污染使用者的变量空间。 # (bash 没有"私有函数"概念,命名上统一加 conda_ 前缀降低撞名概率。)