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

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

このコミットは、Go言語のVimプラグイン (misc/vim/ftplugin/go/test.sh) に含まれるテストスクリプトのクロスプラットフォーム互換性を改善するものです。具体的には、cmp(1) コマンドと grep -P コマンドがMac OS X以外の環境(特にFreeBSDやUbuntu Linux)で期待通りに動作しない問題を修正しています。これにより、テストスクリプトがより多くの環境で安定して実行できるようになります。

コミット

commit 27f7e3b2177b6968563fc85e61acd48540c48ab1
Author: Bill Thiede <couchmoney@gmail.com>
Date:   Tue May 14 09:54:16 2013 -0700

    misc/vim: test.sh seems to only work on Mac OS X.
    
    cmp(1) on FreeBSD requires two file arguments.  grep -P on Linux (at least
    Ubuntu 12.04) is described in the man page as "This is highly
    experimental" and doesn't seem to work. On FreeBSD the man page states
    "This option  is not supported in FreeBSD."  Needed this to work while
    debugging some funky behavior of 'Import' in my local vim setup.
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/7675043

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

https://github.com/golang/go/commit/27f7e3b2177b6968563fc85e61acd48540c48ab1

元コミット内容

このコミットの目的は、Go言語のVimプラグインのテストスクリプト test.sh がMac OS Xでのみ動作し、他のOSでは問題が発生する点を修正することです。具体的には、cmp(1) コマンドがFreeBSDで2つのファイル引数を要求すること、および grep -P コマンドがLinux (Ubuntu 12.04) で実験的であり、FreeBSDではサポートされていないことが問題として挙げられています。これらの互換性の問題を解決し、テストスクリプトが異なる環境でも正しく機能するようにすることが意図されています。

変更の背景

この変更の背景には、Go言語のVimプラグインのテストスクリプト test.sh が、特定のオペレーティングシステム(特にMac OS X)に依存した挙動を示していたという問題があります。コミットメッセージによると、作者が自身のVim環境で 'Import' 機能のデバッグ中に、このスクリプトがMac OS X以外で正しく動作しないことに気づいたとされています。

具体的には、以下の2つのコマンドの挙動が問題となっていました。

  1. cmp(1) コマンド:

    • Mac OS Xでは、gofmt test.go | cmp test.go のように、パイプからの標準入力とファイル引数を組み合わせて比較することが可能でした。
    • しかし、FreeBSDの cmp(1) コマンドは、比較対象として常に2つのファイル引数を必要とし、標準入力からの入力を直接受け付ける形式をサポートしていませんでした。このため、パイプからの出力を直接比較しようとするとエラーが発生していました。
  2. grep -P コマンド (Perl正規表現):

    • grep -P はPerl互換正規表現を使用するためのオプションです。
    • Linux (特にUbuntu 12.04) の grep マニュアルページでは、このオプションが「非常に実験的 (highly experimental)」であると記述されており、安定した動作が保証されていませんでした。
    • FreeBSDの grep マニュアルページでは、このオプションが「サポートされていない (not supported)」と明記されており、そもそも利用できませんでした。

これらのOS間の挙動の違いにより、test.sh スクリプトはMac OS X以外の環境でテストが失敗するか、実行自体が不可能になるという問題に直面していました。このコミットは、これらのプラットフォーム固有の問題を解決し、テストスクリプトの移植性と信頼性を向上させることを目的としています。

前提知識の解説

