Windows + tortoiseHG 環境でTimestampMod拡張使用の不具合について

393 views
Skip to first unread message

flied onion

unread,
May 8, 2012, 8:52:20 AM5/8/12
to mercur...@googlegroups.com
はじめまして。

Windows + tortoiseHGでファイル更新日付を維持するTimestampMod拡張を使用していましたが、
日本語を含むディレクトリやファイル名でエラーとなることに気づきました。
具体的にはsjisで作成されたjsonフォーマットの.hgtimestampが、utf8が期待されるjson.loadに渡されエラーとなり、jsonではなく(csvフォーマット)とみなされて処理が継続する。
しかしエンコードが違うだけで実態は(sjisの) jsonなので、ファイルスタンプが更新できない。という症状になります。

パッチを作成してみましたので興味がある方はご参照ください。
後述しますがcygwin環境かどうかは判別していませんので、ニッチな修正となっています。

パッチは #10728853f4c578b9b976ff05a3926c1b2cf5e224 が元になっていて、win32cp932というブランチに追加されます。


パッチの内容についてdiffの内容を元に説明させていただきます。

まずjson読み込み部分(投稿したpyファイルの484行目あたり)

-  myData = json.load(myTimeStampJSONFile)
+  spec_encode = _get_specified_encode()
+  if not spec_encode :
+    myData = json.load(myTimeStampJSONFile)
+  else:
+    try:
+      myData = json.load(myTimeStampJSONFile)
+    except:
+      myData = json.load(codecs.getreader(spec_encode)(open(repo.wjoin(IN_TimestampFileName),'r')))

_get_specified_encode() については最後にも説明しますが、os.name='nt' の環境であれば 'cp932'が、それ以外は Noneが返ります。
無条件でjson.loadしていたのを、Windows環境では まず無条件にjson.loadし、エラーであれば  _get_specified_encode() によって返されたエンコードで読み込みを行います。
Windows環境でも無条件にjson.loadしているのは、このパッチで最終的にはutf8で書き込むようにしているためです。
( パッチ前のすでにshift-jisで作成されたファイルであっても読み込めるようにexcept句でエンコード指定での読み込みを施行しています)

     for s_fileName, obj_fileData in myData['FileData'].items():
+      if spec_encode:
+        s_fileName = s_fileName.encode(spec_encode)
       #Only import data for entries already in local dictionary.

また、jsonデータから取得したファイル名(s_fileName) を再度 cp932に変換しています。
これはこの後のファイル名のマッチングでtortoiseHgから取得したShift-JISのファイル名と比較しているためです。


続いて書き込み処理です。

   myTimeStampJSONFile = open(repo.wjoin(IN_TimestampFileName), 'w')
+  spec_encode = _get_specified_encode()
+  if spec_encode:
+    myTimeStampJSONFile = codecs.getwriter('utf-8')(myTimeStampJSONFile)
   # Record version data for the file.
   myTimeStampJSONFile.write('{\n"Version": "' + File_Version + '",\n"FileData":{\n')

Windows環境の場合は明示的にutf-8のwriterを指定しています。
この処理を無くして読み込みも書き込みもSJIS前提にしてしまえば楽にはなるのですが、将来的なことを考えると他の環境と同じであろうutf8エンコードの.hgtimestampにしておくべきと考え処理を入れています。現状はwin32mbcs+中央リポジトリもWindowsの場合などではLinuxその他の環境との互換性はありませんがやっておいて損はなさそうなのでこのようにしました。

     else:  #timestamp is valid
-      myTimeStampJSONFile.write('"%s": {"timestamp": %s},\n' % (s_fileName, f_fileModTime))
+      if not spec_encode:
+        myTimeStampJSONFile.write('"%s": {"timestamp": %s},\n' % (s_fileName, f_fileModTime))
+      else:
+        myTimeStampJSONFile.write('"%s": {"timestamp": %s},\n' % (s_fileName.decode(spec_encode), f_fileModTime))
     # end of check for non-existing files or timestamps.

Windows環境の場合はファイル名を一旦unicodeにデコードしてパラメータに渡しています。

最後に環境判定とエンコード指定用に追加した _get_specified_encode関数です。
+def _get_specified_encode():
+ if os.name=='nt':
+ return 'cp932'
+ return None

エンコードを指定する場合はエンコード文字列が、それ以外はNoneが返ります。この関数がNoneを返す環境では、TimestampModはこれまで通りの動きとなります。
os.nameでのみ判定しているのでおそらくcygwin環境でも同じ値が取れてしまうかもしれません。
別の方法で判別すればよいのかもしれませんが、unameはWindows環境では間違いなくエラーになるなど、他にいい手が思いつかなかったので甘いつくりになっています。
他の判定分を追加すれば他のエンコードに対応できそうにつくってはありますが、今のところWindows+TortoiseHg環境での検証しかしていません。


以上です。
TimestampMod.py
TimestampMod_204.patch

flied onion

unread,
May 8, 2012, 9:18:27 AM5/8/12
to mercur...@googlegroups.com
書き忘れてしまいましたが
toroiseHgのバージョンは 2.3.2、Mercurial-2.1.2, Python-2.6.6, PyQt-4.8.6, Qt-4.7.4
になります。

Katsunori FUJIWARA

unread,
May 8, 2012, 10:12:20 AM5/8/12
to mercur...@googlegroups.com
藤原です。

