[インデックス 10442] ファイルの概要
このコミットは、Go言語の実験的なexp/terminalパッケージにおけるビルドエラーを修正し、将来的な同様のビルド失敗を早期に検出するために、Linuxビルドにexp/terminalパッケージを含めるように変更を加えたものです。具体的には、os.Errnoの変更に伴うエラーハンドリングの修正と、Makefileの更新が含まれています。
コミット
- コミットハッシュ:
558d055352747b2a2b5329ece9fa8ddb3c4ed999 - 作者: Gustavo Niemeyer gustavo@niemeyer.net
- コミット日時: Fri Nov 18 01:12:57 2011 -0200
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/558d055352747b2a2b5329ece9fa8ddb3c4ed999
元コミット内容
exp/terminal: fix build after os.Errno changes
Also include exp/terminal in linux build so such failures
are noticed.
R=rsc
CC=golang-dev
https://golang.org/cl/5416044
変更の背景
このコミットの主な背景は、Go言語の標準ライブラリにおけるエラーハンドリングの変更、特にos.Errnoの扱いに関する変更です。Go言語の初期のバージョンでは、システムコールから返されるエラーはsyscall.Errno型であり、これをos.Errno型にラップして利用するパターンが見られました。しかし、Go言語のエラーハンドリングの設計が進化するにつれて、より汎用的なerrorインターフェースを直接利用する方向へと移行しました。
この変更により、syscallパッケージの関数が直接errorインターフェースを返すようになり、以前os.Errno(e)のようにsyscall.Errnoをos.Errnoに変換していたコードがビルドエラーを起こすようになりました。exp/terminalパッケージは、ターミナル操作のために低レベルのシステムコール(syscall.Syscall6など)を多用しており、このos.Errnoの変更の影響を直接受けました。
また、このコミットは、exp/terminalパッケージがLinuxビルドに含まれていなかったため、このようなビルドエラーがすぐに発見されなかったという問題も指摘しています。そのため、将来的に同様の互換性の問題が発生した場合に早期に検出できるよう、Makefileを修正してLinuxビルドにexp/terminalを含めるようにしました。
前提知識の解説
exp/terminalパッケージ: Go言語の実験的なパッケージで、ターミナル(端末)の低レベルな操作、例えばエコーなしのパスワード入力や、ターミナルの生モード(raw mode)への切り替えなどを提供します。これは、標準入出力が通常のファイルではなく、ターミナルデバイスである場合に特に有用です。syscallパッケージ: オペレーティングシステムのシステムコールへの低レベルなインターフェースを提供します。Goプログラムから直接OSの機能(ファイル操作、プロセス管理、ネットワーク通信など)を呼び出す際に使用されます。syscall.Syscall6: 6つの引数を取るシステムコールを実行するための関数です。Go言語では、OSの特定の機能を呼び出すために、この種の関数が利用されます。返り値は通常、システムコールの結果、エラーコード、そしてエラーオブジェクトです。syscall.TCGETS/syscall.TCSETS: これらはUnix系システムにおけるターミナル制御のためのioctlシステムコールで使用されるコマンドです。TCGETS: ターミナルの現在の設定(termios構造体)を取得します。TCSETS: ターミナルの設定を新しい値に設定します。
syscall.Termios: ターミナルの設定を保持する構造体です。入力モード、出力モード、制御文字、ローカルモードなどのフラグが含まれており、ターミナルの挙動を細かく制御するために使用されます。os.Errno: Go言語の初期のバージョンで存在した、システムコールエラーを表す型です。syscall.Errnoをラップしていました。このコミットの時点では、この型が変更されたか、あるいは直接errorインターフェースを返すように変更されたため、既存のコードが影響を受けました。Makefile: ビルドプロセスを自動化するためのツールであるmakeが使用する設定ファイルです。プロジェクトのコンパイル、リンク、テストなどの手順を定義します。
技術的詳細
このコミットの技術的な変更は、主に以下の2点に集約されます。
-
os.Errnoの変更への対応:src/pkg/exp/terminal/util.goファイルでは、syscall.Syscall6やsyscall.Readといったシステムコールを呼び出した際のエラーハンドリングが変更されています。以前は、これらの関数が返すエラーコード(eやerrno)をos.Errno(e)やos.Errno(errno)のようにos.Errno型に変換して返していました。 しかし、Go言語のエラーハンドリングの進化により、syscallパッケージの関数が直接errorインターフェースを返すようになったため、この変換が不要になりました。コミットでは、osパッケージのインポートを削除し、システムコールから返されるエラー変数をeからerrにリネームし、os.Errno(err)のような変換を削除して、直接errを返すように修正しています。これにより、Goのエラーハンドリングの慣習に沿った形になりました。 -
exp/terminalのLinuxビルドへの追加:src/pkg/Makefileファイルが変更され、Linux環境でのビルド時にexp/terminalパッケージがコンパイル対象に含まれるようになりました。以前は、exp/inotifyのみがLinuxビルドの対象として明示されていましたが、この変更によりexp/terminalも追加されました。これは、exp/terminalパッケージがLinux環境で正しくビルドされることを継続的に保証し、将来的なAPI変更などによるビルドエラーを早期に発見するための予防措置です。
これらの変更は、Go言語の進化に伴うAPIの変更に追従し、コードベースの健全性を維持するための典型的なメンテナンス作業と言えます。
コアとなるコードの変更箇所
src/pkg/Makefile
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -188,6 +188,7 @@ DIRS=\
ifeq ($(GOOS),linux)
DIRS+=\
exp/inotify\
+ exp/terminal\
endif
src/pkg/exp/terminal/util.go
--- a/src/pkg/exp/terminal/util.go
+++ b/src/pkg/exp/terminal/util.go
@@ -16,7 +16,6 @@ package terminal
import (
"io"
- "os"
"syscall"
"unsafe"
)
@@ -29,8 +28,8 @@ type State struct {
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var termios syscall.Termios
- _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
- return e == 0
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
@@ -38,15 +37,15 @@ func IsTerminal(fd int) bool {
// restored.
func MakeRaw(fd int) (*State, error) {
var oldState State
- if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
+ return nil, err
}
newState := oldState.termios
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
- if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
+ return nil, err
}
return &oldState, nil
@@ -55,8 +54,8 @@ func MakeRaw(fd int) (*State, error) {
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
- _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
- return os.Errno(e)
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
+ return err
}
// ReadPassword reads a line of input from a terminal without local echo. This
@@ -64,14 +63,14 @@ func ReadPassword(fd int) ([]byte, error) {
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var oldState syscall.Termios
- if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
+ return nil, err
}
newState := oldState
newState.Lflag &^= syscall.ECHO
- if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
+ return nil, err
}
defer func() {
@@ -81,9 +80,9 @@ func ReadPassword(fd int) ([]byte, error) {
var buf [16]byte
var ret []byte
for {
- n, errno := syscall.Read(fd, buf[:])
- if errno != 0 {
- return nil, os.Errno(errno)
+ n, err := syscall.Read(fd, buf[:])
+ if err != nil {
+ return nil, err
}
if n == 0 {
if len(ret) == 0 {
コアとなるコードの解説
src/pkg/Makefileの変更
Makefileの変更は非常にシンプルです。ifeq ($(GOOS),linux)ブロック内に、exp/terminal\という行が追加されました。これは、Goのビルドシステムに対して、オペレーティングシステムがLinuxである場合に、exp/terminalパッケージもビルド対象のディレクトリ(DIRS変数)に含めるように指示しています。これにより、Linux環境でGoのソースコード全体をビルドする際に、exp/terminalパッケージもコンパイルされ、その健全性がチェックされるようになります。
src/pkg/exp/terminal/util.goの変更
このファイルの変更は、os.Errnoの変更に対応するためのものです。
-
import "os"の削除: 以前はosパッケージをインポートしていましたが、エラーハンドリングの変更によりos.Errnoが不要になったため、このインポートが削除されました。これは、コードの依存関係を減らし、よりクリーンな状態にするための良いプラクティスです。 -
エラー変数のリネームと直接的なエラー返却:
IsTerminal,MakeRaw,Restore,ReadPasswordといった関数内で、syscall.Syscall6やsyscall.Readから返されるエラーを示す変数がeやerrnoからerrにリネームされました。 最も重要な変更は、エラーの返却方法です。以前はos.Errno(e)やos.Errno(errno)のように、システムコールから返されたエラーコードをos.Errno型にラップしていましたが、変更後は直接err変数を返しています。これは、syscallパッケージの関数が直接errorインターフェースを返すようになったため、中間的なos.Errnoへの変換が不要になったことを意味します。これにより、Go言語の標準的なエラーハンドリングのパターンに準拠し、コードの可読性と保守性が向上します。
これらの変更は、Go言語の進化するAPIにコードベースを適応させ、将来的な互換性の問題を未然に防ぐための重要なステップです。
関連リンク
- Go CL 5416044: https://golang.org/cl/5416044
参考にした情報源リンク
- (特になし。コミットメッセージとコードの差分から直接解析しました。)