[インデックス 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
参考にした情報源リンク
- (特になし。コミットメッセージとコードの差分から直接解析しました。)