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

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

このコミットは、Go言語のダッシュボードビルダ(gobuilder、後にbuilderに名称変更)が、Mercurial(hg)のリポジトリ設定ファイルである.hgrccodereviewプラグインが有効になっている環境でも正しく動作するように修正するものです。具体的には、Mercurialコマンドの実行時に、codereviewプラグインによる干渉を避けるための設定を明示的に追加しています。

コミット

commit a84056dabe8ce3178879db7416365a2d841bff0a
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Mon Apr 2 18:46:24 2012 +0800

    gobuilder: work with codereview plugin enabled in .hgrc
            Fixes #3312.
    
    R=golang-dev, adg
    CC=golang-dev
    https://golang.org/cl/5907065

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

https://github.com/golang/go/commit/a84056dabe8ce3178879db7416365a2d841bff0a

元コミット内容

gobuilder: work with codereview plugin enabled in .hgrc
        Fixes #3312.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5907065

変更の背景

この変更の背景には、Go言語のビルドシステム(特にダッシュボードのビルダ部分)がMercurialリポジトリと連携する際に発生していた問題があります。Mercurialには、コードレビュープロセスを支援するためのcodereviewという拡張機能(プラグイン)が存在します。このプラグインがユーザーの.hgrc(Mercurialの設定ファイル)で有効になっている場合、通常のMercurialコマンド(pull, clone, update, logなど)の動作に影響を与え、gobuilderが期待通りにリポジトリ操作を行えない状況が発生していました。

具体的には、codereviewプラグインは、Mercurialコマンドの出力や動作をフックして、コードレビューに関連する情報を追加したり、特定のレビューワークフローを強制したりすることがあります。gobuilderは、自動化された環境でMercurialコマンドをプログラム的に実行するため、このようなプラグインによる予期せぬ干渉は、ビルドプロセスの失敗や誤動作を引き起こす可能性がありました。

このコミットは、Issue #3312("gobuilder: work with codereview plugin enabled in .hgrc")を解決するために作成されました。この問題は、gobuilderがMercurialリポジトリからコードを取得したり、特定のコミットに更新したりする際に、codereviewプラグインが有効になっている環境でエラーが発生するというものでした。

前提知識の解説

Go言語のビルドシステムとダッシュボード

Go言語プロジェクトでは、継続的な統合(CI)とテストのために、ビルドダッシュボードが運用されています。このダッシュボードは、様々なプラットフォームや環境でGoのコードをビルドし、テストを実行する役割を担っています。gobuilder(後にbuilderに改名)は、このダッシュボードの一部として、Mercurialリポジトリからソースコードを取得し、ビルドプロセスを実行するエージェントのようなものです。

Mercurial (hg)

Mercurialは、分散型バージョン管理システム(DVCS)の一つで、Gitと同様にコードの変更履歴を管理するために使用されます。Go言語プロジェクトは、初期にはMercurialを主要なバージョン管理システムとして採用していました(後にGitに移行)。Mercurialコマンドは、hg pull(リモートリポジトリから変更を取得)、hg clone(リポジトリを複製)、hg update(特定のバージョンに作業コピーを更新)、hg log(コミット履歴を表示)などがあります。

.hgrcファイル

.hgrcはMercurialの設定ファイルで、ユーザーごとの設定やリポジトリ固有の設定を記述するために使用されます。このファイルには、ユーザー名、エイリアス、拡張機能(プラグイン)の有効化など、様々な設定を記述できます。

Mercurial拡張機能(プラグイン)

Mercurialは、拡張機能(プラグイン)の仕組みを持っており、ユーザーはこれらを有効にすることでMercurialの機能を拡張したり、カスタマイズしたりできます。拡張機能はPythonで記述され、.hgrcファイルで[extensions]セクションに記述することで有効化されます。

codereviewプラグイン

codereviewプラグインは、Mercurialの拡張機能の一つで、コードレビュープロセスをMercurialのワークフローに統合するために使用されます。このプラグインは、コミットメッセージのフォーマットを強制したり、レビューコメントをMercurialの変更セットに紐付けたりするなど、様々な機能を提供します。しかし、その動作はMercurialコマンドの標準的な出力や挙動に影響を与える可能性があり、自動化されたスクリプトがMercurialを操作する際には問題となることがあります。

--configオプション