2012年5月8日21:52 flied onion <flied...@gmail.com>:

> Windows + tortoiseHGでファイル更新日付を維持するTimestampMod拡張
> を使用していましたが、日本語を含むディレクトリやファイル名でエラー
> となることに気づきました。
>
> 具体的にはsjisで作成されたjsonフォーマットの.hgtimestampが、
> utf8が期待されるjson.loadに渡されエラーとなり、jsonではなく(csv
> フォーマット)とみなされて処理が継続する。
>
> しかしエンコードが違うだけで実態は(sjisの) jsonなので、ファイル
> スタンプが更新できない。という症状になります。

以下、ざっと拝見した段階でのコメントです。

なお、私の Python 知見は、Mercurial のソース読解のみに特化していて、
JSON 周りの話も門外漢なので、詳しい方おられましたら、適宜フォロー
していただけると幸いです。

# コメントの便宜上、順番をちょっと入れ替えます。

> 最後に環境判定とエンコード指定用に追加した _get_specified_encode関数です。
> +def _get_specified_encode():
> + if os.name=='nt':
> + return 'cp932'
> + return None
>
> エンコードを指定する場合はエンコード文字列が、それ以外はNoneが返
> ります。この関数がNoneを返す環境では、TimestampModはこれまで通り
> の動きとなります。

現行の Mercurial では、"mercurial.encoding" モジュールの encoding 変数が、
実行環境における文字コード(HGENCODING 等での指定値)を保持していますので、
特別な事情等が無ければ、新たな関数を導入するのではなく、この変数を参照したほうが
良いと思います。

添付パッチで、『if spec_encode』判定している箇所で、処理の切り替えをするための、
『encoding.lower() not in ["utf8" "utf-8"]』みたいな判定処理をユーティリティ化する
必要はあるかも知れませんが………


以下の処理は "encode()" のみであることを考えると、s_fileName は unicode
オブジェクトということだと思うのですが、それだと s_fileName がバイト列に
なってしまい、処理の辻褄が合わない気がしますが、大丈夫なのでしょうか?

> for s_fileName, obj_fileData in myData['FileData'].items():
> + if spec_encode:
> + s_fileName = s_fileName.encode(spec_encode)
> #Only import data for entries already in local dictionary.
>
> また、jsonデータから取得したファイル名(s_fileName) を再度 cp932に変換しています。
> これはこの後のファイル名のマッチングでtortoiseHgから取得したShift-JISのファイル名と比較しているためです。

で、もしも実施したい処理が『バイト列(utf-8)⇒バイト列(cp932)』であれば、
"mercurial.encoding" モジュールの "tolocal()" が使用可能です。

> 続いて書き込み処理です。
>
> myTimeStampJSONFile = open(repo.wjoin(IN_TimestampFileName), 'w')
> + spec_encode = _get_specified_encode()
> + if spec_encode:
> + myTimeStampJSONFile = codecs.getwriter('utf-8')(myTimeStampJSONFile)
> # Record version data for the file.
> myTimeStampJSONFile.write('{\n"Version": "' + File_Version +
> '",\n"FileData":{\n')
>
> Windows環境の場合は明示的にutf-8のwriterを指定しています。
>
> この処理を無くして読み込みも書き込みもSJIS前提にしてしまえば楽に
> はなるのですが、将来的なことを考えると他の環境と同じであろう
> utf8エンコードの.hgtimestampにしておくべきと考え処理を入れていま
> す。現状はwin32mbcs+中央リポジトリもWindowsの場合などではLinux
> その他の環境との互換性はありませんがやっておいて損はなさそうなの
> でこのようにしました。

既に cp932 のファイル名が登録されている場合、リポジトリ中の履歴情報記録が
cp932 で実施されているため、utf-8 化してもあまり旨みが無い気がします。

話は逸れますが、例の『unicode API 利用による UTF-8 への統一』の件、
既存リポジトリから変換するためのツール (convert へのプラグイン形
式?)が必要だなぁ、と思っていたのですが、timestamp/timestampmod エ
クステンションのような、ファイル名一覧ファイルを持つようなケースに
対処するための、「ファイル内容変換機能」も欲しいということを忘れな
いようにしないといけませんね。

閑話休題。

で、HGENCODING に準拠した文字コードで保存するのであれば:

> まずjson読み込み部分(投稿したpyファイルの484行目あたり)
>
> -  myData = json.load(myTimeStampJSONFile)
> +  spec_encode = _get_specified_encode()
> +  if not spec_encode :
> +    myData = json.load(myTimeStampJSONFile)
> +  else:
> +    try:
> +      myData = json.load(myTimeStampJSONFile)
> +    except:
> +      myData =
> json.load(codecs.getreader(spec_encode)(open(repo.wjoin(IN_TimestampFileName),'r')))

読み込み処理も、"mercurial.encoding" の encoding 変数を使った
単一処理にしてしまった方が良いと思います。

以上、ざっと見た範囲でのコメントですが、参考になれば幸いです。

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

flied onion

unread,
May 9, 2012, 7:01:54 AM5/9/12
to mercur...@googlegroups.com
コメントありがとうございます。
mercurialの使用も日が浅く、pythonのコーディングも初めてだったので勉強になります。
時間があるときにいろいろ試してみようと思います。

