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,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.5.2"
11
+ gem "rcov", ">= 0"
12
+ end
@@ -0,0 +1,18 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.5.2)
6
+ bundler (~> 1.0.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.8.7)
10
+ rcov (0.9.9)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 1.0.0)
17
+ jeweler (~> 1.5.2)
18
+ rcov
@@ -0,0 +1,5 @@
1
+ === 0.1.2 2011/07/03
2
+
3
+ * Syntax highlighting (using CodeRay)
4
+
5
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 ongaeshi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ = milkode
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to milkode
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 ongaeshi. See LICENSE.txt for
18
+ further details.
19
+
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ # begin
5
+ # Bundler.setup(:default, :development)
6
+ # rescue Bundler::BundlerError => e
7
+ # $stderr.puts e.message
8
+ # $stderr.puts "Run `bundle install` to install missing gems"
9
+ # exit e.status_code
10
+ # end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "milkode"
17
+ gem.homepage = "http://github.com/ongaeshi/milkode"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{Line based local source(src) code search engin & web-app}
20
+ gem.description = %Q{longer description of your gem}
21
+ gem.email = "ongaeshi0621@gmail.com"
22
+ gem.authors = ["ongaeshi"]
23
+
24
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
25
+ gem.add_runtime_dependency 'termcolor','>= 1.2.0'
26
+ gem.add_runtime_dependency 'rroonga','>= 1.0.0'
27
+ gem.add_runtime_dependency 'rack','>=1.2.1'
28
+ gem.add_runtime_dependency 'sinatra', '>=1.2.6'
29
+ gem.add_runtime_dependency 'launchy', '>=0.3.7'
30
+ gem.add_runtime_dependency 'coderay', '>=0.9.8'
31
+ gem.add_runtime_dependency 'thin', '>=1.2.10'
32
+ gem.add_runtime_dependency 'archive-zip', '>=0.3.0'
33
+
34
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
35
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
36
+ end
37
+ Jeweler::RubygemsDotOrgTasks.new
38
+
39
+ require 'rake/testtask'
40
+
41
+ # groonga関連のテストが通らないため、独自のrake_test_loaderを読み込む
42
+ module Rake
43
+ class TestTask < TaskLib
44
+ def rake_loader # :nodoc:
45
+ find_file('test/rake_test_loader') or
46
+ fail "unable to find rake test loader"
47
+ end
48
+ end
49
+ end
50
+
51
+ Rake::TestTask.new(:test) do |test|
52
+ test.libs << 'lib' << 'test'
53
+ test.pattern = 'test/**/test_*.rb'
54
+ test.verbose = true
55
+ end
56
+
57
+ # task :test do
58
+ # load "test/runner.rb"
59
+ # end
60
+
61
+ require 'rcov/rcovtask'
62
+ Rcov::RcovTask.new do |test|
63
+ test.libs << 'test'
64
+ test.pattern = 'test/**/test_*.rb'
65
+ test.verbose = true
66
+ end
67
+
68
+ task :default => :test
69
+
70
+ require 'rake/rdoctask'
71
+ Rake::RDocTask.new do |rdoc|
72
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
73
+
74
+ rdoc.rdoc_dir = 'rdoc'
75
+ rdoc.title = "milkode #{version}"
76
+ rdoc.rdoc_files.include('README*')
77
+ rdoc.rdoc_files.include('lib/**/*.rb')
78
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/cdv ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2010-8-25.
4
+ # Copyright (c) 2010. All rights reserved.
5
+
6
+ load File.join(File.dirname(__FILE__), "cdview")
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2010-8-25.
4
+ # Copyright (c) 2010. All rights reserved.
5
+
6
+ require 'rubygems'
7
+ require 'milkode/cdview/cli_cdview'
8
+
9
+ Version = "0.1.0"
10
+ Milkode::CLI_Cdview.execute(STDOUT, ARGV)
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2010-9-12.
4
+ # Copyright (c) 2010. All rights reserved.
5
+
6
+ require 'rubygems'
7
+ require 'milkode/cdstk/cli_cdstk'
8
+
9
+ Version = "0.1.0"
10
+ Milkode::CLI_Cdstk.execute(STDOUT, ARGV)
@@ -0,0 +1,508 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'yaml'
4
+ require 'pathname'
5
+ require 'rubygems'
6
+ require 'groonga'
7
+ require 'fileutils'
8
+ require 'pathname'
9
+ require 'milkode/cdstk/cdstk_yaml'
10
+ require 'milkode/common/grenfiletest'
11
+ require 'milkode/common/util'
12
+ include Milkode
13
+ require 'kconv'
14
+ require 'readline'
15
+ require 'milkode/cdweb/lib/database'
16
+ require 'open-uri'
17
+
18
+ module Milkode
19
+ class Cdstk
20
+ # バイグラムでトークナイズする。連続する記号・アルファベット・数字は一語として扱う。
21
+ # DEFAULT_TOKENIZER = "TokenBigram"
22
+
23
+ # 記号・アルファベット・数字もバイグラムでトークナイズする。
24
+ DEFAULT_TOKENIZER = "TokenBigramSplitSymbolAlphaDigit"
25
+
26
+ class ConvetError < RuntimeError ; end
27
+
28
+ def initialize(io = $stdout, db_dir = ".")
29
+ @db_dir = db_dir
30
+ Database.setup(@db_dir)
31
+ @out = io
32
+ clear_count
33
+ end
34
+
35
+ def clear_count
36
+ @package_count = 0
37
+ @file_count = 0
38
+ @add_count = 0
39
+ @update_count = 0
40
+ @start_time = Time.now
41
+ end
42
+
43
+ def init
44
+ if Dir.entries(@db_dir) == [".", ".."]
45
+ CdstkYaml.create(@db_dir)
46
+ @out.puts "create : #{yaml_file}"
47
+ db_create(db_file)
48
+ else
49
+ @out.puts "Can't create milkode db (Because not empty in #{db_dir_expand})"
50
+ end
51
+ end
52
+
53
+ def update(args = nil)
54
+ print_result do
55
+ yaml = yaml_load
56
+ query = args ? CdstkYaml::Query.new(args) : nil
57
+ update_list = yaml_load.list(query)
58
+
59
+ db_open(db_file)
60
+
61
+ update_list.each do |content|
62
+ update_dir_in(content["directory"])
63
+ end
64
+ end
65
+ end
66
+
67
+ def update_dir(dir)
68
+ update_dir_in(dir)
69
+ end
70
+
71
+ def add(contents)
72
+ # YAMLを読み込み
73
+ yaml = yaml_load
74
+
75
+ # コンテンツを読み込める形に変換
76
+ begin
77
+ contents.map!{|v|convert_content(v)}
78
+ rescue ConvetError
79
+ return
80
+ end
81
+
82
+ # 存在しないコンテンツがあった場合はその場で終了
83
+ contents.each do |v|
84
+ shortname = File.basename v
85
+ if (yaml.exist? shortname)
86
+ error_alert("already exist '#{shortname}'.")
87
+ return
88
+ end
89
+
90
+ unless (File.exist? v)
91
+ error_alert("not found '#{v}'.")
92
+ return
93
+ end
94
+ end
95
+
96
+ # YAML更新
97
+ yaml.add(contents)
98
+ yaml.save
99
+
100
+ # 部分アップデート
101
+ print_result do
102
+ db_open(db_file)
103
+ contents.each do |dir|
104
+ update_dir(dir)
105
+ end
106
+ end
107
+ end
108
+
109
+ def convert_content(src)
110
+ # httpファイルならダウンロード
111
+ begin
112
+ src = download_file(src)
113
+ rescue => e
114
+ error_alert("download failure '#{src}'.")
115
+ raise e # そのまま上に持ち上げてスタックトレース表示
116
+ end
117
+
118
+ # アーカイブファイルなら展開
119
+ begin
120
+ src = extract_file(src)
121
+ rescue => e
122
+ error_alert("extract failure '#{src}'.")
123
+ raise e # そのまま上に持ち上げてスタックトレース表示
124
+ end
125
+
126
+ # 絶対パスに変換
127
+ File.expand_path(src)
128
+ end
129
+
130
+ def extract_file(src)
131
+ ext = File.extname(src);
132
+
133
+ case ext
134
+ when '.zip', '.xpi'
135
+ alert("extract", "#{src}")
136
+ zip_dir = File.join(@db_dir, "packages/#{ext.sub(".", "")}")
137
+ result = File.join(zip_dir, Util::zip_extract(src, zip_dir))
138
+ else
139
+ src
140
+ end
141
+ end
142
+
143
+ def download_file(src)
144
+ if (src =~ /^https?:/)
145
+ download_file_in(src)
146
+ else
147
+ src
148
+ end
149
+ end
150
+
151
+ def download_file_in(url)
152
+ alert("download", "#{url}")
153
+
154
+ dst_dir = File.join(@db_dir, "packages/http")
155
+ FileUtils.mkdir_p dst_dir
156
+
157
+ filename = File.join(dst_dir, File.basename(url))
158
+
159
+ open(url) do |src|
160
+ open(filename, "wb") do |dst|
161
+ dst.write(src.read)
162
+ end
163
+ end
164
+
165
+ filename
166
+ end
167
+
168
+ def remove(args, options)
169
+ print_result do
170
+ db_open(db_file)
171
+
172
+ yaml = yaml_load
173
+ query = CdstkYaml::Query.new(args)
174
+
175
+ remove_list = yaml_load.list(query)
176
+ return if remove_list.empty?
177
+
178
+ list(args, {:verbose => true})
179
+
180
+ if options[:force] or yes_or_no("Remove #{remove_list.size} contents? (yes/no)")
181
+ # yamlから削除
182
+ yaml.remove(query)
183
+ yaml.save
184
+
185
+ # データベースからも削除
186
+ packages = remove_list.map{|v| File.basename v['directory']}
187
+
188
+ # 本当はパッケージの配列をまとめて渡した方が効率が良いのだが、表示を綺麗にするため
189
+ packages.each do |package|
190
+ alert("rm_package", package)
191
+ @package_count += 1
192
+
193
+ Database.instance.remove(package) do |record|
194
+ alert("rm_record", record.path)
195
+ @file_count += 1
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ def yes_or_no(msg)
203
+ @out.puts msg
204
+ while buf = Readline.readline("> ")
205
+ case buf
206
+ when 'yes'
207
+ return true
208
+ when 'no'
209
+ break
210
+ end
211
+ end
212
+ return false
213
+ end
214
+
215
+ def list(args, options)
216
+ query = (args.empty?) ? nil : CdstkYaml::Query.new(args)
217
+ a = yaml_load.list(query).map {|v| [File.basename(v['directory']), v['directory']] }
218
+ max = a.map{|v|v[0].length}.max
219
+ str = a.sort_by {|v|
220
+ v[0]
221
+ }.map {|v|
222
+ h = File.exist?(v[1]) ? '' : '? '
223
+ if (options[:verbose])
224
+ "#{(h + v[0]).ljust(max+2)} #{v[1]}"
225
+ else
226
+ "#{h}#{v[0]}"
227
+ end
228
+ }.join("\n")
229
+
230
+ @out.puts str
231
+ end
232
+
233
+ def pwd(options)
234
+ dir = options[:default] ? Dbdir.default_dir : db_dir_expand
235
+
236
+ if File.exist? dir
237
+ @out.puts dir
238
+ else
239
+ @out.puts "Not found db in #{Dir.pwd}"
240
+ end
241
+ end
242
+
243
+ def cleanup(options)
244
+ if (options[:force] or yes_or_no("cleanup contents? (yes/no)"))
245
+ print_result do
246
+ # yamlファイルのクリーンアップ
247
+ yaml = yaml_load
248
+
249
+ yaml.cleanup do |v|
250
+ alert("rm_package", v['directory'])
251
+ @package_count += 1
252
+ end
253
+
254
+ yaml.save
255
+
256
+ # データベースのクリーンアップ
257
+ Database.instance.cleanup do |record|
258
+ alert("rm_record", record.path)
259
+ @file_count += 1
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ def rebuild
266
+ db_delete(db_file)
267
+ db_create(db_file)
268
+ update
269
+ end
270
+
271
+ def dump
272
+ db_open(db_file)
273
+
274
+ documents = Groonga::Context.default["documents"]
275
+ records = documents.select
276
+ records.each do |record|
277
+ @out.puts record.inspect
278
+ @out.puts "path : #{record.path}"
279
+ @out.puts "shortpath : #{record.shortpath}"
280
+ @out.puts "suffix : #{record.suffix}"
281
+ @out.puts "timestamp : #{record.timestamp.strftime('%Y/%m/%d %H:%M:%S')}"
282
+ @out.puts "content :", record.content ? record.content[0..64] : nil
283
+ @out.puts
284
+ end
285
+ @out.puts "total #{records.size} record."
286
+ end
287
+
288
+ private
289
+
290
+ def db_file
291
+ Dbdir.expand_groonga_path(@db_dir)
292
+ end
293
+
294
+ def db_file_expand
295
+ File.expand_path(db_file)
296
+ end
297
+
298
+ def db_dir_expand
299
+ File.expand_path(@db_dir)
300
+ end
301
+
302
+ def yaml_file
303
+ CdstkYaml.yaml_file @db_dir
304
+ end
305
+
306
+ def yaml_load
307
+ CdstkYaml.load(@db_dir)
308
+ end
309
+
310
+ def update_dir_in(dir)
311
+ alert("package", File.basename(dir) )
312
+ @package_count += 1
313
+
314
+ dir = File.expand_path(dir)
315
+
316
+ if (!FileTest.exist?(dir))
317
+ @out.puts "[WARNING] : #{dir} (Not found, skip)"
318
+ elsif (FileTest.directory? dir)
319
+ db_add_dir(dir)
320
+ else
321
+ db_add_file(STDOUT, dir, File.basename(dir))
322
+ end
323
+ end
324
+
325
+ def time
326
+ @end_time - @start_time
327
+ end
328
+
329
+ def print_result
330
+ clear_count
331
+ yield
332
+ @end_time = Time.now
333
+
334
+ result_info
335
+ milkode_info
336
+ end
337
+
338
+ def result_info
339
+ r = []
340
+ r << "#{@package_count} packages" if @package_count > 0
341
+ r << "#{@file_count} records" if @file_count > 0
342
+ r << "#{@add_count} add" if @add_count > 0
343
+ r << "#{@update_count} update" if @update_count > 0
344
+ r.join(', ')
345
+ alert('result', "#{r.join(', ')}. (#{Gren::Util::time_s(time)})")
346
+ end
347
+
348
+ def milkode_info
349
+ alert('*milkode*', "#{yaml_load.package_num} packages, #{Database.instance.totalRecords} records in #{db_file}.")
350
+ end
351
+
352
+ def db_create(filename)
353
+ dbfile = Pathname(File.expand_path(filename))
354
+ dbdir = dbfile.dirname
355
+ dbdir.mkpath unless dbdir.exist?
356
+
357
+ unless dbfile.exist?
358
+ Groonga::Database.create(:path => dbfile.to_s)
359
+ Groonga::Schema.define do |schema|
360
+ schema.create_table("documents") do |table|
361
+ table.string("path")
362
+ table.string("shortpath")
363
+ table.text("content")
364
+ table.time("timestamp")
365
+ table.text("suffix")
366
+ end
367
+
368
+ schema.create_table("terms",
369
+ :type => :patricia_trie,
370
+ :key_normalize => true,
371
+ :default_tokenizer => DEFAULT_TOKENIZER) do |table|
372
+ table.index("documents.path", :with_position => true)
373
+ table.index("documents.shortpath", :with_position => true)
374
+ table.index("documents.content", :with_position => true)
375
+ table.index("documents.suffix", :with_position => true)
376
+ end
377
+ end
378
+ @out.puts "create : #{filename} created."
379
+ else
380
+ @out.puts "message : #{filename} already exist."
381
+ end
382
+ end
383
+
384
+ def db_open(filename)
385
+ dbfile = Pathname(File.expand_path(filename))
386
+
387
+ if dbfile.exist?
388
+ Groonga::Database.open(dbfile.to_s)
389
+ # @out.puts "open : #{dbfile} open."
390
+ else
391
+ raise "error : #{dbfile.to_s} not found!!"
392
+ end
393
+ end
394
+
395
+ def db_delete(filename)
396
+ raise "Illegal file name : #{filename}." unless filename =~ /\.db$/
397
+ Dir.glob("#{filename}*").each do |f|
398
+ @out.puts "delete : #{f}"
399
+ FileUtils.rm_r(f)
400
+ end
401
+ end
402
+ private :db_delete
403
+
404
+ def db_add_dir(dirname)
405
+ searchDirectory(STDOUT, dirname, File.basename(dirname), 0)
406
+ end
407
+ private :db_add_dir
408
+
409
+ def db_add_file(stdout, filename, shortpath)
410
+ # 格納するデータ
411
+ values = {
412
+ :path => filename,
413
+ :shortpath => shortpath,
414
+ :content => nil,
415
+ :timestamp => File.mtime(filename),
416
+ :suffix => File::extname(filename),
417
+ }
418
+
419
+ # 検索するデータベース
420
+ documents = Groonga::Context.default["documents"]
421
+
422
+ # 既に登録されているファイルならばそれを上書き、そうでなければ新規レコードを作成
423
+ _documents = documents.select do |record|
424
+ record["path"] == values[:path]
425
+ end
426
+
427
+ isNewFile = false
428
+
429
+ if _documents.size.zero?
430
+ document = documents.add
431
+ isNewFile = true
432
+ else
433
+ document = _documents.to_a[0].key
434
+ end
435
+
436
+ # タイムスタンプが新しければデータベースに格納
437
+ if (document[:timestamp] < values[:timestamp])
438
+ # 実際に使うタイミングでファイルの内容を読み込み
439
+ # values[:content] = open(filename).read
440
+ # データベース内の文字コードは'utf-8'で統一
441
+ values[:content] = File.read(filename).kconv(Kconv::UTF8)
442
+
443
+ # データベースに格納
444
+ values.each do |key, value|
445
+ if (key == :path)
446
+ if (isNewFile)
447
+ @add_count += 1
448
+ alert("add_record", value)
449
+ else
450
+ @update_count += 1
451
+ alert("update", value)
452
+ end
453
+ end
454
+ document[key] = value
455
+ end
456
+ end
457
+
458
+ end
459
+
460
+ def searchDirectory(stdout, dir, shortdir, depth)
461
+ Dir.foreach(dir) do |name|
462
+ next if (name == '.' || name == '..')
463
+
464
+ fpath = File.join(dir,name)
465
+ shortpath = File.join(shortdir,name)
466
+
467
+ # 除外ディレクトリならばパス
468
+ next if ignoreDir?(fpath)
469
+
470
+ # 読み込み不可ならばパス
471
+ next unless FileTest.readable?(fpath)
472
+
473
+ # ファイルならば中身を探索、ディレクトリならば再帰
474
+ case File.ftype(fpath)
475
+ when "directory"
476
+ searchDirectory(stdout, fpath, shortpath, depth + 1)
477
+ when "file"
478
+ unless ignoreFile?(fpath)
479
+ db_add_file(stdout, fpath, shortpath)
480
+ @file_count += 1
481
+ # @out.puts "file_count : #{@file_count}" if (@file_count % 100 == 0)
482
+ end
483
+ end
484
+ end
485
+ end
486
+
487
+ def ignoreDir?(fpath)
488
+ FileTest.directory?(fpath) &&
489
+ GrenFileTest::ignoreDir?(fpath)
490
+ end
491
+ private :ignoreDir?
492
+
493
+ def ignoreFile?(fpath)
494
+ GrenFileTest::ignoreFile?(fpath) ||
495
+ GrenFileTest::binary?(fpath)
496
+ end
497
+ private :ignoreFile?
498
+
499
+ def alert(title, msg)
500
+ @out.puts "#{title.ljust(10)} : #{msg}"
501
+ end
502
+
503
+ def error_alert(msg)
504
+ @out.puts "[fatal] #{msg}"
505
+ end
506
+
507
+ end
508
+ end