🐚

go のバージョンを go.mod から選ばせてみよう

2024/02/14に公開

ああ、go.mod があるっていうのに、なんで我々は ${PATH} で消耗しないといけないんでしょう?

goenv 入れるのもなあ... なんで .go-version とかいうファイルを置かないといけないんでしょう [1]

もっと雑に管理したいですねえ。 go.mod みていい感じにしてくれたら嬉しいですよねえ!! そうでしょう?

こんなことやってみた

というわけで、ざっくりこんなことやってみました。

ディレクトリを整理する

go の実行系のある場所といえば ~/sdk ですね。
まずはその ~/sdk にちょっと手を加えて、こんな感じにしました。

$ ls -la ~/sdk
total 0
$ ls -la
total 0
drwxr-xr-x  16 youta  staff   512  2 14 22:00 .
drwxr-xr-x+ 91 youta  staff  2912  2 14 21:29 ..
lrwxr-xr-x   1 youta  staff    10  2 14 21:34 go -> ./go1.22.x
drwxr-xr-x  20 youta  staff   640  2 14 21:58 go1.17.13
lrwxr-xr-x   1 youta  staff    11  2 14 21:59 go1.17.x -> ./go1.17.13
drwxr-xr-x  19 youta  staff   608  3 15  2022 go1.18
drwxr-xr-x  20 youta  staff   640  2 14 21:59 go1.18.10
drwxr-xr-x  21 youta  staff   672  9 26  2022 go1.18.6
lrwxr-xr-x   1 youta  staff    11  2 14 21:59 go1.18.x -> ./go1.18.10
drwxr-xr-x  17 youta  staff   544  1  5 08:48 go1.20.13
lrwxr-xr-x   1 youta  staff    11  2 14 22:00 go1.20.x -> ./go1.20.13
drwxr-xr-x  20 youta  staff   640  9 19 23:28 go1.21.1
lrwxr-xr-x   1 youta  staff    10  2 14 22:00 go1.21.x -> ./go1.21.1
drwxr-xr-x  19 youta  staff   608  2 14 21:19 go1.22.0
lrwxr-xr-x   1 youta  staff    10  2 14 22:00 go1.22.x -> ./go1.22.0
drwxr-xr-x  18 youta  staff   576  1 24 04:44 go1.22rc2

はい、 各 go1.${N} ごとに、普段遣いしたいリリース番号のものに向けて go1.${N}.x から symlink しました。

さらに、"go といえばコレ"というバージョンに向けて go からリンクを貼りました。

これが第一段階です。

いいかんじのシェルスクリプトを書く。

あとは、このディレクトリ構成を前提にしたシェルスクリプトを書いて、go って名前にして $PATH の先頭側にくっつけるだけです。

こんなシェルスクリプトになりました[2]

#! /bin/bash

SDK=${GOSDK:-~/sdk}

function detectGomod() {
  if [ -r "./go.mod" ] ; then
    echo $(pwd)/go.mod
    return 0
  fi
  if [ $(pwd) == / ] ; then
    return 0
  fi
  cd ../
  detectGomod
}

GOMOD=$(detectGomod)

if [ "${GOMOD}" == "" ] ; then
  exec "${SDK}/go/bin/go" $@
  exit
fi

GOVER=$(grep -Ee '^go ' ${GOMOD} | head -n 1 | awk '{ print $2 }')

exec ${SDK}/go${GOVER}.x/bin/go $@

起動した場所から上側にたどっていって go.mod を探し、 その中の go ディレクティブをエイヤ!と解析して language version[3] を取り出しています。

リリース番号が書いてないことを前提に、 ~/sdk/go${GOVER}.x/bin/goexec してやれば、 go.mod 準拠の go セレクタが一丁上がり!

go.mod が見つからなければ、~/sdk/go をデフォルトの go だと思うことにしています。

リリース番号には未対応ですが、対応する場合は、リリース番号を検出したら *.x じゃないものから選ぶように拡張すればいいですね。

まとめ

いやあ、シェルスクリプトって気持ちいいですねえ!!!

追記

ゲェーッ、VSCode が ${PATH} に go の実行環境のパスを差し込んでくる...

脚注
  1. 答:リリース番号まで go.mod に書いてあると限らないから。 ↩︎

  2. コピーしたい? ご自由にどうぞ。 ↩︎

  3. https://go.dev/doc/toolchain#version ↩︎

Discussion