utf8への書き込みに関してはもともとが エンコード指定なしの json.load 呼び出しだったのでutf8が期待されていることから.hgtimestampをなるべく元々の期待通りのエンコードに丸める方向で考えていました。
(json.loadは第二引数にエンコードを指定でき、省略時はutf8が指定されたことになります。指定できると言ってもcp932は内容にShiftJISのいわゆるダメ字を含むと非Ascii扱いでエラーとなるのでドキュメントに従いcodecs使用しましたが。)
また、unicode API 利用による UTF-8 への統一 がなされた後でも.hgtimestampの再加工(エンコード変換)を少なくできるのではと考えての事でしたが、
仮にファイル内容変換機能が実装された場合は下手にリポジトリ内に複数のエンコードが混在するよりもリポジトリ内で統一されていたほうが(ファイルのエンコード判定が不要な分)変換はスムーズにできそうですね。
ご指摘のとおりWin環境に限定して使用する分にはutf8にする旨みは全く無いので再考してみようかと思います。

flied onion

unread,
May 17, 2012, 11:49:13 AM5/17/12
to mercur...@googlegroups.com
mercurial.encodingを使用するよう修正しました。
 
ロジック上の主な変更は以下となります。
 
ローカルのエンコードがutf8の場合は既存と同じ処理。
読み込み時はローカルのエンコード→utf8の順で試行する。
.hgtimestampがutf8で開けたにもかかわらずローカルのエンコードがutf8でない場合は、.hgtimestampから取得したファイル名をローカルエンコードに戻してマッチング処理を行う。
 
 
保存時にエンコードは特に指定せず、オリジナルと同じ処理に戻した。
 
 
パッチは前回のパッチへの適用となります。
# 修正内容は見てないが本家がそろそろ0.2.3になりそう。
 
 
 
TimestampMod.py
TimestampMod_win32cp932_217.patch

Katsunori FUJIWARA

unread,
May 21, 2012, 3:23:49 AM5/21/12
to mercur...@googlegroups.com
flied onion さん:

藤原です。お返事遅れて済みません。

2012年5月18日 0:49 flied onion:
> mercurial.encodingを使用するよう修正しました。
>
> ロジック上の主な変更は以下となります。

> ローカルのエンコードがutf8の場合は既存と同じ処理。

設定無しの場合に使用される ascii が『utf-8 以外』に該当してしまう
ので、これも除外対象に含めておいた方が良いかもれません。

そういった意味では、"_no_local_encoding()" みたいな名前の方が良い
かもしれませんね > _get_localencode_is_utf8()


> 読み込み時はローカルのエンコード→utf8の順で試行する。

この処理ですが、cp932 環境で utf-8 化されたファイル名が保存される
可能性はどの程度でしょう?

『基本的にはありえない』のであれば:

> .hgtimestampがutf8で開けたにもかかわらずローカルのエンコードが
> utf8でない場合は、.hgtimestampから取得したファイル名をローカルエ
> ンコードに戻してマッチング処理を行う。

上記の処理も除外できますから、再試行はしない、という判断もありだと思います。

『有る程度ありえる(+ 救済した方が良い)』のであれば、現行の修正内容
で良いと思いますが、json.load() 固有の例外との区別をつける意味で、
excpet 対象は UnicodeError あたりに絞った方が良いかと。


また、開発元で『性能劣化/可読性』のバランスをどのあたりに見据えて
いるかによりますが:

tolocal = lambda x: x # デフォルトは無変換
if is_encoding_utf8:
....
else:
try:
....
exception:
# utf-8 で読み込み
tolocal = encoding.tolocal # 文字コード変換を行う関数に差し替え


if ('FileData' in myData):
....


for s_fileName, obj_fileData in myData['FileData'].items():

# local encoding を保証
s_fileName = tolocal(s_fileName)

という実装形式もあります。

このあたりの判断は、相手の思惑を読まないといけないので、難しいところですね。

# 私も本家 devel-ml でしょっちゅう読み間違いをしてます…orz


> 保存時にエンコードは特に指定せず、オリジナルと同じ処理に戻した。

『cp932 環境では、cp932 で保存される』という理解でよいのですよね?


> パッチは前回のパッチへの適用となります。
> # 修正内容は見てないが本家がそろそろ0.2.3になりそう。

パッチヘッダの "Node ID" を見るに:

1. ebc144b069a9 を commit
2. "hg export tip" を ML に投函
3. 指摘を元に、追加修正の efe2db7ded62 を commit
4. "hg export tip" を ML に投函

という手順だと思いますが、修正内容確認の観点からすると、(4) は
"hg export" 結果ではなく、"hg diff -r ebc144b069a9" の方が良かった
です(笑)。

また、開発元に取り込んでもらう場合、パッチを送るにしろ、bitbucket
等に公開して pull request を投げるにしろ、修正内容を1つのリビジョン
にまとめた方が良いですから、この機会に MQ を使えるようになることを
お勧めします。

# 既に使いこなしていたら失礼しました!


とりあえず、今回必要そうな機能を列挙してみました。

- "hg qimport -r ebc144b069a9::" での修正実施リビジョンの MQ 配下への取り込み
- "hg qpush"/"hg qpop" によるパッチ適用状況の操作
- "hg qfold" による複数 MQ パッチの統合
- 修正 ⇒ "hg qrefresh" の繰り返しによる変更内容の試行錯誤
- "hg qfinsih" による通常リビジョン化

MQ による操作は、履歴を非可逆的に破壊しえるので、有る程度慣れるまでは、
元リポジトリから clone した実験用のリポジトリで練習することをお勧めします。

