[インデックス 10754] ファイルの概要
このコミットは、Go言語のコードレビューツールにおけるパス区切り文字の問題、特にWindows環境でのパスの取り扱いに関するバグを修正するものです。具体的には、Windowsのパスで使われるバックスラッシュ(\
)が、ツール内部で期待されるフォワードスラッシュ(/
)に適切に変換されず、ファイルパスの比較や処理に問題が生じていた点を改善しています。
コミット
- コミットハッシュ:
e62b40344d54bb6932fcb37e756f781d82326b6b
- Author: Yasuhiro Matsumoto mattn.jp@gmail.com
- Date: Tue Dec 13 16:18:56 2011 -0500
- コミットメッセージ:
codereview: fix path slash issue. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/5487057
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e62b40344d54bb6932fcb37e756f781d82326b6b
元コミット内容
commit e62b40344d54bb6932fcb37e756f781d82326b6b
Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Date: Tue Dec 13 16:18:56 2011 -0500
codereview: fix path slash issue.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5487057
---
lib/codereview/codereview.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index fa8dabd397..7ab7b7e0f3 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -1065,25 +1065,30 @@ class uiwrap(object):
ui.verbose = self.oldVerbose
return ui.popbuffer()
+def to_slash(path):
+ if sys.platform == "win32":
+ return path.replace('\\', '/')
+ return path
+
def hg_matchPattern(ui, repo, *pats, **opts):
w = uiwrap(ui)
hg_commands.status(ui, repo, *pats, **opts)
text = w.output()
ret = []
- prefix = os.path.realpath(repo.root)+'/'
+ prefix = to_slash(os.path.realpath(repo.root))+'/'
for line in text.split('\n'):
f = line.split()
if len(f) > 1:
if len(pats) > 0:
# Given patterns, Mercurial shows relative to cwd
- p = os.path.realpath(f[1])
+ p = to_slash(os.path.realpath(f[1]))
if not p.startswith(prefix):
print >>sys.stderr, "File %s not in repo root %s.\n" % (p, prefix)
else:
ret.append(p[len(prefix):])
else:
# Without patterns, Mercurial shows relative to root (what we want)
- ret.append(f[1])
+ ret.append(to_slash(f[1]))
return ret
def hg_heads(ui, repo):
@@ -3139,7 +3144,7 @@ class VersionControlSystem(object):
unused, filename = line.split(':', 1)
# On Windows if a file has property changes its filename uses '\'
# instead of '/'.
- filename = filename.strip().replace('\\', '/')
+ filename = to_slash(filename.strip())
return files
@@ -3357,7 +3362,7 @@ class MercurialVCS(VersionControlSystem):
# A path
# M path
# etc
- line = self.status[i].replace('\\', '/')
+ line = to_slash(self.status[i])
if line[2:] == path:
if i+1 < len(self.status) and self.status[i+1][:2] == ' ':
return self.status[i:i+2]
@@ -3424,7 +3429,7 @@ def SplitPatch(data):
# When a file is modified, paths use '/' between directories, however
# when a property is modified '\' is used on Windows. Make them the same
# otherwise the file shows up twice.
- temp_filename = temp_filename.strip().replace('\\', '/')
+ temp_filename = to_slash(temp_filename.strip())
if temp_filename != filename:
# File has property changes but no modifications, create a new diff.
new_filename = temp_filename
変更の背景
このコミットは、Go言語のコードレビューシステム(codereview.py
スクリプト)が、Windows環境でファイルパスを正しく処理できないという問題に対処するために行われました。Windowsではディレクトリの区切り文字としてバックスラッシュ(\
)が使用されますが、Unix系システムや多くの内部処理ではフォワードスラッシュ(/
)が標準的に使用されます。
既存のコードでは、Mercurial (hg) の出力やその他のファイルパス文字列を処理する際に、このパス区切り文字の不一致が原因で、ファイルが正しく認識されなかったり、重複して表示されたりするバグが発生していました。特に、ファイルパスの比較や、Mercurialのステータス出力からファイル名を抽出する際に、この問題が顕在化していました。この修正は、クロスプラットフォームでのコードレビューツールの安定性と正確性を向上させることを目的としています。
前提知識の解説
- パス区切り文字:
- フォワードスラッシュ (
/
): Unix系OS (Linux, macOSなど) でディレクトリの区切り文字として使用されます。WebのURLでも一般的に使用されます。 - バックスラッシュ (
\
): Windows OSでディレクトリの区切り文字として使用されます。 - プログラミングにおいては、異なるOS間でパスを扱う際に、これらの区切り文字の違いを吸収するための処理が必要となることがよくあります。
- フォワードスラッシュ (
os.path.realpath()
: Pythonのos.path
モジュールにある関数で、指定されたパスのシンボリックリンクを解決し、正規化された絶対パスを返します。これにより、パスの表記揺れをなくし、実際のファイルシステム上の位置を示すパスを得ることができます。- Mercurial (hg): 分散型バージョン管理システムの一つで、Gitと同様にコードの変更履歴を管理します。Go言語のプロジェクトでは、初期の頃にMercurialが広く利用されていました。このコミットは、Mercurialのコマンド出力からファイルパスを解析する部分に関連しています。
- Go言語のコードレビューシステム: Go言語のプロジェクトでは、Googleの内部ツールをベースにした独自のコードレビューシステムが使用されていました。これは、変更セット(チェンジリスト)を提出し、他の開発者がレビューコメントを付け、承認することでコードがマージされるというワークフローをサポートしていました。
codereview.py
はこのシステムの一部を担うPythonスクリプトです。 sys.platform
: Pythonのsys
モジュールにある属性で、現在のプラットフォームを示す文字列を返します。例えば、Windowsでは'win32'
、Linuxでは'linux'
、macOSでは'darwin'
などが返されます。これにより、OSに依存する処理を条件分岐させることができます。
技術的詳細
このコミットの主要な目的は、Windows環境におけるファイルパスの正規化を徹底することです。これまでのコードでは、一部の箇所でバックスラッシュをフォワードスラッシュに置換する処理が行われていましたが、それが一貫していなかったり、特定のケースで漏れていたりしたため、問題が発生していました。
この修正では、to_slash
という新しいヘルパー関数を導入し、すべてのパス正規化処理をこの関数に集約しています。to_slash
関数は、現在のシステムがWindows (sys.platform == "win32"
) である場合にのみ、パス内のすべてのバックスラッシュをフォワードスラッシュに置換します。それ以外のOSでは、パスをそのまま返します。
このアプローチにより、以下の利点が得られます。
- 一貫性: パス正規化のロジックが一箇所にまとめられるため、コード全体で一貫したパス形式が保証されます。
- 可読性:
path.replace('\\', '/')
のような繰り返し出現するコードがto_slash(path)
に置き換えられ、コードの意図がより明確になります。 - 保守性: 将来的にパス正規化のロジックに変更が必要になった場合でも、
to_slash
関数を修正するだけで済むため、保守が容易になります。 - バグの削減: パス区切り文字の不一致による潜在的なバグを根本的に解決します。
具体的には、Mercurialのステータス出力からファイルパスを抽出するhg_matchPattern
関数や、変更されたファイルを検出するVersionControlSystem.GetModifiedFiles
、Mercurialのステータスを処理するMercurialVCS
クラス、そしてパッチデータを分割するSplitPatch
関数など、ファイルパスを扱う複数の箇所でto_slash
関数が適用されています。これにより、Windows環境でもこれらの処理が期待通りに動作するようになります。
コアとなるコードの変更箇所
lib/codereview/codereview.py
ファイルにおいて、以下の変更が行われました。
-
to_slash
関数の追加:def to_slash(path): if sys.platform == "win32": return path.replace('\\', '/') return path
-
hg_matchPattern
関数内でのto_slash
の適用:prefix = os.path.realpath(repo.root)+'/'
がprefix = to_slash(os.path.realpath(repo.root))+'/'
に変更。p = os.path.realpath(f[1])
がp = to_slash(os.path.realpath(f[1]))
に変更。ret.append(f[1])
がret.append(to_slash(f[1]))
に変更。
-
VersionControlSystem.GetModifiedFiles
メソッド内でのto_slash
の適用:filename = filename.strip().replace('\\', '/')
がfilename = to_slash(filename.strip())
に変更。
-
MercurialVCS
クラス内でのto_slash
の適用:line = self.status[i].replace('\\', '/')
がline = to_slash(self.status[i])
に変更。
-
SplitPatch
関数内でのto_slash
の適用:temp_filename = temp_filename.strip().replace('\\', '/')
がtemp_filename = to_slash(temp_filename.strip())
に変更。
コアとなるコードの解説
このコミットの核心は、新しく導入された to_slash
関数と、それが既存のファイルパス処理ロジックにどのように統合されたかです。
to_slash
関数
def to_slash(path):
if sys.platform == "win32":
return path.replace('\\', '/')
return path
この関数は、与えられた path
文字列を受け取ります。
sys.platform == "win32"
の条件により、実行環境がWindowsであるかどうかを判定します。
もしWindowsであれば、path.replace('\\', '/')
を実行し、パス内のすべてのバックスラッシュ (\
) をフォワードスラッシュ (/
) に置換した新しい文字列を返します。
Windows以外のOS(Linux, macOSなど)であれば、パスは既にフォワードスラッシュ形式であると想定されるため、path
をそのまま変更せずに返します。
このシンプルな関数が、クロスプラットフォームでのパスの互換性問題を解決するための中心的な役割を担っています。
hg_matchPattern
関数への適用
hg_matchPattern
関数は、Mercurialのリポジトリからファイルパターンに一致するファイルを取得する際に使用されます。
prefix = to_slash(os.path.realpath(repo.root))+'/'
: リポジトリのルートパスを正規化し、さらにto_slash
でフォワードスラッシュ形式に統一しています。これにより、後続のパス比較が正確に行えるようになります。p = to_slash(os.path.realpath(f[1]))
: Mercurialの出力から得られたファイルパスも、os.path.realpath
で正規化した後、to_slash
でフォワードスラッシュ形式に変換しています。これにより、Windows環境でMercurialがバックスラッシュを含むパスを返した場合でも、正しく処理されます。ret.append(to_slash(f[1]))
: パターンなしでMercurialが返すファイルパスも、to_slash
で正規化してから結果リストに追加しています。
これらの変更により、Mercurialの出力がWindowsのパス形式であっても、codereview.py
内部では一貫してフォワードスラッシュ形式でパスが扱われるようになり、パスの比較やマッチングが正確に行われるようになります。
その他の箇所への適用
VersionControlSystem.GetModifiedFiles
: このメソッドは、バージョン管理システムから変更されたファイルのリストを取得します。Windows環境でファイルプロパティの変更があった場合に、ファイル名がバックスラッシュで返されることがあったため、to_slash
を適用することで、常にフォワードスラッシュ形式に統一し、ファイルが重複して認識される問題を回避します。MercurialVCS
クラス: Mercurialのステータス情報を処理する際に、self.status
から取得した行をto_slash
で正規化しています。これにより、Mercurialの出力形式に依存せず、一貫したパス形式で処理を進めることができます。SplitPatch
関数: パッチデータを解析する際に、一時ファイル名がバックスラッシュを含む形式で生成されることがあったため、to_slash
を適用して正規化しています。これにより、パッチ内のファイルパスと実際のファイルパスの不一致を防ぎ、パッチの適用や表示が正しく行われるようにしています。
これらの変更は、codereview.py
がファイルパスを扱うほぼすべての箇所で、OSに依存しない一貫したパス形式を強制することで、クロスプラットフォーム互換性と堅牢性を大幅に向上させています。
関連リンク
- Go Code Review System (old documentation) - Go言語の古いコードレビューシステムに関する情報が含まれている可能性があります。
- Mercurial Documentation - Mercurialに関する公式ドキュメント。
参考にした情報源リンク
- golang/go commit e62b40344d54bb6932fcb37e756f781d82326b6b on GitHub
- Go CL 5487057 - このコミットに対応するGoのチェンジリストページ。より詳細な議論やレビューコメントが含まれている可能性があります。
- Python
os.path
module documentation - Python
sys
module documentation - Path (computing) - Wikipedia - パスに関する一般的な情報。
- File system - Wikipedia - ファイルシステムに関する一般的な情報。
- Cross-platform compatibility - Wikipedia - クロスプラットフォーム互換性に関する一般的な情報。