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

[インデックス 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では、パスをそのまま返します。

このアプローチにより、以下の利点が得られます。

  1. 一貫性: パス正規化のロジックが一箇所にまとめられるため、コード全体で一貫したパス形式が保証されます。
  2. 可読性: path.replace('\\', '/')のような繰り返し出現するコードがto_slash(path)に置き換えられ、コードの意図がより明確になります。
  3. 保守性: 将来的にパス正規化のロジックに変更が必要になった場合でも、to_slash関数を修正するだけで済むため、保守が容易になります。
  4. バグの削減: パス区切り文字の不一致による潜在的なバグを根本的に解決します。

具体的には、Mercurialのステータス出力からファイルパスを抽出するhg_matchPattern関数や、変更されたファイルを検出するVersionControlSystem.GetModifiedFiles、Mercurialのステータスを処理するMercurialVCSクラス、そしてパッチデータを分割するSplitPatch関数など、ファイルパスを扱う複数の箇所でto_slash関数が適用されています。これにより、Windows環境でもこれらの処理が期待通りに動作するようになります。

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

lib/codereview/codereview.py ファイルにおいて、以下の変更が行われました。

  1. to_slash 関数の追加:

    def to_slash(path):
    	if sys.platform == "win32":
    		return path.replace('\\', '/')
    	return path
    
  2. 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])) に変更。
  3. VersionControlSystem.GetModifiedFiles メソッド内での to_slash の適用:

    • filename = filename.strip().replace('\\', '/')filename = to_slash(filename.strip()) に変更。
  4. MercurialVCS クラス内での to_slash の適用:

    • line = self.status[i].replace('\\', '/')line = to_slash(self.status[i]) に変更。
  5. 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に依存しない一貫したパス形式を強制することで、クロスプラットフォーム互換性と堅牢性を大幅に向上させています。

関連リンク

参考にした情報源リンク