[インデックス 12537] ファイルの概要
このコミットは、Go言語のディストリビューションツール (misc/dist
) において、Windows環境向けにZIPアーカイブの生成機能を追加し、既存のMSIインストーラ生成プロセスを改善するものです。これにより、WindowsユーザーはMSIインストーラだけでなく、より手軽に利用できるZIP形式のGoバイナリディストリビューションも入手できるようになります。
コミット
commit 08a5d7394054a4cb08e99f6bea0c007aed999a67
Author: Andrew Gerrand <adg@golang.org>
Date: Fri Mar 9 12:57:38 2012 +1100
misc/dist: produce a zip file under windows
Updates #3254.
R=golang-dev, bradfitz, alex.brainman
CC=golang-dev
https://golang.org/cl/5783058
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/08a5d7394054a4cb08e99f6bea0c007aed999a67
元コミット内容
このコミットは、Windows環境でのGo言語バイナリディストリビューションの作成方法を更新し、MSIインストーラに加えてZIPファイルを生成するように変更します。また、関連するビルドスクリプトと依存関係の調整も行われています。
変更の背景
この変更は、Go言語のIssue #3254 に対応するものです。当時のGo言語のWindows向けディストリビューションはMSIインストーラ形式のみが提供されていました。しかし、MSIインストーラは管理者権限が必要であったり、特定の環境ではインストールが困難であったりする場合があります。
多くのWindowsユーザーは、ソフトウェアをインストールする際に、単にファイルを展開するだけで利用できるZIPアーカイブ形式を好む傾向にあります。これは、ポータビリティが高く、管理者権限なしで利用できるため、開発環境のセットアップを簡素化する上で非常に有用です。
このコミットの目的は、WindowsユーザーがGo言語をより簡単に導入・利用できるように、MSIインストーラに加えてZIPアーカイブ形式のディストリビューションを提供することにあります。これにより、ユーザーの利便性が向上し、Go言語の普及に貢献することが期待されます。
前提知識の解説
- Go言語のビルドとディストリビューション: Go言語は、
go build
コマンドによって実行可能なバイナリを生成します。このバイナリは、特定のOSとアーキテクチャ向けにクロスコンパイルすることも可能です。misc/dist
ディレクトリ内のスクリプトは、これらのバイナリをパッケージ化し、配布可能な形式(インストーラやアーカイブ)にまとめる役割を担っています。 - クロスコンパイル: Go言語の大きな特徴の一つに、異なるオペレーティングシステムやCPUアーキテクチャ向けの実行ファイルを生成できるクロスコンパイル機能があります。例えば、Linux上でWindows向けの実行ファイルをビルドすることが可能です。
- アーカイブ形式:
.tar.gz
: 主にUnix系OSで広く使われるアーカイブ形式です。複数のファイルを一つのアーカイブにまとめ、gzipで圧縮します。.zip
: 主にWindowsで広く使われるアーカイブ形式です。複数のファイルを一つのアーカイブにまとめ、圧縮します。
- インストーラ形式:
.pkg
: macOSでアプリケーションをインストールするためのパッケージ形式です。.msi
: Windows Installerによって使用されるパッケージ形式で、Windowsアプリケーションのインストール、メンテナンス、削除を管理します。
- 環境変数:
HOME
: Unix系OSでユーザーのホームディレクトリを示す環境変数です。HOMEDRIVE
,HOMEPATH
: Windowsでユーザーのホームディレクトリを示すために使用される環境変数です。HOMEDRIVE
はドライブレター(例:C:
)、HOMEPATH
はドライブ内のパス(例:\Users\username
)を示します。
filepath
パッケージ (Go): Go言語の標準ライブラリで、ファイルパスの操作(結合、分割、パターンマッチングなど)を提供します。filepath.Join
: 複数のパス要素をOS固有の区切り文字で結合します。filepath.Glob
: 指定されたパターンに一致するファイルパスを検索します。
os/exec
パッケージ (Go): Go言語の標準ライブラリで、外部コマンドを実行するための機能を提供します。runtime
パッケージ (Go): Go言語の標準ライブラリで、Goランタイム環境に関する情報(例: 実行中のOS、CPUアーキテクチャ)を提供します。runtime.GOOS
は現在のOS名(例: "windows", "linux", "darwin")を返します。- 7-Zip: 高い圧縮率を誇るオープンソースのファイルアーカイバです。コマンドラインツール
7z
を使用して、様々なアーカイブ形式(ZIP、7z、tarなど)の作成と展開が可能です。このコミットでは、Windows環境でZIPファイルを作成するために7z
コマンドが利用されています。
技術的詳細
このコミットは、主に misc/dist/bindist.go
ファイルと misc/dist/windows/README.txt
ファイルに変更を加えています。
-
misc/dist/bindist.go
の変更点:runtime
パッケージのインポート:runtime
パッケージが新しくインポートされました。これは、実行中のOSを判別し、Windows固有の処理を条件分岐させるために使用されます。filepath.Glob
パターンの更新:- 変更前:
pat := filepath.Join(b.root, "pkg/tool/*/dist")
- 変更後:
pat := filepath.Join(b.root, "pkg/tool/*/dist*") // trailing * for .exe
- この変更により、
filepath.Glob
はWindows環境で実行ファイルに付与される.exe
拡張子を持つdist.exe
も正しくマッチするようになります。
- 変更前:
- Windows向けZIPファイル生成ロジックの追加:
switch b.OS
文のcase "windows":
ブロック内に、ZIPファイルを生成する新しいコードが追加されました。zip := filepath.Join(work, base+".zip")
でZIPファイルのパスを構築します。_, err = b.run(work, "7z", "a", "-tzip", zip, "go")
を使用して、7z
コマンドラインツールを呼び出し、go
ディレクトリの内容をzip
ファイルにアーカイブします。ここで7z
が外部依存として導入されます。- 生成されたZIPファイルを最終的なターゲットパスにコピーし、
targs
スライスに追加します。
- 複数成果物アップロードの対応:
- 以前は、生成された単一の成果物 (
targ
) のみをアップロードしていましたが、この変更によりtargs
スライスに格納されたすべての成果物(ZIP、MSIなど)をループで処理し、それぞれをアップロードするように変更されました。
- 以前は、生成された単一の成果物 (
- アップロード時のラベルとサマリーの改善:
upload
関数内で、Windows向けの成果物に対して、ファイル拡張子(.msi
または.zip
)に基づいて、より具体的なラベル(Type-Installer
またはType-Archive
)とサマリーを追加するロジックが導入されました。これにより、アップロードされたファイルの種別が明確になります。
- Windowsでのホームディレクトリ解決の修正:
readCredentials
関数内で、.gobuildkey
ファイルのパスを決定する際に、Windows環境でのホームディレクトリの取得方法が修正されました。runtime.GOOS == "windows"
の条件分岐が追加され、Windowsの場合はHOMEDRIVE
とHOMEPATH
環境変数を使用してホームディレクトリを正しく構築するように変更されました。これにより、WindowsユーザーがGoビルドシステムに認証情報を提供できるようになります。
-
misc/dist/windows/README.txt
の変更点:- Windowsビルドの依存関係リストに
- 7zip
が追加されました。これは、ZIPファイル生成のために7z
コマンドラインツールが必要になったことを明示しています。
- Windowsビルドの依存関係リストに
コアとなるコードの変更箇所
misc/dist/bindist.go
--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -21,6 +21,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
)
@@ -126,7 +127,7 @@ func (b *Build) Do() error {
version string // "weekly.2012-03-04"
fullVersion []byte // "weekly.2012-03-04 9353aa1efdf3"
)
- pat := filepath.Join(b.root, "pkg/tool/*/dist")
+ pat := filepath.Join(b.root, "pkg/tool/*/dist*") // trailing * for .exe
m, err := filepath.Glob(pat)
if err != nil {
return err
@@ -158,15 +159,17 @@ func (b *Build) Do() error {
}
// Create packages.
- targ := fmt.Sprintf("go.%s.%s-%s", version, b.OS, b.Arch)
+ base := fmt.Sprintf("go.%s.%s-%s", version, b.OS, b.Arch)
+ var targs []string
switch b.OS {
case "linux", "freebsd", "":
// build tarball
+ targ := base + ".tar.gz"
if b.Source {
targ = fmt.Sprintf("go.%s.src", version)
}
- targ += ".tar.gz"
_, err = b.run("", "tar", "czf", targ, "-C", work, "go")
+ targs = append(targs, targ)
case "darwin":
// arrange work so it's laid out as the dest filesystem
etc := filepath.Join(b.root, "misc/dist/darwin/etc")
@@ -191,7 +194,7 @@ func (b *Build) Do() error {
return errors.New("couldn't find PackageMaker")
}
}
- targ += ".pkg"
+ targ := base + ".pkg"
scripts := filepath.Join(work, "usr/local/go/misc/dist/darwin/scripts")
_, err = b.run("", pm, "-v",
"-r", work,
@@ -201,7 +204,20 @@ func (b *Build) Do() error {
"--title", "Go",
"--version", "1.0",
"--target", "10.5")
+ targs = append(targs, targ)
case "windows":
+ // Create ZIP file.
+ zip := filepath.Join(work, base+".zip")
+ _, err = b.run(work, "7z", "a", "-tzip", zip, "go")
+ // Copy zip to target file.
+ targ := base + ".zip"
+ err = cp(targ, zip)
+ if err != nil {
+ return err
+ }
+ targs = append(targs, targ)
+
+ // Create MSI installer.
win := filepath.Join(b.root, "misc/dist/windows")
installer := filepath.Join(win, "installer.wxs")
appfiles := filepath.Join(work, "AppFiles.wxs")
@@ -240,11 +256,17 @@ func (b *Build) Do() error {
return err
}
// Copy installer to target file.
- targ += ".msi"
+ targ = base + ".msi"
err = cp(targ, msi)
+ targs = append(targs, targ)
}
if err == nil && password != "" {
- err = b.upload(version, targ)
+ for _, targ := range targs {
+ err = b.upload(version, targ)
+ if err != nil {
+ return err
+ }
+ }
}
return err
}
@@ -322,9 +344,19 @@ func (b *Build) upload(version string, filename string) error {
labels = append(labels, "Type-Installer", "OpSys-OSX")
case "windows":
os_ = "Windows"
- labels = append(labels, "Type-Installer", "OpSys-Windows")
+ labels = append(labels, "OpSys-Windows")
}
summary := fmt.Sprintf("Go %s %s (%s)", version, os_, arch)
+ if b.OS == "windows" {
+ switch {
+ case strings.HasSuffix(filename, ".msi"):
+ labels = append(labels, "Type-Installer")
+ summary += " MSI installer"
+ case strings.HasSuffix(filename, ".zip"):
+ labels = append(labels, "Type-Archive")
+ summary += " ZIP archive"
+ }
+ }
if b.Source {
labels = append(labels, "Type-Source")
summary = fmt.Sprintf("Go %s (source only)", version)
@@ -398,7 +430,11 @@ func exists(path string) bool {
}
func readCredentials() error {
- name := filepath.Join(os.Getenv("HOME"), ".gobuildkey")
+ name := os.Getenv("HOME")
+ if runtime.GOOS == "windows" {
+ name = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+ }
+ name = filepath.Join(name, ".gobuildkey")
f, err := os.Open(name)
if err != nil {
return err
misc/dist/windows/README.txt
--- a/misc/dist/windows/README.txt
+++ b/misc/dist/windows/README.txt
@@ -4,6 +4,7 @@ Windows build dependencies
- Mercurial (hg): http://mercurial.selenic.com/
- MinGW: http://www.mingw.org/
- Windows Installer XML (WiX) toolset: http://wix.sourceforge.net/
+- 7zip
Packaging
コアとなるコードの解説
-
misc/dist/bindist.go
:import "runtime"
:runtime
パッケージの追加は、Goプログラムが実行されているオペレーティングシステムを動的に検出するために不可欠です。これにより、Windows固有のパス解決やパッケージングロジックを適用できます。filepath.Glob
パターンの変更 (dist
->dist*
): Windowsの実行ファイルは通常.exe
拡張子を持つため、dist.exe
のようなファイルも正しく検出できるようにパターンが拡張されました。これは、ビルドプロセスがGoツールチェーン内の適切な実行可能ファイルを見つけるために重要です。case "windows":
ブロック内のZIPファイル生成:b.run(work, "7z", "a", "-tzip", zip, "go")
: この行が、GoディストリビューションのZIPアーカイブを作成する核心部分です。7z
コマンドラインツールを呼び出し、go
ディレクトリの内容をbase.zip
という名前のZIPファイルに圧縮します。7z
は外部ツールであるため、Windowsビルド環境にインストールされている必要があります。targs = append(targs, targ)
: 生成されたZIPファイルのパスがtargs
スライスに追加されます。これにより、後続のアップロード処理でZIPファイルも対象となるようになります。
- アップロードループ (
for _, targ := range targs
): 以前は単一の成果物しかアップロードしていませんでしたが、このループの導入により、ZIPファイルとMSIインストーラの両方、あるいは将来的に追加される可能性のある他の成果物も確実にアップロードされるようになります。 - アップロード時のラベル付けロジック:
strings.HasSuffix(filename, ".msi")
やstrings.HasSuffix(filename, ".zip")
を用いてファイルの種類を判別し、適切なType-Installer
やType-Archive
といったラベルを付与することで、アップロードされた成果物の管理と識別が容易になります。 readCredentials
におけるWindowsホームディレクトリの解決:runtime.GOOS == "windows"
のチェックとHOMEDRIVE + HOMEPATH
の使用は、Windows環境でユーザーのホームディレクトリを正確に特定するための標準的な方法です。これにより、Goビルドシステムが認証情報ファイル(.gobuildkey
)を正しく見つけられるようになります。
-
misc/dist/windows/README.txt
:- 7zip
の追加: この変更は、WindowsでGoをビルドする際に7z
ツールが新たな依存関係として必要になったことを開発者に明確に伝えます。これは、ビルド環境のセットアップ手順に直接影響します。
これらの変更により、Go言語のWindows向けディストリビューションは、より柔軟でユーザーフレンドリーな形式(ZIP)を提供できるようになり、同時にビルドプロセスの堅牢性と管理性が向上しました。
関連リンク
- Go Issue #3254: https://github.com/golang/go/issues/3254 (このコミットが解決したIssue)
- Gerrit Change-ID (CL) 5783058: https://golang.org/cl/5783058 (Goプロジェクトのコードレビューシステムにおけるこの変更のページ)
参考にした情報源リンク
- 7-Zip 公式サイト: https://www.7-zip.org/
- Go言語
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語
path/filepath
パッケージドキュメント: https://pkg.go.dev/path/filepath - Go言語
runtime
パッケージドキュメント: https://pkg.go.dev/runtime - Windows環境変数
HOMEDRIVE
とHOMEPATH
に関する情報 (Microsoft Learnなど): https://learn.microsoft.com/ja-jp/windows/win32/shell/csidl (CSIDL定数の一部として説明されている場合があります) - Go言語のクロスコンパイルに関する公式ドキュメントやブログ記事 (Go公式ブログなど)