2023年12月1日 星期五

如何解決在 WSL 安裝 GVM 後,無法使用 "code ." 開啟 VS Code 的問題。

 一、前言

前陣子有鑑於今年都沒有參加什麼 conference,所以就去高雄參加 MOPCON 2023,剛好遇到 Dcard 的工程師,小聊了一下才知道他們目前正在從 Node.js 轉換到 Golang。之前也有跟一些 hunter 小聊,很多開口第一句就是「你會寫 Go(以下皆以此取代 Golang)嗎?」對那時的我來說,這就是「不屬於我的機會」,直到我發現目前靠 C# 在寫後端的我,能夠找的職缺有限(排除金融與博弈),所以就開啟一探 Go 神秘面紗的契機。

二、安裝環境

因為我是個不喜歡在 Windows 開發程式(排除開發 C# 專案,因為會用到 Visual Studio),又想要 Windows 上的服務,所以移除非必要,大部分非 C# 的專案都會在 WSL 上開發。因此就找到保哥寫的如何在 Windows 平台打造完美的 Go 開發環境 (WSL 2),在「安裝 VSCode 需要的 go modules 與相關工具」之前的內容基本上就是再用中文交代過一次 gvm 在 GitHub 上的說明。

不過有一個小地方在 GitHub 有提到,但文章中漏掉了,那就是當你從來沒有安裝過 Go 的任何版本時,如果你要安裝 Go 1.5+ 以上的版本,你需要安裝 Go 1.4,主要原因是因為 Go 1.5+ 把  C compilers 移除了。

三、我遇到什麼問題

常用 VS Code 的人就知道,可以在 cmd 切換到指定 repo 後,透過 "code ." 在當下路徑開啟 VS Code,在 WSL 上只要設定好也是如此。但正當我準備開心的進入 Go 的世界時,我發現我無法開啟我的 VS Code!

從錯誤來看,它不認識 "code" 是什麼意思了?怎麼會這樣?於是我開始做以下檢查

  1. 在 Windows 用 Git Bash 可否使用 "code ." => 可以
  2. 重新安裝 VS Code 的 WSL extension 後,在 WSL 嘗試使用 "code ." => 不可以
  3. 重新安裝 VS Code 後,在 WSL 嘗試使用 "code ." => 不可以
  4. 將 gvm 移除後,在 WSL 嘗試使用 "code ." => 不可以
  5. 將 gvm 安裝後,於 .bashrc 所加入的
    [[ -s "/home/cyli/.gvm/scripts/gvm" ]] && source "/home/cyli/.gvm/scripts/gvm"
    註解掉後,在 WSL 嘗試使用 "code ." => 可以,但變成找不到 Go。

四、深入整個安裝流程

1. gvm-installer

執行了 gvm-installer,然後寫進 bash
bash < <(curl -s -S -L
  https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
寫進去的內容就是我前面提到的內容
GVM_DEST=${2:-$HOME}
GVM_NAME="gvm"
[ "$GVM_DEST" = "$HOME" ] && GVM_NAME=".gvm"
source_line="[[ -s \"${GVM_DEST}/$GVM_NAME/scripts/gvm\" ]] && source \"${GVM_DEST}/$GVM_NAME/scripts/gvm\""
source_file="${GVM_DEST}/$GVM_NAME/scripts/gvm"
if [ -z "$GVM_NO_UPDATE_PROFILE" ] ; then
  if [ -f "$HOME/.zshrc" ]; then
    update_profile "$HOME/.zshrc"
  fi
  if [ "$(uname)" == "Linux" ]; then
    update_profile "$HOME/.bashrc" || update_profile "$HOME/.bash_profile"
  elif [ "$(uname)" == "Darwin" ]; then
    LOGIN_SHELL=$(finger $(id -u -n) | grep Shell | cut -d : -f 3)
    echo "macOS detected. User shell is:" $LOGIN_SHELL
    if [ $LOGIN_SHELL == "/bin/zsh" ]; then # macOS moved to ZSH after macOS Catalina
      pdate_profile "$HOME/.zshrc"
    else
      update_profile "$HOME/.profile" || update_profile "$HOME/.bash_profile"
    fi
  fi
fi

2. .gvm/script/gvm

執行 gvm-default
export GVM_ROOT=/home/cyli/.gvm
. $GVM_ROOT/scripts/gvm-default

3.  $GVM_ROOT/script/gvm-default

重設各種變數,並且修改 PATH,最後執行 $GVM_ROOT/environments/default(如果存在), $GVM_ROOT/scripts/env/gvm 與 $GVM_ROOT/scripts/env/cd
unset GOROOT
unset GOARCH
unset GOOS
unset GOPATH
unset GOBIN

unset gvm_go_name
unset gvm_pkgset_name

mkdir -p "$GVM_ROOT/logs" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/gos" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive/package" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/environments" > /dev/null 2>&1

export GVM_VERSION=$(cat "$GVM_ROOT/VERSION")
export PATH="$GVM_ROOT/bin:$PATH"
export GVM_PATH_BACKUP="$PATH"
[ -f "$GVM_ROOT/environments/default" ] && . "$GVM_ROOT/environments/default"
. "$GVM_ROOT/scripts/env/gvm"

. "$GVM_ROOT/scripts/env/cd" && cd .

4. $GVM_ROOT/environments/default

重新設定各種環境變數,包含 PATH。

5. $GVM_ROOT/scripts/env/gvm

設定各種指令的路徑

6. $GVM_ROOT/scripts/env/cd

其中有一段耐人尋味
# Path cleanup
#
# Sort all paths, place rvm paths first, followed by gvm, followed by the rest.
# We do this so that rvm and gvm can live together happily.
#
# NOTE: Cleanup will also take place everytime 'gvm use' or 'gvm pkgset use' is
# executed but we do it now just to call it from some place on login.
#
export PATH="$(__gvm_munge_path)"

五、Walkaround

最終,我嘗試在 .bashrc 裡,再次設定 VS Code 的 PATH,結果就解決了。至於會不會有其他跟 VS Code 有一樣的狀況,可能要等之後遇到再說。
不過有個特別的現象是,因為 Windows 裡會有檔案的名稱含有空白,在我的 WSL 會用 ":" 取代,我有嘗試加入一樣的路徑,但結果不行,最後是加入含有跳脫的版本。

六、後記

我有嘗試在保哥的文章底下留言詢問,不過我推測並不會有通知,所以保哥並沒有回應。而我也到了 Go程式語言 (Golang Taiwan, Gopher Taipei) 的 Facebook 社團去求教,不過看起來大家都不太推 gvm,頂多是推 goenv,但我還是覺得可能可以堅持一下,雖然結果也不算有根本解決,不過至少可以讓我舒服開發了。

四、References