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

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

このコミットは、Go言語のディストリビューションツールの一部である misc/dist/bindist.go ファイルに対する変更です。このファイルは、Goのバイナリディストリビューションパッケージ、特にmacOS向けのインストーラーパッケージ(.pkgファイル)を生成する役割を担っています。変更の目的は、macOSパッケージがインストール時にシンボリックリンクを正しく追跡するようにすることです。

コミット

dist: make sure OS X packages follow symlinks when installing

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

https://github.com/golang/go/commit/28ac033b2ec29a86cd6b7b0f804272abee6d5f94

元コミット内容

dist: make sure OS X packages follow symlinks when installing

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

変更の背景

この変更の背景には、macOS向けのGoバイナリディストリビューションパッケージが、インストール時に含まれるシンボリックリンク(symlinks)を適切に処理できていなかったという問題があります。通常、ソフトウェアパッケージには、実際のファイルへのショートカットとしてシンボリックリンクが含まれることがあります。例えば、あるディレクトリ内のファイルが、別の場所にある実際のファイルを参照している場合などです。

PackageMaker はmacOSのインストーラーパッケージ(.pkg)を作成するためのツールですが、デフォルトの挙動では、パッケージ内のシンボリックリンクを「そのまま」コピーし、リンク先のファイルを追跡してインストール先に配置しない場合があります。これにより、インストールされたGo環境において、シンボリックリンクが正しく解決されず、特定のツールやライブラリが機能しないといった問題が発生する可能性がありました。

このコミットは、PackageMaker に対して、パッケージ作成時にシンボリックリンクを追跡し、そのリンク先の実際のファイルをパッケージに含めるように指示することで、この問題を解決しようとしています。

前提知識の解説

シンボリックリンクは、ファイルシステム上の別のファイルやディレクトリへの参照(ポインタ)として機能する特殊なファイルです。Windowsのショートカットに似ていますが、より低レベルでOSによって透過的に扱われることが多いです。シンボリックリンク自体は非常に小さく、参照先のパス情報のみを保持しています。

例えば、/usr/local/bin/go/usr/local/go/bin/go へのシンボリックリンクである場合、ユーザーが /usr/local/bin/go を実行すると、OSは自動的に /usr/local/go/bin/go を見つけて実行します。

macOSのパッケージ (.pkg) と PackageMaker

macOSでは、アプリケーションやシステムコンポーネントのインストールに .pkg 形式のパッケージが広く利用されます。これらのパッケージは、インストーラーアプリケーションによって展開され、指定された場所にファイルを配置します。

PackageMaker は、Appleが提供していた(現在は非推奨)開発者ツールの一部で、.pkg ファイルを作成するためのコマンドラインツールです。これを使用することで、開発者はアプリケーションやライブラリを配布可能なインストーラーとしてバンドルできます。PackageMaker は、パッケージに含めるファイル、インストール先、スクリプトなどを定義するための様々なオプションを提供します。

misc/dist/bindist.go の役割

Go言語のソースコードリポジトリにおける misc/dist/bindist.go ファイルは、Goの公式バイナリディストリビューションを構築するためのスクリプトの一部です。このファイルは、様々なオペレーティングシステム(macOS, Windows, Linuxなど)向けのGoバイナリパッケージを生成するロジックを含んでいます。具体的には、Goのコンパイル済みバイナリ、標準ライブラリ、ドキュメントなどを集約し、それぞれのOSに適した形式(macOSでは.pkg、Windowsでは.zipなど)で配布可能なアーカイブを作成します。

技術的詳細

このコミットの技術的な核心は、PackageMaker コマンドに --info オプションを導入し、PackageInfo というXML形式のファイルを通じて、パッケージ作成時の挙動をより詳細に制御することにあります。

従来の PackageMaker コマンドでは、--id, --version, --target などのオプションを直接指定していましたが、これではシンボリックリンクの追跡に関する設定ができませんでした。

変更後では、PackageMaker の実行前に createPackageInfo という新しい関数が呼び出されます。この関数は、一時的な PackageInfo XMLファイルを生成します。このXMLファイルには、以下の重要な属性が含まれています。

<pkg-info identifier="com.googlecode.go" version="1.0" followSymLinks="true">
    <payload installKBytes="%v" numberOfFiles="%v"/>
</pkg-info>

ここで最も重要なのは followSymLinks="true" 属性です。この属性を true に設定することで、PackageMaker はパッケージに含めるファイルを収集する際に、シンボリックリンクを単なる参照としてコピーするのではなく、そのリンクが指し示す実際のファイルを追跡し、パッケージのペイロード(実際にインストールされる内容)に含めるようになります。これにより、インストール後にシンボリックリンクが正しく解決され、Go環境が期待通りに機能することが保証されます。

createPackageInfo 関数は、パッケージに含めるファイルの総サイズ(installKBytes)とファイル数(numberOfFiles)も計算し、payload タグの属性としてXMLに埋め込みます。これらの情報は、インストーラーがユーザーに提供する情報(例: インストールに必要なディスク容量)として利用されます。

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

変更は misc/dist/bindist.go ファイルの func (b *Build) Do() error メソッド内のmacOSパッケージ作成ロジックに集中しています。

--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -240,6 +240,11 @@ func (b *Build) Do() error {
 			return err
 		}
 		// build package