MQ の詳細に関しては、拙著『入門 Mercurial』なり、『Mercurial: The
Definitive Guide』の翻訳(旧版ベースですが、基本的な概念は変わって
いません)なりを参考にしつつ、別途 ML/twitter 等で質問してください。

http://foozy.bitbucket.org/hgbook-ja/d6ca1334a19d/hgbookch12.html

概念的な説明が殆ど含まれていないので、コマンド/拡張機能のオンライ
ンヘルプだけで理解するのは、ちょっと(相当?)難しいかもしれません。

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

フジワラ

unread,
May 21, 2012, 6:09:41 AM5/21/12
to mercur...@googlegroups.com
藤原です。

2012年5月21日月曜日 16時23分49秒 UTC+9 フジワラ:

2012年5月18日 0:49 flied onion:

> パッチは前回のパッチへの適用となります。
> # 修正内容は見てないが本家がそろそろ0.2.3になりそう。

パッチヘッダの "Node ID" を見るに:

    1. ebc144b069a9 を commit
    2. "hg export tip" を ML に投函
    3. 指摘を元に、追加修正の efe2db7ded62 を commit
    4. "hg export tip" を ML に投函

という手順だと思いますが、修正内容確認の観点からすると、(4) は
"hg export" 結果ではなく、"hg diff -r ebc144b069a9" の方が良かった
です(笑)。


すみません。diff に指定するリビジョンを間違えてました。

ebc144b069a9 の親リビジョンからの差分を生成したいので、
『diff -r ebc144b069a9』ではなく『diff -r "ebc144b069a9^1"』ですね。

flied onion

unread,
May 29, 2012, 9:15:46 AM5/29/12
to mercur...@googlegroups.com
藤原さん:
遅くなりすみません。
いろいろ実際に運用しながらためしていましたが、
tolocalの問題が見つかったので、それを含め修正しました。
パッチではなくファイルのみです。

前のバージョンだと、パスに日本語を含むファイルに対して日付の複製ができていませんでした。
(commit時の保存はできているが、updateなどするとその日の日付になってしまっていた。)


本家への投稿はどうしようか考え中です。(現状windows+tortoiseHgでしかためしていないので)
forkとかって気軽にやってしまっていいんですかね?
いずれにせよ、hgはじめたてで自分のリポジトリもいろいろごちゃごちゃしてきたので、リポジトリは新たにMQでやり直そうかと考えています。
(日付はTimestampModが戻してくれますし)

>  設定無しの場合に使用される ascii が『utf-8 以外』に該当してしまう
>  ので、これも除外対象に含めておいた方が良いかもれません。

> そういった意味では、"_no_local_encoding()" みたいな名前の方が良い
>  かもしれませんね > _get_localencode_is_utf8()

このあたりは検討の余地ありですね。


>この処理ですが、cp932 環境で utf-8 化されたファイル名が保存される
>可能性はどの程度でしょう?

これは無いことも無いです。私の最初のパッチ当てるとそういう環境が出来上がります(笑)
あとは将来的にWindows環境でもutf8なリポジトリが使えるようになった場合、Linuxからcloneしたリポジトリはそういう環境化にありますね。
いずれにしても、json.loadに失敗するとexceptされてCSVで試行される作りになっていて、jsonなら100%そこで失敗します。
そういう作りなので可能性が少しでもあるなら同じように救ってあげておいてもいいのかな。と考えています。
キャッチ対象の例外は検討してみます。


>    tolocal = lambda x: x # デフォルトは無変換 
---
>            tolocal = encoding.tolocal # 文字コード変換を行う関数に差し替え 
---
>            s_fileName = tolocal(s_fileName)


lambdaで実際の変換時になにしているか意識させないのはいいですね。
そのステートメントではどう変換されるか知る必要はなく、tolocalがうまいことやってくれることだけ知っていればいい。
こういうの好きです。

 >> 保存時にエンコードは特に指定せず、オリジナルと同じ処理に戻した。
 >『cp932 環境では、cp932 で保存される』という理解でよいのですよね?

open依存ではありますが、そういうことになりますね。
HG_ENCODINGではなく、システムエンコーディングが選択されることになると思います。


> ebc144b069a9 の親リビジョンからの差分を生成したいので、 
>『diff -r ebc144b069a9』ではなく『diff -r "ebc144b069a9^1"』ですね。

GUIからばかりやっていたので、こういったコマンドは勉強になります( ^1 とか)
MQは最近やっと本来の使い方がわかってきたので、mercurialの勉強も兼ねていろいろやってみたいと思います。
気軽におためしリポジトリをクローンできるのは強みですよね。


TimestampMod.py

Katsunori FUJIWARA

unread,
May 30, 2012, 11:17:42 AM5/30/12
to mercur...@googlegroups.com
藤原です。

2012年5月29日 22:15 flied onion <flied...@gmail.com>:

> パッチではなくファイルのみです。

とりあえず、前回の修正からの変更点のみ確認してみました。

myList_Match = list()
myList_Match = match.files() #don't add timestamp file here, it will
be added later.

if isinstance(myList_Match,set) and len(myList_Match) == 0:
myList_Match = list()

timestamp_mod(repo.ui, repo, **dict({'save': True, 'restore': None,
'match': list(myList_Match)}))


