Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11495] ファイルの概要

このコミットは、Go言語のビルドシステムにおけるversion.bashスクリプトの挙動を修正するものです。具体的には、バージョン比較が数値として正しく行われるように変更を加えています。

コミット

commit 38e37011fc739487b551dff7f1f6dab5e7abcde5
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jan 30 23:33:16 2012 -0500

    build: force numerical comparison in version.bash
    
    Fixes #2436.
    
    R=golang-dev, adg
    CC=golang-dev
    https://golang.org/cl/5576075
---
 src/version.bash | 2 +-| 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/version.bash b/src/version.bash
index 792814bac7..b2dabe4f7d 100755
--- a/src/version.bash
+++ b/src/version.bash
@@ -36,7 +36,7 @@ TAG=$(hg tags |\
 	grep $BRANCH |\
 	sed 's/:.*//' |\
 	sort -rn -k2 |\
-\tawk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\\./ {print $1}' |\
+\tawk -v ver=$VERSION '$2+0 <= ver+0 && $1~/^(release|weekly)\\./ {print $1}' |\
 	sed -n 1p)\
 \
 if [ "$TAG" != "" ]; then

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/38e37011fc739487b551dff7f1f6dab5e7abcde5

元コミット内容

このコミットは、src/version.bashファイルに対して1行の変更を加えています。具体的には、awkコマンド内でバージョン番号の比較を行う際に、文字列比較ではなく数値比較を強制するように修正しています。

変更前: awk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\\./ {print $1}'

変更後: awk -v ver=$VERSION '$2+0 <= ver+0 && $1~/^(release|weekly)\\./ {print $1}'

この変更により、$2verという変数が数値として評価され、例えば "9" が "10" よりも大きいと誤って判断されるような文字列比較の問題が解消されます。

変更の背景

このコミットは、Go言語のビルドプロセスで使用されるversion.bashスクリプトにおけるバグを修正するために行われました。コミットメッセージに「Fixes #2436」とあることから、GoプロジェクトのIssue 2436に関連する問題が原因です。

この問題は、version.bashスクリプトがバージョン番号を比較する際に、文字列として比較してしまうことに起因していました。例えば、バージョン番号が910の場合、文字列比較では"9""10"よりも大きいと判断されることがあります(辞書順比較のため)。しかし、数値としては910よりも小さいのが正しい挙動です。この誤った比較が、リリースバージョンやウィークリーバージョンのタグを正しく識別できない問題を引き起こしていました。

この修正は、バージョン比較のロジックを堅牢にし、将来的なバージョン番号の増加に対しても正確に動作するようにするために不可欠でした。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念について理解していると役立ちます。

  • Bashスクリプト: Unix系OSでコマンドを実行するためのスクリプト言語です。Go言語のビルドプロセスでは、様々な自動化タスクにBashスクリプトが利用されています。
  • Awk: テキスト処理に特化したプログラミング言語です。パターンマッチングとアクションの組み合わせで、テキストファイルからデータを抽出・変換するのに非常に強力です。このコミットでは、awkがバージョンタグのフィルタリングとソートに使用されています。
  • バージョン管理システム (Mercurial/Git): Goプロジェクトは元々Mercurial (hg) を使用していましたが、現在はGitに移行しています。hg tagsコマンドはMercurialのリポジトリからタグ情報を取得するために使用されます。タグは特定のコミットに付けられる名前で、リリースバージョンなどを識別するために使われます。
  • セマンティックバージョニング: ソフトウェアのバージョン番号付けの慣習で、MAJOR.MINOR.PATCHのような形式でバージョンを表現します。このコミットで扱われているバージョン番号も、このような数値的な比較が期待されるものです。
  • 文字列比較と数値比較: プログラミングにおいて、データ型によって比較の挙動が異なります。
    • 文字列比較: 文字列は辞書順(アルファベット順)で比較されます。例えば、"10" は "2" よりも小さいと判断されます。
    • 数値比較: 数値は数学的な大小関係で比較されます。例えば、10 は 2 よりも大きいと判断されます。 awkでは、変数を数値として扱うためには明示的な変換や演算が必要です。

技術的詳細

このコミットの核心は、awkコマンド内でのバージョン番号の比較方法の変更です。

元のコード: $2 <= ver

修正後のコード: $2+0 <= ver+0

ここで、$2hg tagsコマンドの出力から抽出されたバージョン番号(例: release.r60.1のようなタグから抽出された数値部分)、ver$VERSIONシェル変数から渡される現在のGoのバージョン番号です。

awkにおいて、変数の後ろに+0を付けるテクニックは、その変数を数値として強制的に評価させるための一般的なイディオムです。

  • $2+0: $2が文字列の場合でも、+0という数値演算を行うことで、awk$2の内容を数値として解釈しようとします。例えば、"9"9として、"10"10として扱われます。もし数値に変換できない文字列(例: "abc")であれば、0として扱われます。
  • ver+0: 同様に、ver変数も数値として強制的に評価されます。

この変更により、awkはバージョン番号を文字列としてではなく、数値として正しく比較するようになります。これにより、910よりも大きいと誤って判断されるような問題が解消され、version.bashスクリプトが常に正しいバージョンタグを選択できるようになります。

この修正は、Goのビルドシステムが依存する外部ツール(awk)の挙動を考慮し、堅牢なバージョン比較を実現するための典型的なアプローチと言えます。

コアとなるコードの変更箇所

変更はsrc/version.bashファイルの1行のみです。

--- a/src/version.bash
+++ b/src/version.bash
@@ -36,7 +36,7 @@ TAG=$(hg tags |\
 	grep $BRANCH |\
 	sed 's/:.*//' |\
 	sort -rn -k2 |\
-\tawk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\\./ {print $1}' |\
+\tawk -v ver=$VERSION '$2+0 <= ver+0 && $1~/^(release|weekly)\\./ {print $1}' |\
 	sed -n 1p)\
 \
 if [ "$TAG" != "" ]; then

具体的には、awkコマンドの条件式$2 <= ver$2+0 <= ver+0に変更されています。

コアとなるコードの解説

この変更は、Goのビルドプロセスにおいて、現在のバージョンに対応する適切なリリースまたはウィークリータグを特定するためのロジックの一部です。

TAG=$(hg tags | ...)の行は、Mercurialリポジトリからタグ情報を取得し、それをパイプで複数のコマンドに渡して処理しています。

  1. hg tags: リポジトリ内のすべてのタグをリストします。出力は通常、tagname: revisionのような形式です。
  2. grep $BRANCH: 現在のブランチに関連するタグのみをフィルタリングします。
  3. sed 's/:.*//': タグ名のみを抽出します(: revisionの部分を削除)。
  4. sort -rn -k2: タグを数値的に逆順ソートします。-k2は2番目のフィールド(この場合はバージョン番号の数値部分)をキーとしてソートすることを意味します。-rは逆順、-nは数値ソートです。
  5. awk -v ver=$VERSION '$2+0 <= ver+0 && $1~/^(release|weekly)\\./ {print $1}': ここが今回の修正箇所です。
    • -v ver=$VERSION: シェル変数$VERSIONの値をawkの内部変数verに渡します。
    • $2+0 <= ver+0: ここでバージョン番号の数値比較が行われます。$2sort -k2によってソートされた後の2番目のフィールド、つまりバージョン番号の数値部分です。+0を付けることで、文字列ではなく数値として比較されます。
    • $1~/^(release|weekly)\\./: 1番目のフィールド(タグ名全体)がrelease.またはweekly.で始まる正規表現にマッチするかどうかをチェックします。これにより、リリースまたはウィークリータグのみが対象となります。
    • {print $1}: 上記の条件を満たす行の1番目のフィールド(タグ名)を出力します。
  6. sed -n 1p: awkの出力の最初の行(つまり、条件を満たす中で最も新しいバージョンタグ)のみを取得します。

この一連の処理により、現在のGoのバージョンに対して、最も適切で最新のリリースまたはウィークリータグがTAG変数に設定されます。今回の修正は、このプロセスが常に正確な数値比較に基づいて行われることを保証するものです。

関連リンク

参考にした情報源リンク

  • awkの数値変換に関する情報: awkのドキュメントやチュートリアル(例: GNU Awk User's Guide)
  • Bashスクリプトの基本: Bashの公式ドキュメントやオンラインチュートリアル
  • Mercurialのタグ付け: Mercurialの公式ドキュメント
  • Go言語のビルドプロセスに関する一般的な情報: Goの公式ドキュメントやGoのソースコードのsrc/make.bashsrc/all.bashなどのスクリプト
  • Go Issue 2436に関する情報 (Gerrit Change-ID 5576075から辿れる可能性のある元のIssue): https://golang.org/issue/2436 (ただし、直接的な情報は見つかりませんでした。古いIssueはGerritの変更履歴に埋もれている可能性があります。)
  • https://golang.org/cl/5576075 (このコミットのGerritレビューページ)
  • https://github.com/golang/go/commit/38e37011fc739487b551dff7f1f6dab5e7abcde5 (GitHub上のコミットページ)