+		pkginfo, err := createPackageInfo(work)
+		if err != nil {
+			return err
+		}
+		defer os.Remove(pkginfo)
 		pm := packageMaker
 		if !exists(pm) {
 			pm = "/Developer" + pm
@@ -252,11 +257,10 @@ func (b *Build) Do() error {
 		_, err = b.run("", pm, "-v",
 			"-r", work,
 			"-o", targ,
+			"--info", pkginfo,
 			"--scripts", scripts,
-			"--id", "com.googlecode.go",
 			"--title", "Go",
-			"--version", "1.0",
-			"--target", "10.6")
+			"--target", "10.5")
 		targs = append(targs, targ)
 	case "windows":
 		// Create ZIP file.
@@ -794,3 +798,30 @@ func tarFileInfoHeader(fi os.FileInfo, filename string) (*tar.Header, error) {
 	}
 	return h, nil
 }
+
+// createPackageInfo creates a PackageInfo template file for use with PackageMaker.
+// The returned filename points to a file in a temporary directory on the filesystem,
+// and should be removed after use.
+func createPackageInfo(work string) (filename string, err error) {
+	var size, nfiles int64
+	err = filepath.Walk(work, func(path string, info os.FileInfo, err error) error {
+		nfiles++
+		size += info.Size()
+		return nil
+	})
+	if err != nil {
+		return "", err
+	}
+	pi, err := ioutil.TempFile("", "PackageInfo")
+	if err != nil {
+		return "", err
+	}
+	defer pi.Close()
+	_, err = fmt.Fprintf(pi, "<pkg-info identifier=\"com.googlecode.go\" version=\"1.0\" followSymLinks=\"true\">\\n\"+\n+\t\t\"\\t<payload installKBytes=\\\"%v\\\" numberOfFiles=\\\"%v\\\"/>\\n\"+\n+\t\t\"</pkg-info>\\n\", size/1024, nfiles)
+	if err != nil {
+		return "", err
+	}
+	return pi.Name(), nil
+}

コアとなるコードの解説

createPackageInfo 関数

このコミットで新しく追加された createPackageInfo 関数は、PackageMaker が必要とする PackageInfo XMLファイルを動的に生成する役割を担っています。

  1. ディレクトリウォークと情報収集: filepath.Walk(work, ...) を使用して、パッケージ化されるディレクトリ(work)内のすべてのファイルとディレクトリを再帰的に走査します。この際、nfiles(ファイル数)と size(総バイトサイズ)を計算します。これらの情報は、PackageInfo XMLの payload タグに numberOfFilesinstallKBytes として埋め込まれます。

  2. 一時ファイルの作成: ioutil.TempFile("", "PackageInfo") を呼び出して、一時的なファイルを作成します。このファイルに生成されたXMLコンテンツが書き込まれます。関数が終了する際に defer os.Remove(pi) でこの一時ファイルが削除されるように設定されています。

  3. XMLコンテンツの書き込み: fmt.Fprintf を使用して、PackageInfo XMLの構造を文字列として一時ファイルに書き込みます。 特に注目すべきは、<pkg-info ... followSymLinks="true"> の部分です。これにより、PackageMaker はシンボリックリンクを追跡して、その実体をパッケージに含めるようになります。

  4. ファイル名の返却: 生成された一時ファイルのパスを返します。このパスは、後続の PackageMaker コマンドの --info オプションに渡されます。

Do() メソッド内の変更

Do() メソッドのmacOSパッケージ作成部分では、以下の変更が行われています。

  1. createPackageInfo の呼び出し: pkginfo, err := createPackageInfo(work) が追加され、PackageInfo XMLファイルが作成されます。エラーが発生した場合は、すぐに処理を中断します。

  2. 一時ファイルのクリーンアップ: defer os.Remove(pkginfo) が追加され、Do() メソッドの実行が終了する際に、生成された一時的な PackageInfo ファイルが確実に削除されるようにします。

  3. PackageMaker コマンドの変更: b.run を介して実行される PackageMaker コマンドの引数が変更されました。

    • --info, pkginfo が追加されました。これにより、PackageMaker は生成された PackageInfo XMLファイルから設定を読み込むようになります。
    • --id, com.googlecode.go および --version, 1.0 の直接指定が削除されました。これらの情報は PackageInfo XMLファイル内で定義されるため、コマンドライン引数としては不要になりました。
    • --target, 10.610.5 に変更されていますが、これはこのコミットの主要な目的とは直接関係なく、おそらくmacOSのターゲットバージョンを少し古いものに広げたものと考えられます。

これらの変更により、GoのmacOSインストーラーは、シンボリックリンクを含むファイルを正しくパッケージ化し、インストール時にそれらのリンクが適切に解決されるようになります。

関連リンク

参考にした情報源リンク

  • コミット情報: /home/orange/Project/comemo/commit_data/12806.txt
  • GitHubコミットページ: https://github.com/golang/go/commit/28ac033b2ec29a86cd6b7b0f804272abee6d5f94
  • Go言語のソースコード (misc/dist/bindist.go の当時のバージョン)
  • PackageMaker の挙動に関する一般的な知識 (Web検索を通じて得られた情報)
  • シンボリックリンクに関する一般的な知識 (Web検索を通じて得られた情報)
  • XMLの基本構造に関する知識