これは、単純に私自身の疑問なのですが、"myList_Match = list()" で初
期化しておいて、何故か "myList_Match = match.files()" で上書きする
のって、何かそいいう流儀があるのでしょうかね? 実行上意味が無い気
がしているのですが…

で、どうせ list 化するなら:

if not isinstance(match.files(), list):
# for backward compatibility between 127281884959 and XXXXXXX
myList_Match = list(match.files())
else:
myList_Match = match.files()
#don't add timestamp file here, it will be added later.
timestamp_mod(repo.ui, repo, **dict({'save': True, 'restore': None,
'match': myList_Match}))

ぐらいに簡素化してもよいかも?と思っています。


また、以下の修正箇所は、なかなか微妙な問題をはらんでますね。

- match.files().append(File_TimestampRecords)
+ if not isinstance(match.files(),set):
+ match.files().append(File_TimestampRecords)

問答無用でファイルを追加したい場合は:

if not instance(match.files(), set):
match._files = list(match.files())
match.files().append(File_TimestampRecords)

上記のように、match の内部データを書き換えてしまった方が良いと思い
ます。


> 本家への投稿はどうしようか考え中です。(現状windows+tortoiseHgで
> しかためしていないので)
> forkとかって気軽にやってしまっていいんですかね?
> いずれにせよ、hgはじめたてで自分のリポジトリもいろいろごちゃごちゃ
> してきたので、リポジトリは新たにMQでやり直そうかと考えています。
> (日付はTimestampModが戻してくれますし)

今回のように試行錯誤過程を共有するような場合、いきなり本家から
fork するよりは:

1. 手元のリポジトリにおいて "hg init --mq" を実行し、パッチキュー
を Mercurial 管理化

2. パッチを作成: qnew/qrefresh

3. パッチキューの内容を記録: "hg commit --mq"

4. bitbucket 等にパッチキューの履歴を upload

4.1 bitbucket 上にリポジトリを作成: 通常の「リポジトリ作成」
ないし、「対象リポジトリ」ページの「patch queue」

4.2 .hg/patches/.hg/hgrc の [paths] 設定に上記リポジトリの設
定を追加

4.3 bitbucket に push: "hg push --mq"

上記の要領でパッチキューを公開し、ある程度修正内容が固まってから本
家からの fork ⇒ 修正 ⇒ pull request という通常の流れに乗せたほう
が良いかと。

この手順は:

1. 障害が発生したなら bug tracker 上で issue を open
2. 修正案のパッチを issue に upload
3. レビュアーによるレビューの実施
4. 指摘事項を反映(= 各自の MQ 上で再修正)し、再度 upload
5. OK が出たなら、共有履歴に反映

といった「プレコミットレビュー」形式での開発にも応用できます。


>>この処理ですが、cp932 環境で utf-8 化されたファイル名が保存される
>>可能性はどの程度でしょう?
>

> これは無いことも無いです。私の最初のパッチ当てるとそういう環境が
> 出来上がります(笑)
> あとは将来的にWindows環境でもutf8なリポジトリが使えるようになっ
> た場合、Linuxからcloneしたリポジトリはそういう環境化にありますね。

(将来的な)「Linuxからcloneしたリポジトリ」使用の場合、HGENCODING
を utf-8 に設定することになりますから、「cp932 環境で」という条件
は満たしませんね。

むしろ、HGENCODING にそぐわない文字コードで保存された場合に、次の
commit 時点で迅速に検出できる方が、やり直しが効く、という点でも良
いかもしれません。

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

flied onion

unread,
May 31, 2012, 9:54:13 AM5/31/12
to mercur...@googlegroups.com
詳細な説明ありがとうございます。

> これは、単純に私自身の疑問なのですが、"myList_Match = list()" で初
>  期化しておいて、何故か "myList_Match = match.files()" で上書きする
>  のって、何かそいいう流儀があるのでしょうかね? 実行上意味が無い気
>  がしているのですが… 

これは私も気になってました。最初からこういう実装だったんでほっておいてあるんですが無駄ですよね。
内部変数を直に書き換えるわけですね。当然といえば当然ですが、C# メインだとこうprivateメンバにアクセスしているようでちょっと躊躇してしまいます。
今回はMQ側の修正も決まってる上にリストで来るべきだということで書き換えてしまってもよさそうですね。


bitbucketでの公開の詳細な例ありがとうございます。
いろいろ試してみようと思います。


> (将来的な)「Linuxからcloneしたリポジトリ」使用の場合、HGENCODING
>  を utf-8 に設定することになりますから、「cp932 環境で」という条件
>  は満たしませんね。 

今悩みすぎてもしょうがない問題かもしれませんが
HGENCODING(repo.status?)、encoding.encoding、OSのエンコード(os.stat)、.hgtimestampファイル内容のエンコードなどの組み合わせを検討しないといけないのでどうするのがベターかが難しいです。
私が言った「cp932環境」はOSのエンコードの意味合いが強かったですね、漠然とencoding.encoding=OS(というかプラットフォーム)のエンコードと考えてしまっていましたが、そうとは限らないですよね。

.hgtimestampファイルに関してだけいえば、内容がどんなエンコードであれば開けてしまえばUNICODEになるので、将来を見据えてUTF8でトライしつつ、だめなら別のエンコード
(OSのエンコード?)であけてみるというのが無難なのかなともやもやと考えています。
またはhgrcでユーザー指定可能にするか。

