milkode 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.document +5 -0
  2. data/Gemfile +12 -0
  3. data/Gemfile.lock +18 -0
  4. data/HISTORY.rdoc +5 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +78 -0
  8. data/VERSION +1 -0
  9. data/bin/cdv +6 -0
  10. data/bin/cdview +10 -0
  11. data/bin/milk +10 -0
  12. data/lib/milkode/cdstk/cdstk.rb +508 -0
  13. data/lib/milkode/cdstk/cdstk_yaml.rb +106 -0
  14. data/lib/milkode/cdstk/cli_cdstk.rb +103 -0
  15. data/lib/milkode/cdstk/cli_cdstksub.rb +102 -0
  16. data/lib/milkode/cdview/cli_cdview.rb +43 -0
  17. data/lib/milkode/cdweb/app.rb +136 -0
  18. data/lib/milkode/cdweb/cli_cdweb.rb +111 -0
  19. data/lib/milkode/cdweb/config.ru +3 -0
  20. data/lib/milkode/cdweb/lib/coderay_wrapper.rb +94 -0
  21. data/lib/milkode/cdweb/lib/command.rb +67 -0
  22. data/lib/milkode/cdweb/lib/database.rb +260 -0
  23. data/lib/milkode/cdweb/lib/grep.rb +68 -0
  24. data/lib/milkode/cdweb/lib/mkurl.rb +56 -0
  25. data/lib/milkode/cdweb/lib/query.rb +81 -0
  26. data/lib/milkode/cdweb/lib/search_contents.rb +117 -0
  27. data/lib/milkode/cdweb/lib/search_files.rb +88 -0
  28. data/lib/milkode/cdweb/public/css/coderay.css +131 -0
  29. data/lib/milkode/cdweb/public/css/gren.css +75 -0
  30. data/lib/milkode/cdweb/public/images/directory.png +0 -0
  31. data/lib/milkode/cdweb/public/images/file.png +0 -0
  32. data/lib/milkode/cdweb/public/images/gren-icon-mini.png +0 -0
  33. data/lib/milkode/cdweb/public/images/gren-icon.png +0 -0
  34. data/lib/milkode/cdweb/views/filelist.haml +14 -0
  35. data/lib/milkode/cdweb/views/help.haml +16 -0
  36. data/lib/milkode/cdweb/views/index.haml +17 -0
  37. data/lib/milkode/cdweb/views/layout.haml +33 -0
  38. data/lib/milkode/cdweb/views/search.haml +12 -0
  39. data/lib/milkode/cdweb/views/view.haml +16 -0
  40. data/lib/milkode/common/dbdir.rb +39 -0
  41. data/lib/milkode/common/display_util.rb +62 -0
  42. data/lib/milkode/common/grenfiletest.rb +19 -0
  43. data/lib/milkode/common/grensnip.rb +37 -0
  44. data/lib/milkode/common/platform.rb +17 -0
  45. data/lib/milkode/common/string_snip.rb +61 -0
  46. data/lib/milkode/common/util.rb +144 -0
  47. data/lib/milkode/findgrep/findgrep.rb +408 -0
  48. data/lib/milkode/findgrep/result.rb +43 -0
  49. data/milkode.gemspec +159 -0
  50. data/test/data/abc.zip +0 -0
  51. data/test/data/nodir_abc.zip +0 -0
  52. data/test/data/nodir_abc_xpi.xpi +0 -0
  53. data/test/file_assert.rb +41 -0
  54. data/test/file_test_utils.rb +59 -0
  55. data/test/rake_test_loader.rb +7 -0
  56. data/test/runner.rb +11 -0
  57. data/test/test_bin_exec.rb +30 -0
  58. data/test/test_cdstk.rb +90 -0
  59. data/test/test_cdstk_yaml.rb +157 -0
  60. data/test/test_coderay_wrapper.rb +22 -0
  61. data/test/test_coderay_wrapper_data.rb +91 -0
  62. data/test/test_database.rb +78 -0
  63. data/test/test_dbdir.rb +60 -0
  64. data/test/test_gren_util.rb +34 -0
  65. data/test/test_helper.rb +2 -0
  66. data/test/test_mkurl.rb +30 -0
  67. data/test/test_query.rb +54 -0
  68. data/test/test_string_snip.rb +31 -0
  69. data/test/test_util.rb +40 -0
  70. metadata +300 -0
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'rack'
4
+ require 'launchy'
5
+ require 'optparse'
6
+ require 'milkode/cdweb/lib/database'
7
+
8
+ module Rack
9
+ class Server
10
+ def start
11
+ if options[:warn]
12
+ $-w = true
13
+ end
14
+
15
+ if includes = options[:include]
16
+ $LOAD_PATH.unshift(*includes)
17
+ end
18
+
19
+ if library = options[:require]
20
+ require library
21
+ end
22
+
23
+ if options[:debug]
24
+ $DEBUG = true
25
+ require 'pp'
26
+ p options[:server]
27
+ pp wrapped_app
28
+ pp app
29
+ end
30
+
31
+ # Touch the wrapped app, so that the config.ru is loaded before
32
+ # daemonization (i.e. before chdir, etc).
33
+ wrapped_app
34
+
35
+ daemonize_app if options[:daemonize]
36
+ write_pid if options[:pid]
37
+
38
+ trap(:INT) do
39
+ if server.respond_to?(:shutdown)
40
+ server.shutdown
41
+ else
42
+ exit
43
+ end
44
+ end
45
+
46
+ server.run wrapped_app, options do
47
+ if (options[:LaunchBrowser])
48
+ host = options[:Host] || options[:BindAddress] # options[:BindAddress] for WEBrick
49
+ Launchy.open("http://#{host}:#{options[:Port]}")
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ module Milkode
57
+ class CLI_Cdweb
58
+ def self.execute(stdout, argv)
59
+ options = {
60
+ :environment => ENV['RACK_ENV'] || "development",
61
+ :pid => nil,
62
+ :Port => 9292,
63
+ :Host => "0.0.0.0",
64
+ :AccessLog => [],
65
+ :config => "config.ru",
66
+ # ----------------------------
67
+ :server => "thin",
68
+ :LaunchBrowser => true,
69
+ :DbDir => select_dbdir,
70
+ }
71
+
72
+ opts = OptionParser.new("#{File.basename($0)}")
73
+ opts.on('--db DB_DIR', 'Database dir (default : current_dir)') {|v| options[:DbDir] = v }
74
+ opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") {|host| options[:Host] = host }
75
+ opts.on('-p', '--port PORT', 'use PORT (default: 9292)') {|v| options[:Port] = v }
76
+ opts.on("-s", "--server SERVER", "serve using SERVER (default : thin)") {|s| options[:server] = s }
77
+ opts.on('-n', '--no-browser', 'No launch browser.') {|v| options[:LaunchBrowser] = false }
78
+
79
+ # --hostが'-h'を上書きするので、'-h'を再定義してあげる
80
+ opts.on_tail("-h", "-?", "--help", "Show this message") do
81
+ puts opts
82
+ exit
83
+ end
84
+
85
+ opts.parse!(argv)
86
+
87
+ # 実行!!
88
+ execute_with_options(options)
89
+ end
90
+
91
+ def self.execute_with_options(stdout, options)
92
+ # 使用するデータベースの位置設定
93
+ Database.setup(File.expand_path(options[:DbDir]))
94
+
95
+ # サーバースクリプトのある場所へ移動
96
+ FileUtils.cd(File.dirname(__FILE__))
97
+
98
+ # Rackサーバー起動
99
+ Rack::Server.start(options)
100
+ end
101
+
102
+
103
+ def self.select_dbdir
104
+ if (Dbdir.dbdir?('.') || !Dbdir.dbdir?(Dbdir.default_dir))
105
+ '.'
106
+ else
107
+ Dbdir.default_dir
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ require './app'
2
+ run Sinatra::Application
3
+
@@ -0,0 +1,94 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/03
7
+
8
+ require 'rubygems'
9
+ require 'coderay'
10
+ require 'coderay/helpers/file_type'
11
+
12
+ module Milkode
13
+ class CodeRayWrapper
14
+ attr_reader :line_number_start
15
+
16
+ def initialize(content, filename, match_lines = [])
17
+ @content = content
18
+ @filename = filename
19
+ @match_lines = match_lines
20
+ @highlight_lines = match_lines.map{|v|v.index+1}
21
+ @line_number_start = 1
22
+ end
23
+
24
+ def set_range(range)
25
+ content_a = @content.to_a
26
+ range = limit_range(range, content_a)
27
+ @content = content_a[range]
28
+ @line_number_start = range.first + 1
29
+ end
30
+
31
+ def limit_range(range, array)
32
+ Range.new(range.first < 0 ? 0 : range.first,
33
+ range.last >= array.size ? array.size - 1 : range.last)
34
+ end
35
+
36
+ def to_html
37
+ html = CodeRay.scan(@content, file_type).
38
+ html(
39
+ :wrap => nil,
40
+ :line_numbers => :table,
41
+ :css => :class,
42
+ :highlight_lines => @highlight_lines,
43
+ :line_number_start => @line_number_start
44
+ )
45
+
46
+ milkode_ornament(html)
47
+ end
48
+
49
+ def milkode_ornament(html)
50
+ a = html.split("\n")
51
+
52
+ line_number = @line_number_start
53
+ is_code_content = false
54
+
55
+ a.each_with_index do |l, index|
56
+ if (l =~ / <td class="code"><pre (.*?)>(.*)<tt>/)
57
+ a[index] = " <td class=\"code\"><pre #{$1}><span #{line_attr(line_number)}>#{$2}</span><tt>"
58
+ is_code_content = true
59
+ line_number += 1
60
+ next
61
+ elsif (l =~ %r|</tt></pre></td>|)
62
+ is_code_content = false
63
+ end
64
+
65
+ if (is_code_content)
66
+ if (l =~ %r|</tt>(.*)<tt>|)
67
+ a[index] = "</tt><span #{line_attr(line_number)}>#{$1}</span><tt>"
68
+ line_number += 1
69
+ end
70
+ end
71
+ end
72
+
73
+ a.join("\n") + "\n"
74
+ end
75
+
76
+ def file_type
77
+ case File.extname(@filename)
78
+ when ".el"
79
+ :scheme
80
+ else
81
+ CodeRay::FileType.fetch @filename, :plaintext
82
+ end
83
+ end
84
+
85
+ def line_attr(no)
86
+ r = []
87
+ r << "id=\"#{no}\""
88
+ r << "class=\"highlight-line\"" if @highlight_lines.include?(no)
89
+ r.join(" ")
90
+ end
91
+ end
92
+ end
93
+
94
+
@@ -0,0 +1,67 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/11
7
+
8
+ require 'milkode/cdweb/lib/database'
9
+ require 'milkode/cdweb/lib/coderay_wrapper'
10
+ require 'milkode/cdweb/lib/search_contents'
11
+ require 'milkode/cdweb/lib/search_files'
12
+ require 'milkode/cdweb/lib/mkurl'
13
+
14
+ module Milkode
15
+ def view(record, params, before)
16
+ @title = record.shortpath
17
+ @path = record.shortpath
18
+
19
+ q = params[:query] && Query.new(params[:query])
20
+
21
+ if (q and !q.keywords.empty?)
22
+ grep = Grep.new(record.content)
23
+ match_lines = grep.match_lines_and(q.keywords)
24
+ @record_content = CodeRayWrapper.new(record.content, record.shortpath, match_lines).to_html
25
+ else
26
+ @record_content = CodeRayWrapper.new(record.content, record.shortpath).to_html
27
+ end
28
+
29
+ @elapsed = Time.now - before
30
+ haml :view
31
+ end
32
+
33
+ def search(path, params, before)
34
+ @path = path
35
+ query = Query.new(params[:query])
36
+ @title = "'#{query.query_string}' in #{path_title(path)}"
37
+
38
+ if (query.keywords.size > 0)
39
+ searcher = SearchContents.new(path, params, query)
40
+ else
41
+ searcher = SearchFiles.new(path, params, query)
42
+ end
43
+
44
+ @total_records = searcher.total_records
45
+ @range = searcher.data_range
46
+ @record_content = searcher.html_contents + searcher.html_pagination;
47
+ @elapsed = Time.now - before
48
+ haml :search
49
+ end
50
+
51
+ def filelist(path, params, before)
52
+ @title = filelist_title(path)
53
+ @path = path
54
+ fileList = Database.instance.fileList(path)
55
+ @total_records = fileList.size
56
+ @record_content = fileList.map do |v|
57
+ "<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>"
58
+ end
59
+ @elapsed = Time.now - before
60
+ haml :filelist
61
+ end
62
+
63
+ def file_or_dirimg(is_file)
64
+ src = (is_file) ? '/images/file.png' : '/images/directory.png'
65
+ "<img alt='' style='vertical-align:bottom; border: 0; margin: 1px;' src='#{src}'>"
66
+ end
67
+ end
@@ -0,0 +1,260 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief Milkodeで使用するデータベース
5
+ # @author ongaeshi
6
+ # @date 2010/10/17
7
+
8
+ require 'rubygems'
9
+ require 'pathname'
10
+ require 'singleton'
11
+ require 'groonga'
12
+ require 'milkode/common/dbdir'
13
+ include Milkode
14
+
15
+ module Milkode
16
+ class Database
17
+ include Singleton
18
+
19
+ @@db_dir = nil
20
+
21
+ def self.setup(db_dir)
22
+ @@db_dir = db_dir
23
+ end
24
+
25
+ def initialize
26
+ open(@@db_dir || Dbdir.default_dir)
27
+ end
28
+
29
+ def open(db_dir)
30
+ dbfile = Dbdir.expand_groonga_path(db_dir)
31
+
32
+ if File.exist? dbfile
33
+ Groonga::Database.open(dbfile)
34
+ else
35
+ raise "error : #{dbfile} not found!!"
36
+ end
37
+
38
+ @documents = Groonga::Context.default["documents"]
39
+ end
40
+
41
+ def record(shortpath)
42
+ table = @documents.select { |record| record.shortpath == shortpath }
43
+ return table.records[0]
44
+ end
45
+
46
+ def fileNum
47
+ @documents.select.size
48
+ end
49
+
50
+ def search(patterns, packages, fpaths, suffixs, offset = 0, limit = -1)
51
+ # @todo fpathを厳密に検索するには、検索結果からさらに先頭からのパスではないものを除外する
52
+ records, total_records = searchMain(patterns, packages, fpaths, suffixs, offset, limit)
53
+ end
54
+
55
+ def selectAll(offset = 0, limit = -1)
56
+ table = @documents.select
57
+
58
+ # マッチ数
59
+ total_records = table.size
60
+
61
+ # 2010/10/29 ongaeshi
62
+ # 本当はこのようにgroongaAPIでソートしたいのだが上手くいかなかった
63
+ # # ファイル名順にソート
64
+ # records = table.sort([{:key => "shortpath", :order => "descending"}],
65
+ # :offset => page * limit,
66
+ # :limit => limit)
67
+
68
+ # ソート
69
+ if (limit != -1)
70
+ records = table.records.sort_by{|record| record.shortpath.downcase }[offset, limit]
71
+ else
72
+ records = table.records.sort_by{|record| record.shortpath.downcase }[offset..limit]
73
+ end
74
+
75
+ return records, total_records
76
+ end
77
+
78
+ def selectAll2(offset = 0, limit = -1)
79
+ records, total_records = selectAll(offset, limit)
80
+ records
81
+ end
82
+
83
+ # レコード数を得る
84
+ def totalRecords
85
+ reopen_patch
86
+ @documents.select.size
87
+ end
88
+
89
+ # @sample test/test_database.rb:43 TestDatabase#t_fileList
90
+ def fileList(base)
91
+ base_parts = base.split("/")
92
+ base_depth = base_parts.length
93
+
94
+ # shortpathにマッチするものだけに絞り込む
95
+ if (base == "")
96
+ records = @documents.select.records
97
+ else
98
+ records = @documents.select {|record| record.shortpath =~ base }.to_a
99
+ end
100
+
101
+ # ファイルリストの生成
102
+ paths = records.map {|record|
103
+ record.shortpath.split("/")
104
+ }.find_all {|parts|
105
+ parts.length > base_depth and parts[0, base_depth] == base_parts
106
+ }.map {|parts|
107
+ is_file = parts.length == base_depth + 1
108
+ path = parts[0, base_depth + 1].join("/")
109
+ [path, is_file]
110
+ }.uniq
111
+
112
+ paths
113
+ end
114
+
115
+ # コンテンツの削除
116
+ # @todo パッケージ名完全一致になっていないので直す
117
+ def remove(packages)
118
+ # データベースを開き直す
119
+ reopen_patch
120
+
121
+ # 削除したコンテンツをインデックスから削除
122
+ records, total_records = search([], packages, [], [])
123
+
124
+ # 検索結果はHashのレコードなので、これを直接deleteしても駄目
125
+ # 1. Record#record_idを使って主キー(Groonga#Arrayのレコード)を取り出し
126
+ # 2. Record#delete で削除
127
+ records.each do |r|
128
+ yield r if block_given?
129
+ r.record_id.delete
130
+ end
131
+ end
132
+
133
+ # 実体の存在しないデータを削除
134
+ def cleanup
135
+ # データベースを開き直す
136
+ reopen_patch
137
+
138
+ # クリーンアップ
139
+ records = selectAll2
140
+
141
+ records.each do |r|
142
+ unless File.exist? r.path
143
+ yield r if block_given?
144
+ r.record_id.delete
145
+ end
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def reopen_patch
152
+ # 削除系のコマンドが上手く動作しないためのパッチ
153
+ # 本質的な解決にはなっていないと思う
154
+ open(@@db_dir || Dbdir.default_dir)
155
+ end
156
+
157
+ def searchMain(patterns, packages, fpaths, suffixs, offset, limit)
158
+ table = @documents.select do |record|
159
+ expression = nil
160
+
161
+ # キーワード
162
+ patterns.each do |word|
163
+ sub_expression = record.content =~ word
164
+ if expression.nil?
165
+ expression = sub_expression
166
+ else
167
+ expression &= sub_expression
168
+ end
169
+ end
170
+
171
+ # パッケージ(OR)
172
+ pe = package_expression(record, packages)
173
+ if (pe)
174
+ if expression.nil?
175
+ expression = pe
176
+ else
177
+ expression &= pe
178
+ end
179
+ end
180
+
181
+ # ファイルパス
182
+ fpaths.each do |word|
183
+ sub_expression = record.path =~ word
184
+ if expression.nil?
185
+ expression = sub_expression
186
+ else
187
+ expression &= sub_expression
188
+ end
189
+ end
190
+
191
+ # 拡張子(OR)
192
+ se = suffix_expression(record, suffixs)
193
+ if (se)
194
+ if expression.nil?
195
+ expression = se
196
+ else
197
+ expression &= se
198
+ end
199
+ end
200
+
201
+ # 検索式
202
+ expression
203
+ end
204
+
205
+ # スコアとタイムスタンプでソート
206
+ records = table.sort([{:key => "_score", :order => "descending"},
207
+ {:key => "timestamp", :order => "descending"}],
208
+ :offset => offset,
209
+ :limit => limit)
210
+
211
+ # パッケージの条件追加
212
+ if (packages.size > 0)
213
+ records.delete_if do |record|
214
+ !packages.any?{|package| record.shortpath.split('/')[0] =~ /#{package}/ }
215
+ end
216
+ end
217
+
218
+ # マッチ数
219
+ total_records = records.size
220
+
221
+ return records, total_records
222
+ end
223
+ private :searchMain
224
+
225
+ def package_expression(record, packages)
226
+ sub = nil
227
+
228
+ # @todo 専用カラム package が欲しいところ
229
+ # でも今でもpackageはORとして機能してるからいいっちゃいい
230
+ packages.each do |word|
231
+ e = record.path =~ word
232
+ if sub.nil?
233
+ sub = e
234
+ else
235
+ sub |= e
236
+ end
237
+ end
238
+
239
+ sub
240
+ end
241
+ private :package_expression
242
+
243
+ def suffix_expression(record, suffixs)
244
+ sub = nil
245
+
246
+ suffixs.each do |word|
247
+ e = record.suffix =~ word
248
+ if sub.nil?
249
+ sub = e
250
+ else
251
+ sub |= e
252
+ end
253
+ end
254
+
255
+ sub
256
+ end
257
+ private :suffix_expression
258
+
259
+ end
260
+ end