このコミットの変更内容を理解するためには、以下の技術的な概念やコマンドに関する知識が必要です。

  • シェルスクリプト (test.sh):

    • test.sh はシェルスクリプトであり、一連のコマンドを自動的に実行するためのプログラムです。Go言語のVimプラグインの機能が正しく動作するかを検証するために使用されます。
    • シェルスクリプトは、異なるOSやシェル環境(Bash, Zsh, Dashなど)によって、同じコマンドでも挙動が異なる場合があるため、クロスプラットフォーム互換性の問題が発生しやすい特性があります。
  • vim:

    • 高機能なテキストエディタ。このコミットでは、Vimのコマンドラインモード (-c) を使用して、特定のVimスクリプト (import.vim) をソースし、ファイル操作 (wq! test.go) を行っています。
    • ftplugin/go/: Vimのファイルタイププラグインのディレクトリ構造の一部で、Go言語ファイル (.go) を開いたときに自動的に読み込まれる設定やスクリプトが配置されます。
  • gofmt:

    • Go言語のソースコードを標準的なスタイルに自動整形するツールです。Go言語の公式ツールチェーンの一部であり、コードの可読性と一貫性を保つために広く利用されています。
    • gofmt test.gotest.go ファイルを整形し、その結果を標準出力に出力します。
  • cmp(1) コマンド:

    • cmp は "compare" の略で、2つのファイルをバイト単位で比較し、違いがあれば報告するUNIX系のコマンドです。
    • 通常、cmp file1 file2 のように2つのファイルパスを引数として取ります。
    • 一部のUNIX系システム(例: FreeBSD)では、標準入力からのデータを比較する際に、明示的に標準入力を示す特殊なファイル名(通常は -)を引数として指定する必要があります。
  • grep コマンド:

    • grep は "global regular expression print" の略で、ファイルの内容から正規表現にマッチする行を検索して表示するUNIX系のコマンドです。
    • -P オプション: Perl互換正規表現 (PCRE) を使用するためのオプションです。PCREは、より高度な正規表現機能(例: 非貪欲マッチ、後方参照、肯定/否定先読みなど)を提供しますが、すべての grep 実装でサポートされているわけではありません。
    • -q オプション: "quiet" の略で、マッチした行を標準出力に表示せず、終了ステータス(0: マッチあり、1: マッチなし)のみを返すオプションです。スクリプト内で条件分岐に利用されます。
    • (?s): Perl互換正規表現における「単一行モード」フラグです。これにより、ドット . が改行文字にもマッチするようになります。これは、複数行にまたがるパターンを検索する際に重要です。
  • シェルスクリプトの正規表現マッチ ([[ ... =~ ... ]]):

    • Bashなどのモダンなシェルでは、[[ ... ]] 構文内で =~ 演算子を使用して、文字列が正規表現にマッチするかどうかをテストできます。
    • この方法は、grep コマンドを外部プロセスとして呼び出すよりも効率的であり、また grep -P のような特定の grep 実装に依存する問題を回避できるため、クロスプラットフォーム互換性の高い選択肢となります。
    • $(cat test.go): test.go ファイルの内容を読み込み、その結果を文字列として [[ ... =~ ... ]] の左辺に渡します。

これらの知識が、コミットで行われた変更の意図と影響を深く理解する上で不可欠です。

技術的詳細

このコミットで行われた技術的な変更は、主にシェルスクリプトのコマンドの互換性問題を解決することに焦点を当てています。

  1. cmp コマンドの修正:

    • 変更前: if ! gofmt test.go | cmp test.go; then
      • この行は、gofmt test.go の出力(標準出力)と test.go ファイルの内容を比較していました。
      • Mac OS Xの cmp はこの形式を許容し、パイプからの標準入力を最初の比較対象として扱っていました。
    • 変更後: if ! gofmt test.go | cmp test.go -; then
      • 変更点: cmp test.go の後に - が追加されました。
      • この - は、多くのUNIX系コマンド(cmptarcat など)において「標準入力」を意味する慣例的な引数です。
      • FreeBSDの cmp(1) は、2つのファイル引数を明示的に要求するため、標準入力からのデータを比較する際には、このように - を指定して標準入力をファイルとして扱うように指示する必要があります。これにより、FreeBSD環境での cmp コマンドの互換性が確保されました。
  2. grep -P コマンドの修正:

    • 変更前: if ! grep -P -q "(?s)$2" test.go; then
      • この行は、test.go ファイルの内容に対して、変数 $2 で指定されたPerl互換正規表現 (-P) を使用して検索し、マッチするかどうか (-q) を確認していました。
      • (?s) フラグは、正規表現のドット . が改行文字にもマッチするように設定していました。
      • 前述の通り、grep -P はLinuxで実験的であり、FreeBSDではサポートされていませんでした。
    • 変更後: if ! [[ $(cat test.go) =~ $2 ]]; then
      • 変更点: grep -P -q ... の代わりに、Bashの拡張テスト構文 [[ ... =~ ... ]] が使用されました。
      • $(cat test.go): test.go ファイルの内容全体を読み込み、その結果を文字列として [[ ... =~ ... ]] の左辺に渡します。これにより、ファイル全体を単一の文字列として扱い、複数行にまたがる正規表現マッチを可能にしています。
      • =~: Bashの正規表現マッチ演算子です。右辺の $2 は正規表現として解釈されます。
      • この変更により、grep -P のプラットフォーム依存性(特にPerl互換正規表現エンジンの有無)が解消され、より多くのUNIX系システムで動作する標準的なシェル機能に置き換えられました。[[ ... =~ ... ]] はBashの機能であり、多くのLinuxディストリビューションやMac OS Xでデフォルトシェルとして使用されているBashで利用可能です。FreeBSDのデフォルトシェルはcshですが、Bashがインストールされていればこのスクリプトは動作します。

これらの変更は、シェルスクリプトの移植性を高めるための典型的なアプローチであり、特定のOSやツールのバージョンに依存する機能を、より標準的で広くサポートされている機能に置き換えることで、スクリプトの堅牢性を向上させています。

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

