milkode 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +17 -4
- data/HISTORY.ja.rdoc +27 -0
- data/HISTORY.rdoc +27 -0
- data/LICENSE.txt +23 -1
- data/Rakefile +1 -16
- data/VERSION +1 -1
- data/bin/gmilk +1 -1
- data/bin/milk +1 -1
- data/lib/milkode/cdstk/cdstk.rb +171 -168
- data/lib/milkode/cdstk/milkode_yaml.rb +1 -1
- data/lib/milkode/cdweb/app.rb +11 -3
- data/lib/milkode/cdweb/lib/command.rb +43 -0
- data/lib/milkode/cdweb/lib/database.rb +58 -210
- data/lib/milkode/cdweb/lib/mkurl.rb +10 -1
- data/lib/milkode/cdweb/lib/package_list.rb +61 -0
- data/lib/milkode/cdweb/lib/search_files.rb +2 -1
- data/lib/milkode/cdweb/public/css/bootstrap-responsive.min.css +9 -0
- data/lib/milkode/cdweb/public/css/bootstrap.min.css +9 -0
- data/lib/milkode/cdweb/public/css/milkode.css +44 -9
- data/lib/milkode/cdweb/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/milkode/cdweb/public/img/glyphicons-halflings.png +0 -0
- data/lib/milkode/cdweb/public/js/bootstrap.min.js +6 -0
- data/lib/milkode/cdweb/views/index.haml +52 -16
- data/lib/milkode/cdweb/views/packages.haml +11 -0
- data/lib/milkode/cli.rb +8 -0
- data/lib/milkode/common/array_diff.rb +18 -0
- data/lib/milkode/common/util.rb +16 -0
- data/lib/milkode/database/document_record.rb +64 -0
- data/lib/milkode/database/document_table.rb +341 -0
- data/lib/milkode/database/groonga_database.rb +105 -0
- data/lib/milkode/database/package_table.rb +98 -0
- data/lib/milkode/findgrep/findgrep.rb +20 -124
- data/lib/milkode/grep/cli_grep.rb +3 -1
- data/milkode.gemspec +32 -2
- data/test/data/.gitignore +4 -0
- data/test/data/c_project/a.txt +1 -0
- data/test/data/c_project/abc.c +2 -0
- data/test/data/c_project/abc.h +3 -0
- data/test/data/c_project/b.txt +1 -0
- data/test/data/c_project/c.txt +1 -0
- data/test/data/c_project/cc.txt +1 -0
- data/test/data/c_project/to/file.rb +1 -0
- data/test/test_cdstk.rb +4 -4
- data/test/test_cli.rb +9 -2
- data/test/test_database.rb +5 -14
- data/test/test_document_record.rb +77 -0
- data/test/test_document_table.rb +317 -0
- data/test/test_groonga_database.rb +58 -0
- data/test/test_mkurl.rb +2 -0
- data/test/test_package_list.rb +21 -0
- data/test/test_package_table.rb +215 -0
- data/test/test_util.rb +8 -0
- metadata +57 -5
data/lib/milkode/cdweb/app.rb
CHANGED
@@ -15,15 +15,17 @@ require 'milkode/cdweb/lib/database'
|
|
15
15
|
require 'milkode/cdweb/lib/command'
|
16
16
|
require 'milkode/cdweb/lib/mkurl'
|
17
17
|
require 'milkode/cdweb/lib/web_setting'
|
18
|
+
require 'milkode/cdweb/lib/package_list'
|
18
19
|
|
19
20
|
set :haml, :format => :html5
|
20
21
|
|
21
22
|
get '/' do
|
22
23
|
@setting = WebSetting.new
|
23
|
-
@version = "0.
|
24
|
+
@version = "0.8.0"
|
24
25
|
@package_num = Database.instance.yaml_package_num
|
25
26
|
@file_num = Database.instance.totalRecords
|
26
|
-
|
27
|
+
@package_list = PackageList.new(Database.instance.grndb)
|
28
|
+
haml :index, :layout => false
|
27
29
|
end
|
28
30
|
|
29
31
|
def package_path(path)
|
@@ -56,7 +58,13 @@ get '/home*' do |path|
|
|
56
58
|
path = path.sub(/^\//, "")
|
57
59
|
record = Database.instance.record(path)
|
58
60
|
|
59
|
-
if
|
61
|
+
if path.empty?
|
62
|
+
if (params[:query] and !params[:query].empty?)
|
63
|
+
search(path, params, before)
|
64
|
+
else
|
65
|
+
packages(params, before)
|
66
|
+
end
|
67
|
+
elsif (record)
|
60
68
|
view(record, params, before)
|
61
69
|
else
|
62
70
|
if (params[:query] and !params[:query].empty?)
|
@@ -28,6 +28,7 @@ module Milkode
|
|
28
28
|
@record_content = CodeRayWrapper.new(record.content, record.shortpath).to_html
|
29
29
|
end
|
30
30
|
|
31
|
+
Database.instance.touch_viewtime(@path)
|
31
32
|
@elapsed = Time.now - before
|
32
33
|
haml :view
|
33
34
|
end
|
@@ -61,12 +62,54 @@ module Milkode
|
|
61
62
|
@record_content = fileList.map do |v|
|
62
63
|
"<dt class='result-file'>#{file_or_dirimg(v[1])}<a href='#{Mkurl.new('/home/' + v[0], params).inherit_query_shead}'>#{File.basename v[0]}</a></dt>"
|
63
64
|
end.join
|
65
|
+
Database.instance.touch_viewtime(path)
|
64
66
|
@elapsed = Time.now - before
|
65
67
|
haml :filelist
|
66
68
|
end
|
67
69
|
|
70
|
+
def packages(params, before)
|
71
|
+
@setting = WebSetting.new
|
72
|
+
@title = "Package List"
|
73
|
+
@path = ""
|
74
|
+
packages = Database.instance.packages(params["sort"])
|
75
|
+
@total_records = packages.size
|
76
|
+
|
77
|
+
@sort_change_content =
|
78
|
+
[
|
79
|
+
sort_change_content(params["sort"], '名前'),
|
80
|
+
'|',
|
81
|
+
sort_change_content(params["sort"], '最近使った', 'viewtime'),
|
82
|
+
'|',
|
83
|
+
sort_change_content(params["sort"], '追加順' , 'addtime'),
|
84
|
+
'|',
|
85
|
+
sort_change_content(params["sort"], '更新順' , 'updatetime'),
|
86
|
+
'|',
|
87
|
+
sort_change_content(params["sort"], 'お気に入り', 'favtime'),
|
88
|
+
].join("\n")
|
89
|
+
|
90
|
+
@record_content = packages.map do |v|
|
91
|
+
"<dt class='result-file'>#{file_or_dirimg(false)}<a href='#{Mkurl.new('/home/' + v, params).inherit_query_shead}'>#{File.basename v}</a></dt>"
|
92
|
+
end.join
|
93
|
+
@elapsed = Time.now - before
|
94
|
+
haml :packages
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
68
99
|
def file_or_dirimg(is_file)
|
69
100
|
src = (is_file) ? '/images/file.png' : '/images/directory.png'
|
70
101
|
"<img alt='' style='vertical-align:bottom; border: 0; margin: 1px;' src='#{src}'>"
|
71
102
|
end
|
103
|
+
|
104
|
+
def sort_change_content(current_value, text, sort_kind = nil)
|
105
|
+
if (current_value != sort_kind)
|
106
|
+
if (sort_kind)
|
107
|
+
"<a href='#{Mkurl.new('/home', params).inherit_query_shead_set_sort(sort_kind)}'>#{text}</a>"
|
108
|
+
else
|
109
|
+
"<a href='#{Mkurl.new('/home', params).inherit_query_shead}'>#{text}</a>"
|
110
|
+
end
|
111
|
+
else
|
112
|
+
text
|
113
|
+
end
|
114
|
+
end
|
72
115
|
end
|
@@ -11,9 +11,11 @@ require 'singleton'
|
|
11
11
|
require 'groonga'
|
12
12
|
require 'milkode/common/dbdir'
|
13
13
|
require 'milkode/cdstk/yaml_file_wrapper'
|
14
|
+
require 'milkode/database/groonga_database'
|
14
15
|
include Milkode
|
15
16
|
|
16
17
|
module Milkode
|
18
|
+
# @todo データベースアクセスは将来的にはGroongaDatabaseに収束させる
|
17
19
|
class Database
|
18
20
|
include Singleton
|
19
21
|
|
@@ -28,93 +30,73 @@ module Milkode
|
|
28
30
|
end
|
29
31
|
|
30
32
|
attr_reader :yaml
|
33
|
+
attr_reader :grndb
|
31
34
|
|
32
35
|
def initialize
|
33
|
-
open
|
36
|
+
open
|
34
37
|
end
|
35
38
|
|
36
39
|
def yaml_reload
|
37
40
|
# @yaml = YamlFileWrapper.load_if(@@db_dir || Dbdir.default_dir)
|
38
41
|
end
|
39
42
|
|
40
|
-
def open
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
raise "error : #{dbfile} not found!!"
|
43
|
+
def open
|
44
|
+
if !@grndb || @grndb.closed?
|
45
|
+
@grndb = GroongaDatabase.new
|
46
|
+
@grndb.open(Database.dbdir)
|
47
|
+
@grndb.yaml_sync(yaml_load.contents)
|
48
|
+
@documents = @grndb.documents
|
47
49
|
end
|
48
|
-
|
49
|
-
@documents = Groonga::Context.default["documents"]
|
50
50
|
end
|
51
51
|
|
52
52
|
def record(shortpath)
|
53
|
-
|
54
|
-
table = @documents.select { |record| record.shortpath == shortpath }
|
55
|
-
return table.records[0]
|
53
|
+
DocumentRecord.create @documents.find_shortpath(shortpath)
|
56
54
|
end
|
57
55
|
|
58
56
|
def search(patterns, packages, current_path, fpaths, suffixs, offset = 0, limit = -1)
|
59
|
-
|
60
|
-
unless packages.empty?
|
61
|
-
packages = convert_packages(packages)
|
62
|
-
|
63
|
-
# キーワードがパッケージ名にマッチしなければ検索しない
|
64
|
-
return [], 0 if packages.empty?
|
65
|
-
else
|
66
|
-
# パッケージ名未指定の時は現在位置もfpathsに含める
|
67
|
-
if current_path != ""
|
68
|
-
fpaths << path2fpath(current_path)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# @todo fpathを厳密に検索するには、検索結果からさらに先頭からのパスではないものを除外する
|
73
|
-
records, total_records = searchMain(patterns, packages, fpaths, suffixs, offset, limit)
|
74
|
-
end
|
75
|
-
|
76
|
-
def path2fpath(path)
|
77
|
-
pa = path.split("/")
|
78
|
-
File.join(convert_packages([pa[0]])[0], pa[1..-1].join('/'))
|
79
|
-
end
|
80
|
-
|
81
|
-
def selectAll(offset = 0, limit = -1)
|
82
|
-
table = @documents.select
|
57
|
+
paths = []
|
83
58
|
|
84
|
-
#
|
85
|
-
|
86
|
-
|
87
|
-
# @todo ここが速度低下の原因?と思ったけど、ここは全て選択の部分だけか・・・
|
59
|
+
# パッケージ名未指定の時は現在位置を検索条件に追加
|
60
|
+
if packages.empty? && current_path != ''
|
61
|
+
package, restpath = Util::divide_shortpath(current_path)
|
88
62
|
|
89
|
-
|
90
|
-
|
91
|
-
# # ファイル名順にソート
|
92
|
-
# records = table.sort([{:key => "shortpath", :order => "descending"}],
|
93
|
-
# :offset => offset,
|
94
|
-
# :limit => limit)
|
63
|
+
# PackageRecord#directory をキーに検索する
|
64
|
+
directory = @grndb.packages[package].directory
|
95
65
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
66
|
+
if restpath
|
67
|
+
paths << File.join(directory, restpath)
|
68
|
+
else
|
69
|
+
paths << directory
|
70
|
+
end
|
101
71
|
end
|
102
72
|
|
103
|
-
|
73
|
+
# 検索
|
74
|
+
result = @documents.search(
|
75
|
+
:patterns => patterns,
|
76
|
+
# :keywords => ,
|
77
|
+
:paths => paths,
|
78
|
+
:packages => packages,
|
79
|
+
:restpaths => fpaths,
|
80
|
+
:suffixs => suffixs,
|
81
|
+
:offset => offset,
|
82
|
+
:limit => limit
|
83
|
+
)
|
84
|
+
|
85
|
+
# 結果
|
86
|
+
return result.map{|r| DocumentRecord.new(r)}, result.size
|
104
87
|
end
|
105
88
|
|
106
|
-
def
|
107
|
-
|
108
|
-
records
|
89
|
+
def selectAll(offset, limit)
|
90
|
+
@documents.select_all_sort_by_shortpath(offset, limit)
|
109
91
|
end
|
110
|
-
|
92
|
+
|
111
93
|
# レコード数を得る
|
112
94
|
def totalRecords
|
113
|
-
|
114
|
-
@documents.select.size
|
95
|
+
@documents.size
|
115
96
|
end
|
116
97
|
|
117
98
|
# yamlからパッケージの総数を得る
|
99
|
+
# @todo PackageTableから取得するように変更する
|
118
100
|
def yaml_package_num
|
119
101
|
yaml_load.contents.size
|
120
102
|
end
|
@@ -128,17 +110,13 @@ module Milkode
|
|
128
110
|
if (base_depth == 0)
|
129
111
|
return yaml_load.contents.sort_by{|v| v.name}.map{|v| [v.name, false] }
|
130
112
|
end
|
131
|
-
|
132
|
-
#
|
133
|
-
|
134
|
-
records = @documents.select.records
|
135
|
-
else
|
136
|
-
records = @documents.select {|record| record.shortpath =~ base }.to_a
|
137
|
-
end
|
113
|
+
|
114
|
+
# base/以下のファイルを全て取得
|
115
|
+
records = @documents.find_shortpath_below(base)
|
138
116
|
|
139
117
|
# ファイルリストの生成
|
140
118
|
paths = records.map {|record|
|
141
|
-
record.shortpath.split("/")
|
119
|
+
DocumentRecord.new(record).shortpath.split("/")
|
142
120
|
}.find_all {|parts|
|
143
121
|
parts.length > base_depth and parts[0, base_depth] == base_parts
|
144
122
|
}.map {|parts|
|
@@ -151,161 +129,31 @@ module Milkode
|
|
151
129
|
|
152
130
|
paths
|
153
131
|
end
|
154
|
-
|
155
|
-
# 指定したfpathにマッチするレコードを削除する
|
156
|
-
def remove_fpath(fpath)
|
157
|
-
# データベースを開き直す
|
158
|
-
reopen_patch
|
159
|
-
|
160
|
-
# 削除したいコンテンツを検索
|
161
|
-
records, total_records = searchMain([], [], [fpath], [], 0, -1)
|
162
|
-
|
163
|
-
# 検索結果はHashのレコードなので、これを直接deleteしても駄目
|
164
|
-
# 1. Record#record_idを使って主キー(Groonga#Arrayのレコード)を取り出し
|
165
|
-
# 2. Record#delete で削除
|
166
|
-
records.each do |r|
|
167
|
-
yield r if block_given?
|
168
|
-
r.record_id.delete
|
169
|
-
end
|
170
|
-
end
|
171
132
|
|
172
|
-
|
173
|
-
|
174
|
-
# データベースを開き直す
|
175
|
-
reopen_patch
|
133
|
+
def packages(sort_kind)
|
134
|
+
sorted = nil
|
176
135
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
r.record_id.delete
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
private
|
189
|
-
|
190
|
-
def reopen_patch
|
191
|
-
# 削除系のコマンドが上手く動作しないためのパッチ
|
192
|
-
# 本質的な解決にはなっていないと思う
|
193
|
-
open(Database.dbdir)
|
194
|
-
end
|
195
|
-
|
196
|
-
def searchMain(patterns, packages, fpaths, suffixs, offset, limit)
|
197
|
-
table = @documents.select do |record|
|
198
|
-
expression = nil
|
199
|
-
|
200
|
-
# キーワード
|
201
|
-
patterns.each do |word|
|
202
|
-
sub_expression = record.content =~ word
|
203
|
-
if expression.nil?
|
204
|
-
expression = sub_expression
|
205
|
-
else
|
206
|
-
expression &= sub_expression
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
# パッケージ(OR)
|
211
|
-
pe = package_expression(record, packages)
|
212
|
-
if (pe)
|
213
|
-
if expression.nil?
|
214
|
-
expression = pe
|
215
|
-
else
|
216
|
-
expression &= pe
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
# ファイルパス
|
221
|
-
fpaths.each do |word|
|
222
|
-
sub_expression = record.path =~ word
|
223
|
-
if expression.nil?
|
224
|
-
expression = sub_expression
|
225
|
-
else
|
226
|
-
expression &= sub_expression
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
# 拡張子(OR)
|
231
|
-
se = suffix_expression(record, suffixs)
|
232
|
-
if (se)
|
233
|
-
if expression.nil?
|
234
|
-
expression = se
|
235
|
-
else
|
236
|
-
expression &= se
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
# 検索式
|
241
|
-
expression
|
242
|
-
end
|
243
|
-
|
244
|
-
# スコアとタイムスタンプでソート
|
245
|
-
# records = table.sort([{:key => "_score", :order => "descending"},
|
246
|
-
# {:key => "timestamp", :order => "descending"}],
|
247
|
-
# :offset => offset,
|
248
|
-
# :limit => limit)
|
249
|
-
|
250
|
-
# ファイル名でソート
|
251
|
-
records = table.sort([{:key => "shortpath", :order => "ascending"}],
|
252
|
-
:offset => offset,
|
253
|
-
:limit => limit)
|
254
|
-
|
255
|
-
# マッチ数
|
256
|
-
total_records = table.size
|
257
|
-
|
258
|
-
return records, total_records
|
259
|
-
end
|
260
|
-
private :searchMain
|
261
|
-
|
262
|
-
def package_expression(record, packages)
|
263
|
-
sub = nil
|
264
|
-
|
265
|
-
# @todo 専用カラム package が欲しいところ
|
266
|
-
# でも今でもpackageはORとして機能してるからいいっちゃいい
|
267
|
-
packages.each do |word|
|
268
|
-
e = record.path =~ word
|
269
|
-
if sub.nil?
|
270
|
-
sub = e
|
271
|
-
else
|
272
|
-
sub |= e
|
273
|
-
end
|
136
|
+
if sort_kind == "favtime"
|
137
|
+
sorted = @grndb.packages.favs
|
138
|
+
elsif (sort_kind)
|
139
|
+
sorted = @grndb.packages.sort(sort_kind)
|
140
|
+
else
|
141
|
+
sorted = @grndb.packages.sort("name", "ascending")
|
274
142
|
end
|
275
143
|
|
276
|
-
|
144
|
+
sorted.map {|r| r.name}
|
277
145
|
end
|
278
|
-
private :package_expression
|
279
146
|
|
280
|
-
def
|
281
|
-
|
282
|
-
|
283
|
-
suffixs.each do |word|
|
284
|
-
e = record.suffix =~ word
|
285
|
-
if sub.nil?
|
286
|
-
sub = e
|
287
|
-
else
|
288
|
-
sub |= e
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
sub
|
147
|
+
def touch_viewtime(path)
|
148
|
+
package, restpath = Util::divide_shortpath(path)
|
149
|
+
@grndb.packages.touch(package, :viewtime) if package
|
293
150
|
end
|
294
|
-
private :suffix_expression
|
295
151
|
|
296
|
-
|
297
|
-
packages.inject([]) {|r, p| r += expand_packages(p)}
|
298
|
-
end
|
299
|
-
|
300
|
-
def expand_packages(keyword)
|
301
|
-
yaml_load.match_all(keyword).map{|p| p.directory}
|
302
|
-
end
|
152
|
+
private
|
303
153
|
|
304
154
|
def yaml_load
|
305
155
|
YamlFileWrapper.load_if(Database.dbdir)
|
306
156
|
end
|
307
157
|
|
308
|
-
# --- error ---
|
309
|
-
class NotFoundPackage < RuntimeError ; end
|
310
158
|
end
|
311
159
|
end
|
@@ -24,6 +24,14 @@ module Milkode
|
|
24
24
|
create_url(query_param(true, true, false))
|
25
25
|
end
|
26
26
|
|
27
|
+
def inherit_query_shead_set_sort(sort_kind)
|
28
|
+
create_url(query_param(true, true, false, sort_kind))
|
29
|
+
end
|
30
|
+
|
31
|
+
def inherit_query_shead
|
32
|
+
create_url(query_param(true, true, false))
|
33
|
+
end
|
34
|
+
|
27
35
|
def inherit_shead
|
28
36
|
create_url(query_param(false, true, false))
|
29
37
|
end
|
@@ -42,13 +50,14 @@ module Milkode
|
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
45
|
-
def query_param(query_inherit, shead_inherit, offset_inherit)
|
53
|
+
def query_param(query_inherit, shead_inherit, offset_inherit, sort_kind = nil)
|
46
54
|
qparam = []
|
47
55
|
qparam << "query=#{escape(@params[:query])}" if (query_inherit and @params[:query])
|
48
56
|
qparam << "shead=#{escape(@params[:shead])}" if (shead_inherit and @params[:shead])
|
49
57
|
qparam << "onematch=#{escape(@params[:onematch])}" if (shead_inherit and @params[:onematch])
|
50
58
|
qparam << "offset=#{escape(@params[:offset])}" if (offset_inherit and @params[:offset])
|
51
59
|
qparam << "line=#{escape(@params[:line])}" if (offset_inherit and @params[:line])
|
60
|
+
qparam << "sort=#{sort_kind}" if sort_kind
|
52
61
|
qparam.join('&')
|
53
62
|
end
|
54
63
|
end
|