Mercurialコマンドには、--configオプションがあり、一時的に設定値を上書きすることができます。これは、特定のコマンド実行時のみ、.hgrcファイルの設定を無視したり、異なる設定を適用したりする場合に便利です。

技術的詳細

このコミットの主要な技術的変更は、Mercurialコマンドを実行する際に、--config extensions.codereview=!というオプションを明示的に追加することです。

--config extensions.codereview=!の意味は以下の通りです。

  • --config: Mercurialの設定を一時的に変更するためのオプション。
  • extensions.codereview: codereviewという名前の拡張機能に関する設定。
  • !: これは、指定された拡張機能を無効にするための特殊な値です。つまり、codereview拡張機能が.hgrcで有効になっていたとしても、このコマンド実行時には無効化されます。

これにより、gobuilderがMercurialコマンドを実行する際に、codereviewプラグインによる予期せぬ干渉を回避し、Mercurialの標準的な動作を保証できるようになります。

この変更は、misc/dashboard/builder/main.goファイル内のMercurialコマンド呼び出し箇所すべてに適用されています。具体的には、hgCmdというヘルパー関数が導入され、すべてのMercurialコマンドがこの関数を介して実行されるようになりました。hgCmd関数は、渡された引数の前に"hg", "--config", "extensions.codereview=!"を追加して、完全なコマンドライン引数リストを構築します。

また、misc/dashboard/builder/Makefileでは、ビルド成果物の名前がgobuilderからbuilderに変更されています。これは、機能的な変更ではなく、命名規則の整理や簡素化の一環と考えられます。

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

misc/dashboard/builder/Makefile

--- a/misc/dashboard/builder/Makefile
+++ b/misc/dashboard/builder/Makefile
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
-gobuilder: $(shell ls *.go)
-	go build -o $@ $^
+builder: $(shell ls *.go)
+	go build -o $@ $^
 
 clean:
-	rm -f gobuilder
+	rm -f builder

misc/dashboard/builder/main.go