mergeツールもいくつか用意しておくのもいいかなぁと思っています。(常に新しい方、常に古い方)
「取り込まないという結論だっただけで、間違いなくその時点で比較・変更作業は行った」という判断でよいとするなら常に新しい方をとるmergeツールもあってもいいかもしれませんね。
常に古い方はオマケです。
いろいろ首を突っ込み始めてるのでなかなか作る時間はなさそうですが(^^:::

Katsunori FUJIWARA

unread,
Jun 1, 2012, 11:42:22 AM6/1/12
to mercur...@googlegroups.com
藤原です。

2012年5月31日 0:17 Katsunori FUJIWARA <flying...@gmail.com>:

>> 本家への投稿はどうしようか考え中です。(現状windows+tortoiseHgで
>> しかためしていないので)
>> forkとかって気軽にやってしまっていいんですかね?
>> いずれにせよ、hgはじめたてで自分のリポジトリもいろいろごちゃごちゃ
>> してきたので、リポジトリは新たにMQでやり直そうかと考えています。
>> (日付はTimestampModが戻してくれますし)
>
> 今回のように試行錯誤過程を共有するような場合、いきなり本家から
> fork するよりは:
>
> 1. 手元のリポジトリにおいて "hg init --mq" を実行し、パッチキュー
> を Mercurial 管理化
>
> 2. パッチを作成: qnew/qrefresh
>
> 3. パッチキューの内容を記録: "hg commit --mq"
>
> 4. bitbucket 等にパッチキューの履歴を upload
>
> 4.1 bitbucket 上にリポジトリを作成: 通常の「リポジトリ作成」
> ないし、「対象リポジトリ」ページの「patch queue」
>
> 4.2 .hg/patches/.hg/hgrc の [paths] 設定に上記リポジトリの設
> 定を追加
>
> 4.3 bitbucket に push: "hg push --mq"

済みません。嘘書いちゃってました。

bitbucket での "patch queue" では、親リポジトリ毎 clone されます。

つまり、デカいプロジェクトの patch queue だけ作ったつもりで、『プ
ロジェクト丸々の複製リポジトリ』と『その配下の .hg/patches 用リポ
ジトリ』が作成されてしまいます。

「patch queue」でリポジトリを作成する場合は、その辺を納得した上で
ご使用ください。

作成ページの説明も単に『patch queue を作るよ?』だったので、
完全に誤解してました … orz

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

flied onion

unread,
Jun 1, 2012, 1:44:10 PM6/1/12
to mercur...@googlegroups.com
flied onionです、こんばんは。
 

bitbucket での "patch queue" では、親リポジトリ毎 clone されます。

藤原さんにいろいろ教わりながら四苦八苦してましたが、これどうもcloneではなさそうです。 

hgtip-content-jaのpatch queueボタンでpatch queue hgtip-content-ja-patchを作成し、
hg qcloneしたら 
hgtip-content-ja-patch/.hg/hgrc のpathは作成されたURL(https://~/hgtip-content-ja-patch)を指していて、
hgtip-content-ja-patch/.hg/patches/.hg/hgrc のpathは https:// ~/hgtip-content-ja-patch/.hg/patches)を指していました。

hgtip-content-ja-patch に対してpushかけてみたんですけど(hg outもhg pushもは自分のURL指してました)認証ではじかれました。
親リポジトリに関しては本物を指しているような印象です。シンボリックリンクかスナップショットみたいな感じですかね?


ところで、せっかくなのでまとめます。
A. bitbucketで既存リポジトリからpatch queueしてパッチ作業したい場合
1. patch queueでリポジトリを作成します。
(名前は慣例的には 元のリポジトリ+ "-patches" という記述をみかけましたがそれであってますかね?)
2. hg qclone (URL) でローカルにもってきます
3. .hg/patches/.hg/hgrc のpathやユーザー名を適宜設定します(pathは多分設定されてますし、~/hgrcにユーザー名設定されてれば多分不要です)
4. MQ利用してパッチ作成します
5. パッチキューの内容を記録: "hg commit --mq"
6. hg out --mq
7. hg push --mq
で、bitbucketにcommitsにも表示されます。(patch seriesタブじゃないのが気になります。なんかまちがってるのか、hg commit --mqがいらないのか?)
この場合は元としたリポジトリのfork/patchesに表示されます。


B. bitbucketで新規リポジトリにpatchをpushしたい場合
1. bitbucketで普通にリポジトリを作ります
2. 元したいリポジトリを普通に手元にクローンします
3. MQ利用してパッチを作成します
4. パッチキューの内容を記録: "hg commit --mq"
5. .hg/patches/.hg/hgrc のpathやユーザー名を適宜設定します(pathは設定されてないはず、ユーザー名は~/hgrcに設定されてれば多分不要)
6. hg out --mq
7. hg push --mq
で、完了です。
この場合は元としたリポジトリのfork/patchesに表示されません。なので「patchできたよー」って報告するのどうすればいいのかわかりませんでした。


まだ使い初めなので認識違いあるかもしれませんが、上記A,Bのやり方でpushまでできました。
なお、patch queueで作成したのに(A-1)、B-2以降のやり方でpatch queueのリポジトリにpush --mqしようとするとrelated failかなにかのエラーがでます。
関係ないリポジトリにpushしたときとのエラーと同じやつでしょうね。


ところで、 hg push --mq後に 別の場所にhg qcloneすると、.hg/patchesにパッチはいるんですけど qseriesには何もいない状況&通常リビジョンとしてcommitされてるわけでもないし、qpushもできない
という状況になりましたがなにかご存知の方いませんか?(・_・;

Katsunori FUJIWARA

unread,
Jun 2, 2012, 7:04:36 AM6/2/12
to mercur...@googlegroups.com
藤原です。

色々混乱させてしまい済みませんでした orz

2012年6月2日 2:44 flied onion <flied...@gmail.com>:

>> bitbucket での "patch queue" では、親リポジトリ毎 clone されます。
>
> 藤原さんにいろいろ教わりながら四苦八苦してましたが、これどうも
> cloneではなさそうです。
>
> hgtip-content-jaのpatch queueボタンでpatch queue
> hgtip-content-ja-patchを作成し、hg qcloneしたら
> hgtip-content-ja-patch/.hg/hgrc のpathは作成されたURL(https://~
> /hgtip-content-ja-patch)を指していて、
> hgtip-content-ja-patch/.hg/patches/.hg/hgrc のpathは https:// ~
> /hgtip-content-ja-patch/.hg/patches)を指していました。
>
> hgtip-content-ja-patch に対してpushかけてみたんですけど(hg outも
> hg pushもは自分のURL指してました)認証ではじかれました。親リポジ
> トリに関しては本物を指しているような印象です。シンボリックリンク
> かスナップショットみたいな感じですかね?

自分のリポジトリを元に patch queue を作成したところ:

- qfinish で適用対象リポジトリに変更を記録
- hg push で適用対象リポジトリに変更を反映

という手順で、『patch queue 元リポジトリ』に変更が反映されるのを確
認しました。

この挙動を『自前リポジトリで権限があったため』と考えれば、おそらく
『シンボリックリンク』的なものなのでしょうね。


> 1. patch queueでリポジトリを作成します。(名前は慣例的には 元のリ
> ポジトリ+ "-patches" という記述をみかけましたがそれであってま
> すかね?)

『パッチキューそのもの』が作成されるのであれば、"hg qqueue" との兼
ね合いを考えて "patches-*" 形式の方が良いと思いますが、ここで指定
した名前は、仮想的とは言え、『適用対象リポジトリ』の複製に対する名
前なので、"patches-*" は無しになりますね。

"*-patches" 形式でよいのではないでしょうか?


> 7. hg push --mq で、bitbucketにcommitsにも表示されます。(patch
> seriesタブじゃないのが気になります。なんかまちがってるのか、
> hg commit --mqがいらないのか?)

それは変ですね。わたしが試したところ、"hg push --mq" 後は:

- commits タブには『パッチキューにおける』変更内容の一覧
- patch series タブには管理下のパッチ一覧
⇒ ラジオボタンで選択して「Apply patches」を押すと差分が表示

という状況になりました。

# クラスタ化等で情報伝播が遅延しているとか?


> B. bitbucketで新規リポジトリにpatchをpushしたい場合

> この場合は元としたリポジトリのfork/patchesに表示されません。なの
> で「patchできたよー」って報告するのどうすればいいのかわかりませ
> んでした。

この辺は開発元の修正受付ポリシー次第で:

A pull request を受け付ける
B patch リポジトリからの取り込みを受け付ける
C メールベースでパッチを受け付ける

(B) は受け付けるけど (A) は受け付けない、というのは多分無い(逆の
方が大多数では?)と思うので:

1. "patch queue" ではなく、"fork" で複製
2. パッチ適用結果を fork に push
3. fork 元に pull request 発行

という流れが妥当ではないでしょうか?

Mercurial 本体みたいに (C) しか受け付けていないケースでの私の手順
は、以下のような感じですね。

1 パッチを適用: hg qpush -a

2 パッチを投函: hg email -r "mq()" ... To:/Subject: 等の引数指定 ...

3 ドキドキしながら返事を待つ

4 取り込みを確認したらパッチを破棄

同時に複数の作業を並行する場合があるので、パッチ破棄の利便性
上とあわせて:

- "hg qq --create xxxx" で専用の作業キューを作成

- "hg qq --purge xxxx" で専用キューを破棄

といった感じで ".hg/patches" は直接使わないようにしてます

5 指摘付きで却下されたら再度修正作業


> --mqしようとするとrelated failかなにかのエラーがでます。関係ない
> リポジトリにpushしたときとのエラーと同じやつでしょうね。

これに関してですが:

1. "patch queue" で作成した bitbucket リポジトリで、既存のリビジョ
ン全て(とは言っても初期状態だと1つしかありませんが)を破棄

"Admin" ⇒ "Strip changesets" ⇒ 40桁のリビジョンIDを指定

リビジョンID指定は40桁の完全指定でないと無視されます

2. 手元のパッチキューの paths 設定(.hg/patches/.hg/hgrc)で、
"<patch queue で生成されたリポジトリの URL>/.hg/patches"
指定を追加

3. "hg push --mq <反映先>" 実行

という手順で push できることを確認しました。

最初は私も上手く行かなかったのですが、パッチキューのリポジトリが実際には:

<patch queue で生成されたリポジトリの URL>/.hg/patches

に配置されていることが分かったので、そちらと連携するように設定した
ら上手くいきました。


> ところで、 hg push --mq後に 別の場所にhg qcloneする
> と、.hg/patchesにパッチはいるんですけどqseriesには何もいない状況
> &通常リビジョンとしてcommitされてるわけでもないし、qpushもでき
> ないという状況になりましたがなにかご存知の方いませんか?(・_・;

これも私の手元では再現しませんでした。

先述した「patch series タブ」の件もありますから:

- 手元のリポジトリからの成果反映が上手く行ってない
- bitbucket 内部での反映伝播が遅い

上記のいずれかではないでしょうか?

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

flied onion

unread,
Jun 4, 2012, 10:27:10 AM6/4/12
to mercur...@googlegroups.com
原因はわかりました・・・。
が、対策は不明です。

patch seriesタブを開くと
「解析に失敗した。series ファイルがみつからない、コミットした?」
というエラーでした。

で、tortoiseHg の MQ表示で、QCommitを選び、seriesとstatusが対象になっていなかったので、加えてみて、hg push --mqしたところうまくいきました。
(patch queueタブに正しく表示されました)

本来はseriesやstatusはどこで加えてやるべきものなんでしょう?

私がうまくいかなかった手順としては

qcloneはコマンドプロンプトで行う(TortoiseHgのhgでqclone)
MQのパッチ作成、パッチ更新はTortoiseHgで行う
hg commit --mq はコマンドプロンプトで行う
hg push --mq はコマンドプロンプトで行う

(なぜコマンドプロンプト併用しているかと言われれば、対応するTortoiseHgでの操作がどれにあたるかわからなかったからです。
「qcommitは今は使わないという記述をどこかでみかけたし、commit --mqがqcommitと同じかわからなかった」
「qcloneはcloneオプションでパッチキューも取得というのがあったが、同じかわからなかった」
「push --mqは見当たらなかった」)

になります。

# なんかだんだん話題が変わってきて恐縮です(^_^;


flied onion

unread,
Jun 4, 2012, 11:04:53 AM6/4/12
to mercur...@googlegroups.com
自己解決しました・・・patch queue作るときにOmit seriesつけてました

二度目のトライだったので「すでにパッチがあるなら・・・」的な文言に惹かれてチェックした記憶があります。
わかってみれば当然ですね。お恥ずかしい orz

Katsunori FUJIWARA

unread,
Jun 4, 2012, 11:12:54 AM6/4/12
to mercur...@googlegroups.com
藤原です。

だいぶ表題と離れた話題になってきましたが、とりあえず続行します(笑)。

2012年6月4日 23:27 flied onion <flied...@gmail.com>:

> patch seriesタブを開くと
> 「解析に失敗した。series ファイルがみつからない、コミットした?」
> というエラーでした。
>
> で、tortoiseHg の MQ表示で、QCommitを選び、seriesとstatusが対象になっていなかったので、加えてみて、hg push
> --mqしたところうまくいきました。
> (patch queueタブに正しく表示されました)
>
> 本来はseriesやstatusはどこで加えてやるべきものなんでしょう?

私はもっぱら CUI 上で "hg init --mq" でキューの hg 管理初期化をし
てます。この時点で自動的に series 等の管理ファイルを追加してくれま
す。

画面上には series や .hgignore 追加の表示はないですが、"hg status
--mq" で確認するとちゃんと追加されてますね。

> 私がうまくいかなかった手順としては
>
> qcloneはコマンドプロンプトで行う(TortoiseHgのhgでqclone)
> MQのパッチ作成、パッチ更新はTortoiseHgで行う
> hg commit --mq はコマンドプロンプトで行う
> hg push --mq はコマンドプロンプトで行う

commit 対象に sereis が無かったということは、ひょっとして qclone
元の ".hg/patches" 配下に series が無かった(or 当該リビジョンが無
かった)のでは?

# 私が『strip すれば上手くいくかも?』とか言った際のリポジトリ?

--
----------------------------------------------------------------------
FUJIWARA Katsunori(flying...@gmail.com)

Yuya Nishihara

unread,
Jun 4, 2012, 11:13:08 AM6/4/12
to mercur...@googlegroups.com
こんにちは。西原です。

On Mon, 4 Jun 2012 07:27:10 -0700 (PDT), flied onion wrote:
> patch seriesタブを開くと
> 「解析に失敗した。series ファイルがみつからない、コミットした?」
> というエラーでした。
>
> で、tortoiseHg の MQ表示で、QCommitを選び、seriesとstatusが対象になって
> いなかったので、加えてみて、hg push --mqしたところうまくいきました。
> (patch queueタブに正しく表示されました)

あ、 status は適用したパッチを覚えているファイルなので、コミット対象外ですよ。

> 本来はseriesやstatusはどこで加えてやるべきものなんでしょう?

コマンドラインだと、 "hg init --mq" (= "hg qinit")した時に add されます。
併せて status などを除外するための .hgignore もできます。
GUI だと「MQ リポジトリを作成」ボタンを押した時みたいです。

flied onion

unread,
Jun 14, 2012, 8:19:54 AM6/14/12
to mercur...@googlegroups.com
flied onionです。

遅くなってしまいましたが、回答ありがとうございます。

> あ、 status は適用したパッチを覚えているファイルなので、コミット対象外ですよ。 

そうなんですね、正しくOmit seriesしたときも、statusをコミットしないように気をつけます。
Omit seriesの時は手元に一式(series等)あるだろうからあえて作らないって事なんですね。


2012年6月5日火曜日 0時13分08秒 UTC+9 Yuya Nishihara:
Reply all
Reply to author
Forward
0 new messages