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

[インデックス 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 ファイルに変更を加えています。

  1. 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の場合は HOMEDRIVEHOMEPATH 環境変数を使用してホームディレクトリを正しく構築するように変更されました。これにより、WindowsユーザーがGoビルドシステムに認証情報を提供できるようになります。
  2. misc/dist/windows/README.txt の変更点:

    • Windowsビルドの依存関係リストに - 7zip が追加されました。これは、ZIPファイル生成のために 7z コマンドラインツールが必要になったことを明示しています。

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

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-InstallerType-Archive といったラベルを付与することで、アップロードされた成果物の管理と識別が容易になります。
    • readCredentials におけるWindowsホームディレクトリの解決: runtime.GOOS == "windows" のチェックと HOMEDRIVE + HOMEPATH の使用は、Windows環境でユーザーのホームディレクトリを正確に特定するための標準的な方法です。これにより、Goビルドシステムが認証情報ファイル(.gobuildkey)を正しく見つけられるようになります。
  • misc/dist/windows/README.txt:

    • - 7zip の追加: この変更は、WindowsでGoをビルドする際に 7z ツールが新たな依存関係として必要になったことを開発者に明確に伝えます。これは、ビルド環境のセットアップ手順に直接影響します。

これらの変更により、Go言語のWindows向けディストリビューションは、より柔軟でユーザーフレンドリーな形式(ZIP)を提供できるようになり、同時にビルドプロセスの堅牢性と管理性が向上しました。

関連リンク

参考にした情報源リンク