--- a/misc/dashboard/builder/main.go
+++ b/misc/dashboard/builder/main.go
@@ -220,7 +220,7 @@ func (b *Builder) build() bool {
 	// Look for hash locally before running hg pull.
 	if _, err := fullHash(goroot, hash[:12]); err != nil {
 		// Don't have hash, so run hg pull.
-		if err := run(nil, goroot, "hg", "pull"); err != nil {
+		if err := run(nil, goroot, hgCmd("pull")...); err != nil {
 			log.Println("hg pull failed:", err)
 			return false
 		}
@@ -243,12 +243,12 @@ func (b *Builder) buildHash(hash string) error {
 	defer os.RemoveAll(workpath)
 
 	// clone repo
-	if err := run(nil, workpath, "hg", "clone", goroot, "go"); err != nil {
+	if err := run(nil, workpath, hgCmd("clone", goroot, "go")...); err != nil {
 		return err
 	}
 
 	// update to specified revision
-	if err := run(nil, filepath.Join(workpath, "go"), "hg", "update", hash); err != nil {
+	if err := run(nil, filepath.Join(workpath, "go"), hgCmd("update", hash)...); err != nil {
 		return err
 	}
 
@@ -369,7 +369,7 @@ func (b *Builder) buildSubrepo(goRoot, pkg, hash string) (string, error) {
 
 	// hg update to the specified hash
 	pkgPath := filepath.Join(goRoot, "src/pkg", pkg)
-	if err := run(nil, pkgPath, "hg", "update", hash); err != nil {
+	if err := run(nil, pkgPath, hgCmd("update", hash)...); err != nil {
 		return "", err
 	}
 
@@ -475,7 +475,7 @@ func commitWatcher() {
 }
 
 func hgClone(url, path string) error {
-	return run(nil, *buildroot, "hg", "clone", url, path)
+	return run(nil, *buildroot, hgCmd("clone", url, path)...)
 }
 
 func hgRepoExists(path string) bool {
@@ -532,17 +532,17 @@ func commitPoll(key, pkg string) {
 		}
 	}
 
-	if err := run(nil, pkgRoot, "hg", "pull"); err != nil {
+	if err := run(nil, pkgRoot, hgCmd("pull")...); err != nil {
 		log.Printf("hg pull: %v", err)
 		return
 	}
 
 	const N = 50 // how many revisions to grab
 
-	data, _, err := runLog(nil, "", pkgRoot, "hg", "log",
+	data, _, err := runLog(nil, "", pkgRoot, hgCmd("log",
 		"--encoding=utf-8",
 		"--limit="+strconv.Itoa(N),
-		"--template="+xmlLogTemplate,
+		"--template="+xmlLogTemplate)...,
 	)
 	if err != nil {
 		log.Printf("hg log: %v", err)
@@ -628,11 +628,11 @@ func addCommit(pkg, hash, key string) bool {
 // fullHash returns the full hash for the given Mercurial revision.
 func fullHash(root, rev string) (string, error) {
 	s, _, err := runLog(nil, "", root,
-		"hg", "log",
-		"--encoding=utf-8",
-		"--rev="+rev,
-		"--limit=1",
-		"--template={node}",
+		hgCmd("log",
+			"--encoding=utf-8",
+			"--rev="+rev,
+			"--limit=1",
+			"--template={node}")...),
 	)
 	if err != nil {
 		return "", nil
@@ -681,3 +681,7 @@ func getenvOk(k string) (v string, ok bool) {
 	}
 	return "", false
 }\n+
+func hgCmd(args ...string) []string {\n+\treturn append([]string{"hg", "--config", "extensions.codereview=!"}, args...)\n+}\n

コアとなるコードの解説

misc/dashboard/builder/Makefileの変更

  • gobuilderというターゲット名がbuilderに変更されました。これは、ビルドされる実行ファイルの名前もgobuilderからbuilderに変わることを意味します。cleanターゲットも同様にrm -f gobuilderからrm -f builderに変更されています。これは機能的な変更ではなく、命名規則の統一や簡素化を目的としたものです。

misc/dashboard/builder/main.goの変更

  1. hgCmd関数の追加:

    func hgCmd(args ...string) []string {
        return append([]string{"hg", "--config", "extensions.codereview=!"}, args...)
    }
    

    この新しいヘルパー関数が、このコミットの核心です。

    • args ...string: 可変長引数として、本来のMercurialコマンドの引数(例: pull, clone, update, logとそのオプション)を受け取ります。
    • append([]string{"hg", "--config", "extensions.codereview=!"}, args...):
      • "hg": Mercurialコマンド自体。
      • "--config": Mercurialの設定を一時的に上書きするためのオプション。
      • "extensions.codereview=!": codereview拡張機能を無効にする設定。!は拡張機能を無効にするためのMercurialの構文です。
      • この3つの要素の後に、元のMercurialコマンドの引数が追加され、新しいスライス(文字列の配列)として返されます。
  2. Mercurialコマンド呼び出しの変更: main.go内の既存のMercurialコマンド呼び出し(hg pull, hg clone, hg update, hg log)がすべてhgCmd関数を使用するように変更されました。

    変更前:

    run(nil, goroot, "hg", "pull")
    run(nil, workpath, "hg", "clone", goroot, "go")
    run(nil, filepath.Join(workpath, "go"), "hg", "update", hash)
    run(nil, pkgPath, "hg", "update", hash)
    run(nil, *buildroot, "hg", "clone", url, path)
    run(nil, pkgRoot, "hg", "pull")
    runLog(nil, "", pkgRoot, "hg", "log", ...)
    runLog(nil, "", root, "hg", "log", ...)
    

    変更後:

    run(nil, goroot, hgCmd("pull")...)
    run(nil, workpath, hgCmd("clone", goroot, "go")...)
    run(nil, filepath.Join(workpath, "go"), hgCmd("update", hash)...)
    run(nil, pkgPath, hgCmd("update", hash)...)
    run(nil, *buildroot, hgCmd("clone", url, path)...)
    run(nil, pkgRoot, hgCmd("pull")...)
    runLog(nil, "", pkgRoot, hgCmd("log", ...)...)
    runLog(nil, "", root, hgCmd("log", ...)...)
    

    ...(スプレッド演算子)は、hgCmd関数が返す文字列スライスをrunまたはrunLog関数の可変長引数として展開するために使用されます。

この変更により、gobuilderがMercurialコマンドを実行する際に、ユーザーの.hgrcファイルでcodereviewプラグインが有効になっていても、その影響を受けずに安定して動作することが保証されます。これは、自動化されたビルド環境の堅牢性を高める上で重要な修正です。

関連リンク

参考にした情報源リンク