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)
藤原です。お返事遅れて済みません。
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)
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" の方が良かった
です(笑)。
> 設定無しの場合に使用される ascii が『utf-8 以外』に該当してしまう
> ので、これも除外対象に含めておいた方が良いかもれません。
> そういった意味では、"_no_local_encoding()" みたいな名前の方が良い
> かもしれませんね > _get_localencode_is_utf8()
>この処理ですが、cp932 環境で utf-8 化されたファイル名が保存される
>可能性はどの程度でしょう?
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)
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)
bitbucket での "patch queue" では、親リポジトリ毎 clone されます。
色々混乱させてしまい済みませんでした 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)
だいぶ表題と離れた話題になってきましたが、とりあえず続行します(笑)。
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)