diff --git a/misc/vim/ftplugin/go/test.sh b/misc/vim/ftplugin/go/test.sh
index a6e31d8a3c..d8a5b89511 100755
--- a/misc/vim/ftplugin/go/test.sh
+++ b/misc/vim/ftplugin/go/test.sh
@@ -29,13 +29,13 @@ test_one() {\n   vim -e -s -u /dev/null -U /dev/null --noplugin -c "source import.vim" \\\n     -c "$1" -c 'wq! test.go' base.go\n   # ensure blank lines are treated correctly\n-  if ! gofmt test.go | cmp test.go; then\n+  if ! gofmt test.go | cmp test.go -; then
     echo 2>&1 "gofmt conflict"\n     gofmt test.go | diff -u test.go - | sed "s/^/\t/\" 2>&1\n     fail=1\n     return\n   fi\n-  if ! grep -P -q "(?s)$2" test.go; then\n+  if ! [[ $(cat test.go) =~ $2 ]]; then
     echo 2>&1 "$2 did not match"\n     cat test.go | sed "s/^/\t/\" 2>&1\n     fail=1\n```

## コアとなるコードの解説

このコミットでは、`misc/vim/ftplugin/go/test.sh` ファイル内の2つの主要な変更が行われています。

1.  **`cmp` コマンドの修正**:
    *   **変更前**: `if ! gofmt test.go | cmp test.go; then`
        *   `gofmt test.go` の出力(標準出力)と `test.go` ファイルの内容を比較していました。
        *   この形式は、Mac OS Xの `cmp` コマンドでは動作しましたが、FreeBSDの `cmp` コマンドは標準入力からのデータを受け取る際に、明示的に `-` を指定する必要がありました。
    *   **変更後**: `if ! gofmt test.go | cmp test.go -; then`
        *   `cmp` コマンドの引数に `-` が追加されました。この `-` は、多くのUNIX系コマンドにおいて「標準入力」を意味する特殊なファイル名です。
        *   これにより、`gofmt test.go` の標準出力が `cmp` コマンドの2番目の比較対象として正しく渡されるようになり、FreeBSDを含むより多くの環境で `cmp` が期待通りに動作するようになりました。この行は、`gofmt` による整形後にファイル内容が変更されていないことを確認するためのものです。

2.  **正規表現マッチングの修正**:
    *   **変更前**: `if ! grep -P -q "(?s)$2" test.go; then`
        *   `test.go` ファイル内で、変数 `$2` に格納された正規表現(Perl互換正規表現 `-P` と単一行モード `(?s)` を使用)にマッチする文字列が存在するかどうかを `grep` コマンドで確認していました。
        *   この `grep -P` オプションは、Linuxでは実験的であり、FreeBSDではサポートされていなかったため、クロスプラットフォーム互換性の問題がありました。
    *   **変更後**: `if ! [[ $(cat test.go) =~ $2 ]]; then`
        *   `grep` コマンドの代わりに、Bashの拡張テスト構文 `[[ ... =~ ... ]]` が使用されました。
        *   `$(cat test.go)` は、`test.go` ファイルの内容全体を読み込み、その結果を文字列として `[[ ... =~ ... ]]` の左辺に渡します。これにより、ファイル全体を単一の文字列として扱い、複数行にまたがる正規表現マッチを可能にしています。
        *   `=~` 演算子は、右辺の文字列を正規表現として解釈し、左辺の文字列がその正規表現にマッチするかどうかをテストします。
        *   この変更により、`grep -P` のプラットフォーム依存性が解消され、より広く利用されているBashの機能に置き換えられました。これにより、テストスクリプトの移植性が大幅に向上しました。この行は、Vimの操作によって期待される文字列が `test.go` に含まれていることを確認するためのものです。

これらの変更は、シェルスクリプトの堅牢性とクロスプラットフォーム互換性を高めるための典型的な修正であり、特定のOSやツールのバージョンに依存する挙動を、より標準的で広くサポートされている機能に置き換えることで、テストの信頼性を向上させています。

## 関連リンク

*   Go CL 7675043: [https://golang.org/cl/7675043](https://golang.org/cl/7675043)

## 参考にした情報源リンク

*   `cmp(1)` man page (FreeBSD): [https://www.freebsd.org/cgi/man.cgi?query=cmp&sektion=1](https://www.freebsd.org/cgi/man.cgi?query=cmp&sektion=1)
*   `grep(1)` man page (Linux/GNU grep): [https://man7.org/linux/man-pages/man1/grep.1.html](https://man7.org/linux/man-pages/man1/grep.1.html)
*   `grep(1)` man page (FreeBSD): [https://www.freebsd.org/cgi/man.cgi?query=grep&sektion=1](https://www.freebsd.org/cgi/man.cgi?query=grep&sektion=1)
*   Bash Conditional Expressions (`[[ ... ]]`): [https://www.gnu.org/software/bash/manual/bash.html#Conditional-Expressions](https://www.gnu.org/software/bash/manual/bash.html#Conditional-Expressions)
*   Bash Regular Expression Matching (`=~`): [https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions](https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions)
*   `gofmt` documentation: [https://go.dev/blog/gofmt](https://go.dev/blog/gofmt)
*   Vim documentation (filetype plugins): [https://vimhelp.org/filetype.txt.html#filetype-plugins](https://vimhelp.org/filetype.txt.html#filetype-plugins)