hirobeさんの許可をいただいて、
リポジトリの全文検索 with HyperEstraier プラグイン Ver 0.1
http://coderepos.org/share/browser/platform/trac/plugins/searchhyperestraier
のtrac0.12対応(+機能追加)版をshibuya-tracにおいた。
@@ -0,0 +1,61 @@ | ||
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +import os | |
4 | +import time | |
5 | +import sys, string | |
6 | +from svn import core, fs, delta, repos | |
7 | +import codecs | |
8 | + | |
9 | +#argvs[1]:repository path | |
10 | +#argvs[2]:changeset folder | |
11 | +#argvs[3]:start revision | |
12 | +#argvs[4]:end revision | |
13 | +argvs = sys.argv #コマンドライン引数リスト | |
14 | +argc = len(argvs) #引数の個数 | |
15 | + | |
16 | +if (argc != 5): #5でなければ出る | |
17 | + usage(1) | |
18 | + | |
19 | +path = argvs[1] | |
20 | +path = core.svn_path_canonicalize(path) | |
21 | +repos_ptr = repos.open(path) | |
22 | +fs_ptr = repos.fs(repos_ptr) | |
23 | + | |
24 | +changeset_folder = argvs[2] | |
25 | + | |
26 | +start_rev = int(argvs[3]) | |
27 | +end_rev = int(argvs[4]) | |
28 | + | |
29 | +if start_rev>end_rev: | |
30 | + sys.exit(exit) | |
31 | + | |
32 | +rev = fs.youngest_rev(fs_ptr) | |
33 | +if start_rev>rev and end_rev>rev: | |
34 | + sys.exit(exit) | |
35 | + | |
36 | +if start_rev>rev: | |
37 | + start_rev=rev | |
38 | +if end_rev>rev: | |
39 | + end_rev=rev | |
40 | + | |
41 | +for current_rev in range(start_rev,end_rev+1): | |
42 | + #get comment log | |
43 | + log = fs.revision_prop(fs_ptr, current_rev, core.SVN_PROP_REVISION_LOG) or '' | |
44 | + | |
45 | + #make dir | |
46 | + folder_num = current_rev/1000 | |
47 | + file_folder = changeset_folder+'\\'+str(folder_num) | |
48 | + if not os.path.exists(file_folder): | |
49 | + os.makedirs(file_folder) | |
50 | + #make file | |
51 | + filename = file_folder+'\\'+str(current_rev)+'.txt' | |
52 | + f = open(filename, 'w') | |
53 | + f.write(log) | |
54 | + f.close() | |
55 | + #file update time | |
56 | + date = fs.revision_prop(fs_ptr, current_rev, core.SVN_PROP_REVISION_DATE) | |
57 | + aprtime = core.svn_time_from_cstring(date) | |
58 | + secs = aprtime / 1000000 # aprtime is microseconds; make seconds | |
59 | + timestr=time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(secs)) | |
60 | + atime = mtime = time.mktime(time.strptime(timestr, '%Y-%m-%d-%H:%M:%S')) | |
61 | + os.utime(filename, (atime, mtime)) |
@@ -0,0 +1,317 @@ | ||
1 | += !HyperEstraierによる全文検索プラグイン Ver 0.1(勝手にtrac0.12対応版) = | |
2 | +ここでは、Hirobeさん作、リポジトリ検索プラグインの[http://weekbuild.sakura.ne.jp/trac/wiki/TracDoc/SearchHyperEstraierPlugin SearchHyperEstraier]を[[BR]]「勝手に」修正し、trac0.12に対応、その他機能追加を行ったものについて記述してます。 | |
3 | + | |
4 | +== 1. 概要 == | |
5 | +全文検索を行うためのプラグインです。[[BR]] | |
6 | +trac0.12対応としてマルチリポジトリに対応しています。[[BR]] また、機能追加を行ってますので以下のような検索が行えます。[[BR]] | |
7 | + | |
8 | + * リポジトリからチェックアウトしたソースについての検索(従来から機能) | |
9 | + * チェンジセットのコミットログの検索 | |
10 | + * 添付ファイル内の文字列検索 | |
11 | + * ドキュメントディレクトリの文字列検索 | |
12 | + | |
13 | +仕組み:バッチを使い、リポジトリのソースやコミットログ、添付ファイルやドキュメントディレクトリの内容から、[[BR]]HyperEstraierのインデックスを生成します。[[BR]]そのインデックスを利用し、Trac内でコマンド版cmdestを実行、その結果を表示します。 | |
14 | + | |
15 | +'''制限''' | |
16 | + | |
17 | + * ソースの検索は、リポジトリ内の最新のファイルしか検索できません。 | |
18 | + * apacheからcmdest.exeを起動できるように権限設定が必要かもしれません。 | |
19 | + * Windowsでしか動作確認してません。 | |
20 | + * 動作は無保証です。 | |
21 | + | |
22 | +== 2. セットアップ == | |
23 | +インストール方法の後、構成例を挙げ、それに沿って、リポジトリ、チェンジセット、添付ファイル、ドキュメントの[[BR]] | |
24 | +それぞれの機能のセットアップを記述してます。[[BR]] | |
25 | +それぞれの機能は独立してますので、いくつかだけを有効にすることもできます。[[BR]] | |
26 | +必要な部分だけ読んでください。[[BR]] | |
27 | +設定例のファイル(makeindex.bat.sample,trac.ini.sample,updateindex.bat.sample)[[BR]] | |
28 | +やコミットログを出力するスクリプト(MkCommentFile.py)も添付してますので[[BR]] | |
29 | +ご利用下さい。 | |
30 | + | |
31 | +=== 2.0. インストール === | |
32 | +[http://fallabs.com/hyperestraier/ HyperEstraier]のWindows版バイナリパッケージの中の[[BR]] | |
33 | +estraier.dll,qdbm.dll,mgwz.dll,libiconv-2.dll, [[BR]]regex.dll,pthreadGC2.dll,estcmd.exe,estxfilt.bat,xdoc2txt.exe,zlib.dll[[BR]] | |
34 | +があればHyperEstraierを使えます。pathが通った場所においてください。[[BR]] | |
35 | +TracLightningであればインストールフォルダのbinフォルダがよいでしょう。 | |
36 | + | |
37 | +そしてこのプラグインを解凍、setup.pyがあるディレクトリに移動して、 | |
38 | +{{{ | |
39 | +python setup.py install | |
40 | +}}} | |
41 | +を実行してください。 | |
42 | +=== 2.1.ディレクトリ構成例 === | |
43 | +TracLightningでの使用を意識したディレクトリの構成例を示します。 | |
44 | + | |
45 | + * c:\TracLight | |
46 | + * projects | |
47 | + * svn | |
48 | + * pj1…default repository | |
49 | + * repos2 | |
50 | + * trac | |
51 | + * pj1 | |
52 | + * doc | |
53 | + * pj1 | |
54 | + * search | |
55 | + * repos | |
56 | + * pj1 | |
57 | + * rep | |
58 | + * casket | |
59 | + * repos2 | |
60 | + * rep | |
61 | + * casket | |
62 | + * changeset | |
63 | + * pj1 | |
64 | + * rep | |
65 | + * casket | |
66 | + * repos2 | |
67 | + * rep | |
68 | + * casket | |
69 | + * attach | |
70 | + * pj1 | |
71 | + * casket | |
72 | + * doc | |
73 | + * pj1 | |
74 | + * casket | |
75 | + | |
76 | +c:\TracLight\projectsはtracプロジェクトやリポジトリを含むディレクトリを示しています。[[BR]]ここでは、tracプロジェクト1つ(c:\TracLight\projects\trac\pj1)、[[BR]]それに対応するリポジトリ2つ(c:\TracLight\projects\svn\pj1,repos2)と[[BR]]ドキュメントディレクトリ1つ(c:\TracLight\projects\doc\pj1)にしてます。 | |
77 | + | |
78 | +c:\TracLight\searchはHyperEstraierで使用する検索用のindexデータ(casket)と、[[BR]]検索される内容を入れるディレクトリです。[[BR]]検索される内容としては、 | |
79 | + | |
80 | + * リポジトリからチェックアウトしたソース(c:\TracLight\search\repos\pj1\repとc:\TracLight\search\repos\repos2\rep) | |
81 | + * チェンジセットのコミットログ(c:\TracLight\search\changeset\pj1\repとc:\TracLight\search\changeset\repos2\rep) | |
82 | + | |
83 | +を配置してます。 | |
84 | + | |
85 | +=== 2.2.リポジトリ === | |
86 | +リポジトリからエクスポートしたソースを検索する設定です。[[BR]] | |
87 | +※tracへのリポジトリの登録は事前にしておいてください。 | |
88 | +==== 2.2.1 エクスポート/インデックス生成バッチファイルの作成 ==== | |
89 | +リポジトリのエクスポートとインデックス生成を行うバッチを作成します。 | |
90 | + | |
91 | +上図に沿ったバッチファイルの例を示します。 | |
92 | + | |
93 | +{{{ | |
94 | +set EXPORT_FOLDER=c:\TracLight\search\repos\pj1\rep | |
95 | +set INDEX_FOLDER=c:\TracLight\search\repos\pj1\casket | |
96 | +set REPOS_URI=file:///C:/TracLight/projects/svn/pj1/trunk | |
97 | + | |
98 | +rmdir /S /Q %EXPORT_FOLDER% | |
99 | +rmdir /S /Q %INDEX_FOLDER% | |
100 | +svn export %REPOS_URI% %EXPORT_FOLDER% | |
101 | +estcmd gather -cl -fx .pdf,.rtf,.doc,.xls,.ppt T@estxfilt -ic CP932 -pc CP932 -sd %INDEX_FOLDER% %EXPORT_FOLDER% | |
102 | +}}} | |
103 | +上記バッチファイルでは、冒頭部の環境変数により設定をしています。 | |
104 | + | |
105 | +|| EXPORT_FOLDER || リポジトリのエクスポート先となるディレクトリ。空のディレクトリを指定。 || | |
106 | +|| REPOS_URI || エクスポート元となるリポジトリのURI || | |
107 | +|| INDEX_FOLDER || インデックスの生成先ディレクトリ。空のディレクトリを指定。 || | |
108 | + | |
109 | +適切に書き換えてご使用ください。[[BR]]なお、リポジトリのエクスポートの認証は考慮してません。認証が必要であればsvn exportに適切な引数を設定してください。[[BR]] 通常は上記のようにtrunkなどリポジトリの一部を指定します。[[BR]](全体にしてしまうとtagsやbranchesの中身もチェックアウトしてしまいます。)[[BR]]また、上記バッチファイルはフルパス指定であるため、どこにおいてもかまいませんが、[[BR]]tracプロジェクトのconfディレクトリなどにおくのが管理しやすいと思います。[[BR]] また上記では「.pdf,.rtf,.doc,.xls,.ppt」の拡張子のファイルしか検索しません。[[BR]] .txtや.cなどテキストファイルであればestxfilt.batで呼ばれる[[BR]]xdoc2txtはスルーで出しますので[[BR]]「,.txt」のように-fxの後に続く拡張子の列挙の後追記してください。 | |
110 | + | |
111 | +この例ではpj1リポジトリのみ設定してますが、バッチファイル中の「pj1」を[[BR]] 「repos2」に置き換えて下方に同様の処理を書くか、別のバッチファイルを作るかすれば[[BR]] 対応できます。 | |
112 | +==== 2.2.2 trac.iniの設定 ==== | |
113 | +テキストファイルでtrac.ini(上図ではc:\TracLight\projects\trac\pj1\conf配下)を開いて [searchhyperestraier]というブロックを追加してください。 | |
114 | + | |
115 | +|| xxx.index_path || インデックス生成パス(バッチファイルのINDEX_FOLDER) || | |
116 | +|| xxx.replace_left || 検索結果のパスの頭で削るべき文字列。 || | |
117 | +|| xxx.url_left || URLを生成する際に頭につける文字列。browse_trac=enabledの場合は/がリポジトリのルートになるようにすること。 || | |
118 | +|| browse_trac || Tracのブラウザへのリンクを作るか否か。enabled=Tracのブラウザへのリンクを作る。リポジトリソース検索共通の機能。デフォルトは'enabled'。 || | |
119 | +|| estcmd_path || 環境変数PATHが設定済みなら設定不要。estcmd.exeの絶対パス。すべての機能に共通の機能。デフォルトは'estcmd' || | |
120 | +|| estcmd_arg || Windowsでは設定不要。estcmd.exeの引数。すべての機能に共通の機能。デフォルトは'search -vx -sf -ic Shift_JIS' || | |
121 | +|| estcmd_encode || Windowsでは設定不要。コマンド実行時のエンコード(Pythonでの形式)。すべての機能に共通の機能。デフォルトは'mbcs' || | |
122 | + | |
123 | + ここではdefaultリポジトリであるかを意識して設定する必要があります。[[BR]] 上表で「xxx」になっている部分はリポジトリ名を記述します。[[BR]] ただし、defaultリポジトリであれば、何も書きません。[[BR]] たとえば、「.index_path」のように記述します[[BR]] | |
124 | +(元のSearchHyperEstraierを使っていた人は変更が必要です)。[[BR]] | |
125 | +index_path,replace_left,url_leftはリポジトリごとに設定できます。[[BR]] | |
126 | + | |
127 | +例: | |
128 | + | |
129 | +{{{ | |
130 | +[searchhyperestraier] | |
131 | +.index_path = C:\TracLight\search\repos\pj1\casket | |
132 | +.replace_left = C:\TracLight\search\repos\pj1\rep | |
133 | +.url_left = /trunk | |
134 | +repos2.index_path = C:\TracLight\search\repos\repos2\casket | |
135 | +repos2.replace_left = C:\TracLight\search\repos\repos2\rep | |
136 | +repos2.url_left = /trunk | |
137 | +}}} | |
138 | +browser_tracがenabledになる場合は、登録されるURLはTracのリポジトリブラウザでRoot直下が/となるように replace_left,url_leftを調整する必要があります。[[BR]]たとえば、リポジトリブラウザでRoot/trunk/test3/検索のテスト.docと表示されるファイルは、/trunk/test3/検索のテスト.docとなるように調整してください。[[BR]]難しければ、何も設定せずに、検索結果として表示されたURLを見ながら調整してください。[[BR]]通常、EXPORT_FOLDER=replace_left、INDEX_FOLDER=index_pathになります。[[BR]] | |
139 | + | |
140 | +また、[components]ブロックでこの機能を有効にしてください。 | |
141 | + | |
142 | +{{{ | |
143 | +[components] | |
144 | +searchhyperestraier.searchhyperestraier.searchhyperestraiermodule = enabled | |
145 | +}}} | |
146 | +=== 2.3.チェンジセット === | |
147 | +「direct-svnfs」専用です。[[BR]] | |
148 | +チェンジセットはtracにも機能がありますが、[[BR]] | |
149 | +typeが「direct-svnfs」の場合、DBに取り込まれないので[[BR]] | |
150 | +検索できません。そういう場合にお使いください。[[BR]] | |
151 | +「direct-svnfs」以外のものは検索しないようにしてますので[[BR]] | |
152 | +併用していただいても大丈夫です。[[BR]] | |
153 | + | |
154 | +※tracへのリポジトリの登録は事前にしておいてください。 | |
155 | +==== 2.3.1.コミットログファイル/インデックス生成バッチファイルの作成 ==== | |
156 | +コミットログを一つ一つのファイルとして出力し、インデックス生成を行うバッチを作成します。[[BR]] | |
157 | +コミットログをファイルとして出力するために、MkCommentFile.pyというスクリプトを[[BR]] | |
158 | +用意しました。[[BR]] | |
159 | + | |
160 | +上図に沿ったバッチファイルの例を示します。 | |
161 | + | |
162 | +{{{ | |
163 | +set EXPORT_FOLDER=c:\TracLight\search\changeset\pj1\rep | |
164 | +set INDEX_FOLDER=c:\TracLight\search\changeset\pj1\casket | |
165 | +set REPOS_FOLDER=C:/TracLight/projects/svn/pj1 | |
166 | + | |
167 | +for /F %%i in ('svnlook youngest %REPOS_FOLDER%') do set LASTREVISION=%%i | |
168 | +python MkCommentFile.py %REPOS_FOLDER% %EXPORT_FOLDER% 1 %LASTREVISION% | |
169 | +estcmd gather -cl -fx.pdf,.rtf,.doc,.xls,.ppt T@estxfilt -ic CP932 -pc CP932 -sd %INDEX_FOLDER% %EXPORT_FOLDER% | |
170 | + | |
171 | +}}} | |
172 | +2.2.1.と同様、上記バッチファイルでは、冒頭部の環境変数により設定をしています。 | |
173 | + | |
174 | +|| EXPORT_FOLDER || コミットログが入るディレクトリ。空のディレクトリを指定。 || | |
175 | +|| REPOS_FOLDER || 対象リポジトリのディレクトリ。ここではtrunkなどの指定をしません。 || | |
176 | +|| INDEX_FOLDER || インデックスの生成先ディレクトリ。空のディレクトリを指定。 || | |
177 | + | |
178 | +適切に書き換えてご使用ください。 | |
179 | + | |
180 | +この例ではpj1リポジトリのみ設定してますが、バッチファイル中の「pj1」を[[BR]] 「repos2」に置き換えて下方に同様の処理を書くか、別のバッチファイルを作るかすれば[[BR]] 対応できます。 | |
181 | +==== 2.3.2.trac.iniの設定 ==== | |
182 | +trac.iniを開いて [searchhyperestraier]ブロックに追加してください。 | |
183 | + | |
184 | +|| xxx.cs_index_path || インデックス生成パス(バッチファイルのINDEX_FOLDER) || | |
185 | + | |
186 | +2.2.2.と同様、ここではdefaultリポジトリであるかを意識して設定する必要があります。[[BR]] 上表で「xxx」になっている部分はリポジトリ名を記述します。[[BR]] ただし、defaultリポジトリであれば、何も書きません。[[BR]] 「.cs_index_path」のように記述します。[[BR]] | |
187 | +xxxの部分を変えて設定することでリポジトリごとに設定できます。[[BR]] | |
188 | + | |
189 | +例: | |
190 | + | |
191 | +{{{ | |
192 | +[searchhyperestraier] | |
193 | +.cs_index_path = C:\TracLight\search\changeset\pj1\casket | |
194 | +repos2.cs_index_path = C:\TracLight\search\changeset\repos2\casket | |
195 | +}}} | |
196 | + | |
197 | +また、[components]ブロックでこの機能を有効にしてください。 | |
198 | + | |
199 | +{{{ | |
200 | +[components] | |
201 | +searchhyperestraier.searchhyperestraier.searchchangesethyperestraiermodule = enabled | |
202 | +}}} | |
203 | +=== 2.4.添付ファイル === | |
204 | +tracのチケットやwikiの添付ファイル中の文字列検索を行うための設定です。 | |
205 | +==== 2.4.1.インデックス生成バッチファイルの作成 ==== | |
206 | +インデックス生成を行うバッチを作成します。[[BR]] | |
207 | + | |
208 | +上図に沿ったバッチファイルの例を示します。 | |
209 | + | |
210 | +{{{ | |
211 | +set INDEX_FOLDER=c:\TracLight\search\attach\pj1\casket | |
212 | +set ATT_FOLDER=c:\TracLight\projects\trac\pj1\attachments | |
213 | + | |
214 | +estcmd gather -cl -fx .pdf,.rtf,.doc,.xls,.ppt,.c,.asm,.py,.txt T@estxfilt -ic CP932 -pc CP932 -sd %INDEX_FOLDER% %ATT_FOLDER% | |
215 | +}}} | |
216 | +2.2.1.と同様、上記バッチファイルでは、冒頭部の環境変数により設定をしています。 | |
217 | + | |
218 | +|| ATT_FOLDER || tracの添付ファイルディレクトリ。tracプロジェクトのattachmentsディレクトリを指定。 || | |
219 | +|| INDEX_FOLDER || インデックスの生成先ディレクトリ。空のディレクトリを指定。 || | |
220 | + | |
221 | +適切に書き換えてご使用ください。 | |
222 | + | |
223 | +==== 2.4.2.trac.iniの設定 ==== | |
224 | +trac.iniを開いて [searchhyperestraier]ブロックに追加してください。 | |
225 | + | |
226 | +|| att_index_path || インデックス生成パス(バッチファイルのINDEX_FOLDER) || | |
227 | + | |
228 | +単純にインデックス生成パスを設定してください。 | |
229 | + | |
230 | +例: | |
231 | + | |
232 | +{{{ | |
233 | +[searchhyperestraier] | |
234 | +att_index_path = C:\TracLight\search\attach\pj1\casket | |
235 | +}}} | |
236 | + | |
237 | +また、[components]ブロックでこの機能を有効にしてください。 | |
238 | + | |
239 | +{{{ | |
240 | +[components] | |
241 | +searchhyperestraier.searchhyperestraier.searchattachmenthyperestraiermodule = enabled | |
242 | +}}} | |
243 | +=== 2.5.ドキュメント === | |
244 | +ドキュメントディレクトリにある指定ファイル中の文字列検索を行うための設定です。 | |
245 | +ドキュメントディレクトリがブラウザで見られるようにhttpd.confを設定しておく必要があります。 | |
246 | +例 | |
247 | +{{{ | |
248 | +Alias /doc "c:\tracpj\doc" | |
249 | +<Directory "c:\tracpj\doc"> | |
250 | + Options Indexes | |
251 | + IndexOptions +FancyIndexing +NameWidth=* +SuppressDescription +SuppressIcon | |
252 | + Allow from all | |
253 | +</Directory> | |
254 | +}}} | |
255 | +==== 2.5.1.インデックス生成バッチファイルの作成 ==== | |
256 | +インデックス生成を行うバッチを作成します。[[BR]] | |
257 | + | |
258 | +上図に沿ったバッチファイルの例を示します。 | |
259 | + | |
260 | +{{{ | |
261 | +set DOC_FOLDER=c:\TracLight\projects\doc\pj1 | |
262 | +set INDEX_FOLDER=c:\TracLight\search\doc\pj1\casket | |
263 | + | |
264 | +estcmd gather -cl -fx .pdf,.rtf,.doc,.xls,.ppt,.c,.asm,.py,.txt T@estxfilt -ic CP932 -pc CP932 -sd %INDEX_FOLDER% %DOC_FOLDER% | |
265 | +}}} | |
266 | +2.2.1.と同様、上記バッチファイルでは、冒頭部の環境変数により設定をしています。 | |
267 | + | |
268 | +|| DOC_FOLDER || ドキュメントディレクトリ。 || | |
269 | +|| INDEX_FOLDER || インデックスの生成先ディレクトリ。空のディレクトリを指定。 || | |
270 | + | |
271 | +適切に書き換えてご使用ください。 | |
272 | + | |
273 | +==== 2.5.2.trac.iniの設定 ==== | |
274 | +trac.iniを開いて [searchhyperestraier]ブロックに追加してください。 | |
275 | + | |
276 | +|| doc_index_path || インデックス生成パス(バッチファイルのINDEX_FOLDER) || | |
277 | +|| doc_replace_left || 検索結果のパスの頭で削るべき文字列(バッチファイルのDOC_FOLDER)。 || | |
278 | +|| doc_url_left || URLを生成する際に頭につける文字列。 || | |
279 | + | |
280 | +単純にインデックス生成パスを設定してください。 | |
281 | + | |
282 | +例: | |
283 | + | |
284 | +{{{ | |
285 | +[searchhyperestraier] | |
286 | +doc_index_path = C:\TracLight\search\doc\pj1\casket | |
287 | +doc_replace_left = c:\TracLight\projects\doc\pj1 | |
288 | +doc_url_left = /doc/pj1 | |
289 | +}}} | |
290 | + | |
291 | +また、[components]ブロックでこの機能を有効にしてください。 | |
292 | + | |
293 | +{{{ | |
294 | +[components] | |
295 | +searchhyperestraier.searchhyperestraier.searchdocumenthyperestraiermodule = enabled | |
296 | +}}} | |
297 | +== 3. apacheを再起動する == | |
298 | +trac.iniを設定したら、apacheを再起動してください。[[BR]](「サービスのアンインストール」を実行、再度「サービスのインストール」を実行。) | |
299 | + | |
300 | +== 4. バッチファイルを実行する == | |
301 | +作成したバッチファイルを実行してください。 | |
302 | + | |
303 | +== 5. 検索してみる == | |
304 | +検索タブをクリックして、チェックボックスが表示されることを確認してください。[[BR]]同様の機能と区別するため、頭に「he:」と表記してます。[[BR]] | |
305 | +he:リポジトリ,he:添付ファイル,he:チェンジセット,he:ドキュメントのうち[[BR]] | |
306 | +機能を有効にしているものが表示されているか確認してください。[[BR]] | |
307 | +リポジトリは'BROWSER_VIEW'、チェンジセットは'CHANGESET_VIEW'、[[BR]] | |
308 | +添付ファイルatt_index_pathが設定されていること、 | |
309 | +ドキュメントはdoc_index_path,doc_replace_left,doc_url_leftが[[BR]] | |
310 | +設定されていることが表示条件です。[[BR]] | |
311 | +表示されていればチェックを入れ、適当なキーワードで検索して、結果を確認してください。[[BR]]リンクをクリックして、画面がリポジトリブラウザに切り替わり、正しくそのファイルを表示していることを確認してください。 | |
312 | + | |
313 | +== 6. バッチファイルをタスク設定する == | |
314 | +動作確認ができたら必要なバッチファイルが1日1回実行できるようにWindowsのタスクを設定してください。[[BR]] 2000またはXPでは、タスクの追加は、以下のように行います。[[BR]] [スタート]メニューから[プログラム]-[アクセサリ]-[システムツール]-[タスク][[BR]] または[[BR]] [コントロール パネル]の[タスク][[BR]] を開き、[スケジュールされたタスクの追加]をクリックします。[[BR]] するとタスクウィザードが起動します。[[BR]] 「実行するプログラムを1つ選択してください。」のところで、[[BR]] 参照ボタンを押し、バッチファイルを指定してください。[[BR]] 「このタスクの実行」で「日単位」を選択してください。[[BR]] その後、開始日時などを設定します。[[BR]] 最後にユーザー名とパスワードの入力を行って終了です。[[BR]] 完了ボタンを押すと登録されます。 | |
315 | + | |
316 | +== 7. 設定時刻を待たずにすぐ更新する == | |
317 | +もし、設定時刻を待たずにすぐ更新したい場合は、[[BR]] バッチファイルを直接実行してください。 | |
\ No newline at end of file |
@@ -0,0 +1,14 @@ | ||
1 | +from setuptools import find_packages, setup | |
2 | + | |
3 | +setup( | |
4 | + name='TracHyperestraierPlugin', version='0.1-k-trac0.12', | |
5 | + packages=find_packages(exclude=['*.tests*']), | |
6 | + entry_points = """ | |
7 | + [trac.plugins] | |
8 | + searchhyperestraier.searchhyperestraier = searchhyperestraier.searchhyperestraier | |
9 | + searchhyperestraier.searchattachmenthyperestraier = searchhyperestraier.searchattachmenthyperestraier | |
10 | + searchhyperestraier.searchdocumenthyperestraier = searchhyperestraier.searchdocumenthyperestraier | |
11 | + searchhyperestraier.searchchangesethyperestraier = searchhyperestraier.searchchangesethyperestraier | |
12 | + """, | |
13 | +) | |
14 | + |
@@ -0,0 +1,413 @@ | ||
1 | +# -*- coding: utf-8 -*- | |
2 | +# SearchRepositoryWithHyperestraier plugin | |
3 | + | |
4 | +from trac.core import * | |
5 | +#from trac.Search import ISearchSource | |
6 | +from trac.search.api import ISearchSource # for Trac0.11 | |
7 | +from trac.util import NaivePopen | |
8 | +from StringIO import StringIO | |
9 | +import urllib | |
10 | +import time | |
11 | +from xml.dom.minidom import parseString | |
12 | +import datetime | |
13 | +from trac.util.datefmt import to_datetime, utc # for Trac0.11 | |
14 | +from trac.util.text import to_unicode # for Trac0.11 | |
15 | +from trac.versioncontrol import RepositoryManager | |
16 | +import os.path | |
17 | + | |
18 | +class SearchHyperEstraierModule(Component): | |
19 | + implements(ISearchSource) | |
20 | + | |
21 | + # ISearchProvider methods | |
22 | + def get_search_filters(self, req): | |
23 | + if req.perm.has_permission('BROWSER_VIEW'): | |
24 | + yield ('repositoryhyperest', u'he:リポジトリ', 0) | |
25 | + | |
26 | + def get_search_results(self, req, terms, filters): | |
27 | + if not 'repositoryhyperest' in filters: | |
28 | + return | |
29 | + #estcmd.exeのパス | |
30 | + estcmd_path = self.env.config.get('searchhyperestraier', 'estcmd_path','estcmd') | |
31 | + #estcmd.exeの引数 | |
32 | + estcmd_arg = self.env.config.get('searchhyperestraier', 'estcmd_arg','search -vx -sf -ic Shift_JIS') | |
33 | + estcmd_encode = self.env.config.get('searchhyperestraier', 'estcmd_encode','mbcs') | |
34 | + #Tracのブラウザへのリンクを作るか否か。 | |
35 | + #enabled:Tracのブラウザへのリンクを作る | |
36 | + #上記以外:replace_left,url_leftで指定したURLへのリンクを作る | |
37 | + browse_trac = self.env.config.get('searchhyperestraier', 'browse_trac','enabled') | |
38 | + | |
39 | + #for multi repos | |
40 | + for option in self.config['searchhyperestraier']: | |
41 | + #リポジトリのパス | |
42 | + if not option.endswith('.index_path'): | |
43 | + continue | |
44 | + mrepstr = option[:-len('.index_path')] #'.index_path'の前の文字列がreponame | |
45 | + if RepositoryManager(self.env).get_repository(mrepstr) is None: #mrepstrのrepositoryがない | |
46 | + continue | |
47 | + #インデックスのパス | |
48 | + index_path = self.env.config.get('searchhyperestraier', mrepstr+'.index_path','') | |
49 | + if index_path == '':#mrepstr+'.index_path'がない | |
50 | + continue | |
51 | + #検索結果のパスの頭で削る文字列 | |
52 | + replace_left = self.env.config.get('searchhyperestraier', mrepstr+'.replace_left','') | |
53 | + if replace_left == '': #mrepstr+'.replace_left'がない | |
54 | + continue | |
55 | + #URLを生成する際に頭につける文字列 | |
56 | + #browse_trac=enabledの場合は/がリポジトリのルートになるように | |
57 | + url_left = self.env.config.get('searchhyperestraier', mrepstr+'.url_left','') | |
58 | + if url_left == '': #mrepstr+'.url_left'がない | |
59 | + continue | |
60 | + if mrepstr != '': #defaultでない | |
61 | + url_left = '/' + mrepstr + url_left | |
62 | + | |
63 | + #cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,index_path,unicode(query,'utf-8').encode('CP932')) | |
64 | + qline = ' '.join(terms) | |
65 | + cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,index_path,qline) | |
66 | + self.log.debug('SearchHyperEstraier:%s' % cmdline) | |
67 | + cmdline = unicode(cmdline).encode(estcmd_encode) | |
68 | + np = NaivePopen(cmdline) | |
69 | + #self.log.debug('Result:%s' % unicode(np.out,'utf-8').encode('mbcs')) | |
70 | + #self.log.debug('Result:%s' % np.out) | |
71 | + if np.errorlevel or np.err: | |
72 | + err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, | |
73 | + np.err) | |
74 | + raise Exception, err | |
75 | + if np.out=='': #何も入ってない | |
76 | + continue | |
77 | + dom = parseString(np.out) | |
78 | + root = dom.documentElement | |
79 | + #estresult_node = root.getElementsByTagName("document")[0] | |
80 | + element_array = root.getElementsByTagName("document") | |
81 | + for element in element_array: | |
82 | + #self.log.debug('Result:%s' % 'hoge') | |
83 | + url = "" | |
84 | + title = "" | |
85 | + date = 0 | |
86 | + detail = "" | |
87 | + author = "不明" | |
88 | + | |
89 | + #detailを生成 | |
90 | + elem_array = element.getElementsByTagName("snippet") | |
91 | + detail = self._get_innerText("",elem_array) | |
92 | + | |
93 | + #その他の属性を生成 | |
94 | + attrelem_array = element.getElementsByTagName("attribute") | |
95 | + for attrelem in attrelem_array: | |
96 | + attr_name = attrelem.getAttribute("name") | |
97 | + attr_value = unicode(attrelem.getAttribute("value")) | |
98 | + #URLとタイトルを生成 | |
99 | + #if attr_name == "_lreal": #"_lreal"ではファイル名に' 'などが入っている場合対応できない | |
100 | + # attr_value=attr_value[len(replace_left):].replace("\\","/") | |
101 | + # if browse_trac == "enabled": | |
102 | + # url = self.env.href.browser(url_left + attr_value) | |
103 | + # title = "source:"+ url_left + attr_value | |
104 | + # else: | |
105 | + # url = url_left + attr_value | |
106 | + # title = url_left + attr_value | |
107 | + if attr_name == "_lpath": #s-jisをquoteしたもの("file:///C|/TracLight/…"の形式) | |
108 | + attr_value = urllib.unquote(attr_value).encode('raw_unicode_escape').decode('CP932') | |
109 | + attr_value = attr_value[(len('file:///')+len(replace_left)):] | |
110 | + if browse_trac == "enabled": | |
111 | + url = self.env.href.browser(url_left + attr_value) | |
112 | + title = "source:"+ urllib.unquote(url).encode('raw_unicode_escape').decode('utf-8') | |
113 | + else: | |
114 | + url = url_left + attr_value | |
115 | + title = urllib.unquote(url).encode('raw_unicode_escape').decode('utf-8') | |
116 | + #更新日時を生成 | |
117 | + elif attr_name =="@mdate": | |
118 | + date = time.strptime(attr_value,"%Y-%m-%dT%H:%M:%SZ") | |
119 | + self.log.debug('date:%s' % attr_value) | |
120 | + date = to_datetime(datetime.datetime(date[0],date[1],date[2],date[3],date[4],date[5],0,utc)) # for Trac0.11 | |
121 | + yield(url,title,date,to_unicode(author,'utf-8'),to_unicode(detail,'utf-8')) | |
122 | + return | |
123 | + | |
124 | + #XMLのElementを再帰的に探してテキストを生成 | |
125 | + def _get_innerText(self,text,node_array): | |
126 | + for node in node_array: | |
127 | + if node.nodeType == node.TEXT_NODE: | |
128 | + text = text + unicode(node.data).encode('utf-8') | |
129 | + else: | |
130 | + text = self._get_innerText(text,node.childNodes) | |
131 | + return text | |
132 | + | |
133 | +class SearchChangesetHyperEstraierModule(Component): | |
134 | + implements(ISearchSource) | |
135 | + | |
136 | + # ISearchProvider methods | |
137 | + def get_search_filters(self, req): | |
138 | + if req.perm.has_permission('CHANGESET_VIEW'): | |
139 | + yield ('changesethyperest', u'he:チェンジセット', 0) | |
140 | + | |
141 | + def get_search_results(self, req, terms, filters): | |
142 | + if not 'changesethyperest' in filters: | |
143 | + return | |
144 | + #estcmd.exeのパス | |
145 | + estcmd_path = self.env.config.get('searchhyperestraier', 'estcmd_path','estcmd') | |
146 | + #estcmd.exeの引数 | |
147 | + estcmd_arg = self.env.config.get('searchhyperestraier', 'estcmd_arg','search -vx -sf -ic Shift_JIS') | |
148 | + estcmd_encode = self.env.config.get('searchhyperestraier', 'estcmd_encode','mbcs') | |
149 | + | |
150 | + #for multi repos | |
151 | + for option in self.config['searchhyperestraier']: | |
152 | + #リポジトリのパス | |
153 | + if not option.endswith('.cs_index_path'): | |
154 | + continue | |
155 | + mrepstr = option[:-len('.cs_index_path')] #'.cs_index_path'の前の文字列がreponame | |
156 | + if RepositoryManager(self.env).get_repository(mrepstr) is None: #mrepstrのrepositoryがない | |
157 | + continue | |
158 | + repoinfo = RepositoryManager(self.env).get_all_repositories().get(mrepstr, {}) | |
159 | + #self.log.debug('type:%s' % repoinfo.get('type')) | |
160 | + if repoinfo.get('type') != 'direct-svnfs':#'direct-svnfs'のリポジトリでない | |
161 | + continue | |
162 | + #インデックスのパス | |
163 | + cs_index_path = self.env.config.get('searchhyperestraier', mrepstr+'.cs_index_path','') | |
164 | + if cs_index_path == '':#mrepstr+'.cs_index_path'がない | |
165 | + continue | |
166 | + if mrepstr != '': #defaultでない | |
167 | + mrepstr = '/' + mrepstr | |
168 | + | |
169 | + #cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,cs_index_path,unicode(query,'utf-8').encode('CP932')) | |
170 | + qline = ' '.join(terms) | |
171 | + cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,cs_index_path,qline) | |
172 | + self.log.debug('SearchChangesetHyperEstraier:%s' % cmdline) | |
173 | + cmdline = unicode(cmdline).encode(estcmd_encode) | |
174 | + np = NaivePopen(cmdline) | |
175 | + #self.log.debug('Result:%s' % unicode(np.out,'utf-8').encode('mbcs')) | |
176 | + #self.log.debug('Result:%s' % np.out) | |
177 | + if np.errorlevel or np.err: | |
178 | + err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, | |
179 | + np.err) | |
180 | + raise Exception, err | |
181 | + if np.out=='': #何も入ってない | |
182 | + continue | |
183 | + dom = parseString(np.out) | |
184 | + root = dom.documentElement | |
185 | + #estresult_node = root.getElementsByTagName("document")[0] | |
186 | + element_array = root.getElementsByTagName("document") | |
187 | + for element in element_array: | |
188 | + #self.log.debug('Result:%s' % 'hoge') | |
189 | + url = "" | |
190 | + title = "" | |
191 | + date = 0 | |
192 | + detail = "" | |
193 | + author = "不明" | |
194 | + | |
195 | + #detailを生成 | |
196 | + elem_array = element.getElementsByTagName("snippet") | |
197 | + detail = self._get_innerText("",elem_array) | |
198 | + | |
199 | + #その他の属性を生成 | |
200 | + attrelem_array = element.getElementsByTagName("attribute") | |
201 | + for attrelem in attrelem_array: | |
202 | + attr_name = attrelem.getAttribute("name") | |
203 | + attr_value = unicode(attrelem.getAttribute("value")) | |
204 | + #URLとタイトルを生成 | |
205 | + if attr_name == "_lreal": | |
206 | + attr_value=attr_value.replace(".txt","") | |
207 | + end = len(attr_value) | |
208 | + for m in range(1,end): | |
209 | + if not attr_value[(end-m):].isdigit(): | |
210 | + break | |
211 | + attr_value = attr_value[(end-m+1):] + mrepstr #数字の文字列 + mrepstr | |
212 | + url = self.env.href('/changeset/' + attr_value ) | |
213 | + title = "changeset:" + attr_value | |
214 | + #更新日時を生成 | |
215 | + elif attr_name =="@mdate": | |
216 | + date = time.strptime(attr_value,"%Y-%m-%dT%H:%M:%SZ") | |
217 | + self.log.debug('date:%s' % attr_value) | |
218 | + date = to_datetime(datetime.datetime(date[0],date[1],date[2],date[3],date[4],date[5],0,utc)) # for Trac0.11 | |
219 | + yield(url,title,date,to_unicode(author,'utf-8'),to_unicode(detail,'utf-8')) | |
220 | + return | |
221 | + | |
222 | + #XMLのElementを再帰的に探してテキストを生成 | |
223 | + def _get_innerText(self,text,node_array): | |
224 | + for node in node_array: | |
225 | + if node.nodeType == node.TEXT_NODE: | |
226 | + text = text + unicode(node.data).encode('utf-8') | |
227 | + else: | |
228 | + text = self._get_innerText(text,node.childNodes) | |
229 | + return text | |
230 | + | |
231 | +class SearchAttachmentHyperEstraierModule(Component): | |
232 | + implements(ISearchSource) | |
233 | + | |
234 | + # ISearchProvider methods | |
235 | + def get_search_filters(self, req): | |
236 | + if self.env.config.get('searchhyperestraier', 'att_index_path','')!='': | |
237 | + yield ('attachmenthyperest', u'he:添付ファイル', 0) | |
238 | + | |
239 | + def get_search_results(self, req, terms, filters): | |
240 | + if not 'attachmenthyperest' in filters: | |
241 | + return | |
242 | + #estcmd.exeのパス | |
243 | + estcmd_path = self.env.config.get('searchhyperestraier', 'estcmd_path','estcmd') | |
244 | + #estcmd.exeの引数 | |
245 | + estcmd_arg = self.env.config.get('searchhyperestraier', 'estcmd_arg','search -vx -sf -ic Shift_JIS') | |
246 | + estcmd_encode = self.env.config.get('searchhyperestraier', 'estcmd_encode','mbcs') | |
247 | + | |
248 | + #インデックスのパス | |
249 | + att_index_path = self.env.config.get('searchhyperestraier', 'att_index_path','') | |
250 | + #コマンド実行時のエンコード(Pythonでの形式) | |
251 | + #estcmd_argと一致(?)させる必要有り。 | |
252 | + | |
253 | + #検索結果のパスの頭で削る文字列 | |
254 | + #self.log.debug('attpath:%s' % os.path.normpath(self.env.path)) | |
255 | + att_replace_left = os.path.join(os.path.normpath(self.env.path),'attachments') | |
256 | + #self.log.debug('attleft:%s' % att_replace_left) | |
257 | + | |
258 | + #cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,att_index_path,unicode(query,'utf-8').encode('CP932')) | |
259 | + qline = ' '.join(terms) | |
260 | + cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,att_index_path,qline) | |
261 | + self.log.debug('SearchHyperEstraier:%s' % cmdline) | |
262 | + cmdline = unicode(cmdline).encode(estcmd_encode) | |
263 | + np = NaivePopen(cmdline) | |
264 | + #self.log.debug('Result:%s' % unicode(np.out,'utf-8').encode('mbcs')) | |
265 | + #self.log.debug('Result:%s' % np.out) | |
266 | + if np.errorlevel or np.err: | |
267 | + err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, | |
268 | + np.err) | |
269 | + raise Exception, err | |
270 | + if np.out == '': #添付ファイルフォルダに何も入ってない | |
271 | + return | |
272 | + | |
273 | + dom = parseString(np.out) | |
274 | + root = dom.documentElement | |
275 | + #estresult_node = root.getElementsByTagName("document")[0] | |
276 | + element_array = root.getElementsByTagName("document") | |
277 | + for element in element_array: | |
278 | + #self.log.debug('Result:%s' % 'hoge') | |
279 | + url = "" | |
280 | + title = "" | |
281 | + date = 0 | |
282 | + detail = "" | |
283 | + author = "不明" | |
284 | + | |
285 | + #detailを生成 | |
286 | + elem_array = element.getElementsByTagName("snippet") | |
287 | + detail = self._get_innerText("",elem_array) | |
288 | + | |
289 | + #その他の属性を生成 | |
290 | + attrelem_array = element.getElementsByTagName("attribute") | |
291 | + for attrelem in attrelem_array: | |
292 | + attr_name = attrelem.getAttribute("name") | |
293 | + attr_value = unicode(attrelem.getAttribute("value")) #添付ファイルはパスがquoteされたものになっている | |
294 | + #URLとタイトルを生成 | |
295 | + if attr_name == "_lreal": | |
296 | + attr_value=attr_value[len(att_replace_left):].replace("\\","/") | |
297 | + url = self.env.href.attachment("") #attachmentまでのurl取得 | |
298 | + url = url +attr_value[1:] #[1:]は先頭の"/"を除くため | |
299 | + #そのままunquoteすると文字化けするから | |
300 | + title = urllib.unquote(attr_value).encode('raw_unicode_escape').decode('utf-8') | |
301 | + title = "attachment"+ title | |
302 | + title = title.replace("/",":") | |
303 | + #更新日時を生成 | |
304 | + elif attr_name =="@mdate": | |
305 | + date = time.strptime(attr_value,"%Y-%m-%dT%H:%M:%SZ") | |
306 | + self.log.debug('date:%s' % attr_value) | |
307 | + date = to_datetime(datetime.datetime(date[0],date[1],date[2],date[3],date[4],date[5],0,utc)) # for Trac0.11 | |
308 | + yield(url,title,date,to_unicode(author,'utf-8'),to_unicode(detail,'utf-8')) | |
309 | + return | |
310 | + | |
311 | + #XMLのElementを再帰的に探してテキストを生成 | |
312 | + def _get_innerText(self,text,node_array): | |
313 | + for node in node_array: | |
314 | + if node.nodeType == node.TEXT_NODE: | |
315 | + text = text + unicode(node.data).encode('utf-8') | |
316 | + else: | |
317 | + text = self._get_innerText(text,node.childNodes) | |
318 | + return text | |
319 | + | |
320 | +class SearchDocumentHyperEstraierModule(Component): | |
321 | + implements(ISearchSource) | |
322 | + | |
323 | + # ISearchProvider methods | |
324 | + def get_search_filters(self, req): | |
325 | + if self.env.config.get('searchhyperestraier', 'doc_index_path','')!='' \ | |
326 | + and self.env.config.get('searchhyperestraier', 'doc_replace_left','')!='' \ | |
327 | + and self.env.config.get('searchhyperestraier', 'doc_url_left','')!='': | |
328 | + yield ('documenthyperest', u'he:ドキュメント', 0) | |
329 | + | |
330 | + def get_search_results(self, req, terms, filters): | |
331 | + if not 'documenthyperest' in filters: | |
332 | + return | |
333 | + #estcmd.exeのパス | |
334 | + estcmd_path = self.env.config.get('searchhyperestraier', 'estcmd_path','estcmd') | |
335 | + #estcmd.exeの引数 | |
336 | + estcmd_arg = self.env.config.get('searchhyperestraier', 'estcmd_arg','search -vx -sf -ic Shift_JIS') | |
337 | + estcmd_encode = self.env.config.get('searchhyperestraier', 'estcmd_encode','mbcs') | |
338 | + | |
339 | + #インデックスのパス | |
340 | + doc_index_path = self.env.config.get('searchhyperestraier', 'doc_index_path','') | |
341 | + #コマンド実行時のエンコード(Pythonでの形式) | |
342 | + #estcmd_argと一致(?)させる必要有り。 | |
343 | + | |
344 | + #検索結果のパスの頭で削る文字列 | |
345 | + doc_replace_left = self.env.config.get('searchhyperestraier', 'doc_replace_left','') | |
346 | + | |
347 | + #tracやsvnと同じならびにくるドキュメントのフォルダ名 | |
348 | + doc_url_left = self.env.config.get('searchhyperestraier', 'doc_url_left','doc') | |
349 | + | |
350 | + #cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,doc_index_path,unicode(query,'utf-8').encode('CP932')) | |
351 | + qline = ' '.join(terms) | |
352 | + cmdline = "%s %s %s %s" % (estcmd_path,estcmd_arg,doc_index_path,qline) | |
353 | + self.log.debug('SearchHyperEstraier:%s' % cmdline) | |
354 | + cmdline = unicode(cmdline).encode(estcmd_encode) | |
355 | + np = NaivePopen(cmdline) | |
356 | + #self.log.debug('Result:%s' % unicode(np.out,'utf-8').encode('mbcs')) | |
357 | + #self.log.debug('Result:%s' % np.out) | |
358 | + if np.errorlevel or np.err: | |
359 | + err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, | |
360 | + np.err) | |
361 | + raise Exception, err | |
362 | + if np.out=='': #ドキュメントフォルダに何も入ってない | |
363 | + return | |
364 | + dom = parseString(np.out) | |
365 | + root = dom.documentElement | |
366 | + #estresult_node = root.getElementsByTagName("document")[0] | |
367 | + element_array = root.getElementsByTagName("document") | |
368 | + for element in element_array: | |
369 | + #self.log.debug('Result:%s' % 'hoge') | |
370 | + url = "" | |
371 | + title = "" | |
372 | + date = 0 | |
373 | + detail = "" | |
374 | + author = "不明" | |
375 | + | |
376 | + #detailを生成 | |
377 | + elem_array = element.getElementsByTagName("snippet") | |
378 | + detail = self._get_innerText("",elem_array) | |
379 | + | |
380 | + #その他の属性を生成 | |
381 | + attrelem_array = element.getElementsByTagName("attribute") | |
382 | + for attrelem in attrelem_array: | |
383 | + attr_name = attrelem.getAttribute("name") | |
384 | + attr_value = unicode(attrelem.getAttribute("value")) | |
385 | + #URLとタイトルを生成 | |
386 | + #if attr_name == "_lreal": #"_lreal"ではファイル名に' 'などが入っている場合対応できない | |
387 | + # attr_value=attr_value[len(doc_replace_left):].replace("\\","/") | |
388 | + # title = doc_url_left + attr_value | |
389 | + # url = urllib.quote(title.encode('utf-8')) | |
390 | + # title = '/' + title | |
391 | + if attr_name == "_lpath": #s-jisをquoteしたもの("file:///C|/TracLight/…"の形式) | |
392 | + attr_value = urllib.unquote(attr_value).encode('raw_unicode_escape').decode('CP932') | |
393 | + attr_value = attr_value[(len('file:///')+len(doc_replace_left)):] | |
394 | + #url = doc_url_left + attr_value | |
395 | + #title = '/' + urllib.unquote(url) | |
396 | + title = '/' + doc_url_left + attr_value | |
397 | + url = urllib.quote((doc_url_left + attr_value).encode('utf-8')) | |
398 | + #更新日時を生成 | |
399 | + elif attr_name =="@mdate": | |
400 | + date = time.strptime(attr_value,"%Y-%m-%dT%H:%M:%SZ") | |
401 | + self.log.debug('date:%s' % attr_value) | |
402 | + date = to_datetime(datetime.datetime(date[0],date[1],date[2],date[3],date[4],date[5],0,utc)) # for Trac0.11 | |
403 | + yield(url,title,date,to_unicode(author,'utf-8'),to_unicode(detail,'utf-8')) | |
404 | + return | |
405 | + | |
406 | + #XMLのElementを再帰的に探してテキストを生成 | |
407 | + def _get_innerText(self,text,node_array): | |
408 | + for node in node_array: | |
409 | + if node.nodeType == node.TEXT_NODE: | |
410 | + text = text + unicode(node.data).encode('utf-8') | |
411 | + else: | |
412 | + text = self._get_innerText(text,node.childNodes) | |
413 | + return text |
@@ -0,0 +1,2 @@ | ||
1 | +# SearchRepositoryWithHyperEstraier module | |
2 | +from searchhyperestraier import * |