milkode 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|