gonzui 1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS.txt +9 -0
- data/History.txt +5539 -0
- data/Manifest.txt +115 -0
- data/PostInstall.txt +17 -0
- data/README.rdoc +149 -0
- data/Rakefile +28 -0
- data/bin/gonzui-db +167 -0
- data/bin/gonzui-import +177 -0
- data/bin/gonzui-remove +58 -0
- data/bin/gonzui-search +68 -0
- data/bin/gonzui-server +176 -0
- data/bin/gonzui-update +53 -0
- data/data/gonzui/catalog/catalog.ja +80 -0
- data/data/gonzui/doc/favicon.ico +0 -0
- data/data/gonzui/doc/folder.png +0 -0
- data/data/gonzui/doc/gonzui.css +279 -0
- data/data/gonzui/doc/gonzui.js +111 -0
- data/data/gonzui/doc/text.png +0 -0
- data/data/gonzuirc.sample +29 -0
- data/ext/autopack/autopack.c +88 -0
- data/ext/autopack/extconf.rb +3 -0
- data/ext/delta/delta.c +147 -0
- data/ext/delta/extconf.rb +5 -0
- data/ext/texttokenizer/extconf.rb +5 -0
- data/ext/texttokenizer/texttokenizer.c +93 -0
- data/ext/xmlformatter/extconf.rb +5 -0
- data/ext/xmlformatter/xmlformatter.c +207 -0
- data/lib/gonzui.rb +59 -0
- data/lib/gonzui/apt.rb +193 -0
- data/lib/gonzui/bdbdbm.rb +118 -0
- data/lib/gonzui/cmdapp.rb +14 -0
- data/lib/gonzui/cmdapp/app.rb +175 -0
- data/lib/gonzui/cmdapp/search.rb +134 -0
- data/lib/gonzui/config.rb +117 -0
- data/lib/gonzui/content.rb +19 -0
- data/lib/gonzui/dbm.rb +673 -0
- data/lib/gonzui/deindexer.rb +162 -0
- data/lib/gonzui/delta.rb +49 -0
- data/lib/gonzui/extractor.rb +347 -0
- data/lib/gonzui/fetcher.rb +309 -0
- data/lib/gonzui/gettext.rb +144 -0
- data/lib/gonzui/importer.rb +84 -0
- data/lib/gonzui/indexer.rb +316 -0
- data/lib/gonzui/info.rb +80 -0
- data/lib/gonzui/license.rb +100 -0
- data/lib/gonzui/logger.rb +48 -0
- data/lib/gonzui/monitor.rb +177 -0
- data/lib/gonzui/progressbar.rb +235 -0
- data/lib/gonzui/remover.rb +38 -0
- data/lib/gonzui/searcher.rb +330 -0
- data/lib/gonzui/searchquery.rb +235 -0
- data/lib/gonzui/searchresult.rb +111 -0
- data/lib/gonzui/updater.rb +254 -0
- data/lib/gonzui/util.rb +415 -0
- data/lib/gonzui/vcs.rb +128 -0
- data/lib/gonzui/webapp.rb +25 -0
- data/lib/gonzui/webapp/advsearch.rb +123 -0
- data/lib/gonzui/webapp/filehandler.rb +24 -0
- data/lib/gonzui/webapp/jsfeed.rb +61 -0
- data/lib/gonzui/webapp/markup.rb +445 -0
- data/lib/gonzui/webapp/search.rb +269 -0
- data/lib/gonzui/webapp/servlet.rb +319 -0
- data/lib/gonzui/webapp/snippet.rb +155 -0
- data/lib/gonzui/webapp/source.rb +37 -0
- data/lib/gonzui/webapp/stat.rb +137 -0
- data/lib/gonzui/webapp/top.rb +63 -0
- data/lib/gonzui/webapp/uri.rb +140 -0
- data/lib/gonzui/webapp/webrick.rb +48 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/makemanifest.rb +21 -0
- data/tasks/extconf.rake +13 -0
- data/tasks/extconf/autopack.rake +43 -0
- data/tasks/extconf/delta.rake +43 -0
- data/tasks/extconf/texttokenizer.rake +43 -0
- data/tasks/extconf/xmlformatter.rake +43 -0
- data/test/_external_tools.rb +13 -0
- data/test/_test-util.rb +142 -0
- data/test/foo/Makefile.foo +66 -0
- data/test/foo/bar.c +5 -0
- data/test/foo/bar.h +6 -0
- data/test/foo/foo.c +25 -0
- data/test/foo/foo.spec +33 -0
- data/test/test_apt.rb +42 -0
- data/test/test_autopack_extn.rb +7 -0
- data/test/test_bdbdbm.rb +79 -0
- data/test/test_cmdapp-app.rb +35 -0
- data/test/test_cmdapp-search.rb +99 -0
- data/test/test_config.rb +28 -0
- data/test/test_content.rb +15 -0
- data/test/test_dbm.rb +171 -0
- data/test/test_deindexer.rb +50 -0
- data/test/test_delta.rb +66 -0
- data/test/test_extractor.rb +78 -0
- data/test/test_fetcher.rb +75 -0
- data/test/test_gettext.rb +50 -0
- data/test/test_gonzui.rb +11 -0
- data/test/test_helper.rb +10 -0
- data/test/test_importer.rb +56 -0
- data/test/test_indexer.rb +37 -0
- data/test/test_info.rb +82 -0
- data/test/test_license.rb +49 -0
- data/test/test_logger.rb +60 -0
- data/test/test_monitor.rb +23 -0
- data/test/test_searcher.rb +37 -0
- data/test/test_searchquery.rb +27 -0
- data/test/test_searchresult.rb +43 -0
- data/test/test_texttokenizer.rb +47 -0
- data/test/test_updater.rb +95 -0
- data/test/test_util.rb +149 -0
- data/test/test_vcs.rb +61 -0
- data/test/test_webapp-markup.rb +42 -0
- data/test/test_webapp-util.rb +19 -0
- data/test/test_webapp-xmlformatter.rb +19 -0
- metadata +291 -0
@@ -0,0 +1,309 @@
|
|
1
|
+
#
|
2
|
+
# fetcher.rb - fetch contents from various sources
|
3
|
+
#
|
4
|
+
# Copyright (C) 2004-2005 Satoru Takabayashi <satoru@namazu.org>
|
5
|
+
# All rights reserved.
|
6
|
+
# This is free software with ABSOLUTELY NO WARRANTY.
|
7
|
+
#
|
8
|
+
# You can redistribute it and/or modify it under the terms of
|
9
|
+
# the GNU General Public License version 2.
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'open-uri'
|
13
|
+
require 'webrick/httputils'
|
14
|
+
require 'ftools'
|
15
|
+
|
16
|
+
module Gonzui
|
17
|
+
class FetcherError < GonzuiError; end
|
18
|
+
class FetchFailed < FetcherError; end
|
19
|
+
|
20
|
+
module Fetcher
|
21
|
+
extend Util
|
22
|
+
FetcherRegistory = {}
|
23
|
+
|
24
|
+
module_function
|
25
|
+
def new(config, source_uri, options = {})
|
26
|
+
klass = FetcherRegistory[source_uri.scheme]
|
27
|
+
if klass.nil?
|
28
|
+
raise FetcherError.new("#{source_uri.scheme}: unsupported scheme")
|
29
|
+
end
|
30
|
+
if source_uri.path.nil?
|
31
|
+
raise FetcherError.new("#{source_uri.to_s}: malformed URI")
|
32
|
+
end
|
33
|
+
fetcher = klass.new(config, source_uri, options)
|
34
|
+
if fetcher.need_extraction? # fallback to FileFetcher
|
35
|
+
extractor = fetcher.get_extractor
|
36
|
+
directory = extractor.extract
|
37
|
+
fetcher.finish
|
38
|
+
|
39
|
+
source_uri = URI.from_path(directory)
|
40
|
+
fetcher = FileFetcher.new(config, source_uri, options)
|
41
|
+
fetcher.add_finishing_proc(lambda { extractor.clean })
|
42
|
+
end
|
43
|
+
return fetcher
|
44
|
+
end
|
45
|
+
|
46
|
+
def register(klass)
|
47
|
+
FetcherRegistory[klass.scheme] = klass
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class AbstractFetcher
|
52
|
+
include Util
|
53
|
+
|
54
|
+
def initialize(config, source_uri, options = {})
|
55
|
+
@config = config
|
56
|
+
@source_uri = source_uri
|
57
|
+
@exclude_pattern = (options[:exclude_pattern] or @config.exclude_pattern)
|
58
|
+
@finishing_procs = []
|
59
|
+
@base_uri = source_uri
|
60
|
+
end
|
61
|
+
|
62
|
+
public
|
63
|
+
def add_finishing_proc (proc)
|
64
|
+
@finishing_procs.push(proc)
|
65
|
+
end
|
66
|
+
|
67
|
+
def collect
|
68
|
+
raise NotImplementedError.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def exclude?(relative_path)
|
72
|
+
@exclude_pattern.match(relative_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def fetch(relative_path)
|
76
|
+
raise NotImplementedError.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def finish
|
80
|
+
@finishing_procs.each {|proc| proc.call }
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_extractor
|
84
|
+
raise NotImplementedError.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def need_extraction?
|
88
|
+
raise NotImplementedError.new
|
89
|
+
end
|
90
|
+
|
91
|
+
def package_name
|
92
|
+
File.basename(@base_uri.path)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class FileFetcher < AbstractFetcher
|
97
|
+
def self.scheme
|
98
|
+
"file"
|
99
|
+
end
|
100
|
+
|
101
|
+
def initialize(config, source_uri, options)
|
102
|
+
super(config, source_uri, options)
|
103
|
+
begin
|
104
|
+
File.ftype(source_uri.path)
|
105
|
+
rescue => e
|
106
|
+
raise FetchFailed.new(e.message)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
def restore_path(relative_path)
|
112
|
+
File.join(@base_uri.path, relative_path)
|
113
|
+
end
|
114
|
+
|
115
|
+
public
|
116
|
+
def need_extraction?
|
117
|
+
not File.directory?(@source_uri.path)
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_extractor
|
121
|
+
return Extractor.new(@config, @source_uri.path)
|
122
|
+
end
|
123
|
+
|
124
|
+
def fetch(relative_path)
|
125
|
+
path = restore_path(relative_path)
|
126
|
+
content = File.read(path)
|
127
|
+
mtime = File.mtime(path)
|
128
|
+
return Content.new(content, mtime, path)
|
129
|
+
end
|
130
|
+
|
131
|
+
def collect
|
132
|
+
directory = @base_uri.path
|
133
|
+
relative_paths = []
|
134
|
+
Dir.all_files(directory).map {|file_name|
|
135
|
+
next if exclude?(file_name)
|
136
|
+
relative_path = File.relative_path(file_name, directory)
|
137
|
+
relative_paths.push(relative_path)
|
138
|
+
}
|
139
|
+
return relative_paths
|
140
|
+
end
|
141
|
+
|
142
|
+
Fetcher.register(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
# FIXME: very ad hoc implementation
|
146
|
+
class HTTPFetcher < AbstractFetcher
|
147
|
+
include TemporaryDirectoryUtil
|
148
|
+
def self.scheme
|
149
|
+
"http"
|
150
|
+
end
|
151
|
+
|
152
|
+
def initialize(config, source_uri, options)
|
153
|
+
super(config, source_uri, options)
|
154
|
+
begin
|
155
|
+
open(source_uri.to_s) {|f|
|
156
|
+
@content = f.read
|
157
|
+
@content_type = f.content_type
|
158
|
+
@base_uri = f.base_uri
|
159
|
+
}
|
160
|
+
rescue OpenURI::HTTPError => e
|
161
|
+
raise FetchFailed.new("#{source_uri.to_s}: #{e.message}")
|
162
|
+
end
|
163
|
+
|
164
|
+
# http://example.com/foo/index.html => http://example.com/foo/
|
165
|
+
unless /\/$/.match(@base_uri.path) #/
|
166
|
+
@base_uri.path = File.dirname(@base_uri.path) + "/"
|
167
|
+
end
|
168
|
+
set_temporary_directory(@config.temporary_directory)
|
169
|
+
end
|
170
|
+
|
171
|
+
def restore_uri(relative_path)
|
172
|
+
u = @base_uri.to_s + relative_path
|
173
|
+
URI.parse(u)
|
174
|
+
end
|
175
|
+
|
176
|
+
public
|
177
|
+
def need_extraction?
|
178
|
+
@content_type != "text/html"
|
179
|
+
end
|
180
|
+
|
181
|
+
def get_extractor
|
182
|
+
prepare_temporary_directory
|
183
|
+
tmp_name = File.join(self.temporary_directory,
|
184
|
+
File.basename(@source_uri.path))
|
185
|
+
File.open(tmp_name, "w") {|f| f.write(@content) }
|
186
|
+
add_finishing_proc(lambda { clean_temporary_directory })
|
187
|
+
return Extractor.new(@config, tmp_name)
|
188
|
+
end
|
189
|
+
|
190
|
+
def fetch(relative_path)
|
191
|
+
uri = restore_uri(relative_path)
|
192
|
+
content = mtime = nil
|
193
|
+
open(uri.to_s) {|f|
|
194
|
+
content = f.read
|
195
|
+
mtime = f.last_modified
|
196
|
+
}
|
197
|
+
return Content.new(content, mtime)
|
198
|
+
end
|
199
|
+
|
200
|
+
def collect
|
201
|
+
relative_paths = []
|
202
|
+
@content.scan(/href=(["'])(.*?)\1/i).each {|qmark, link|
|
203
|
+
u = URI.parse(link)
|
204
|
+
next if u.path.nil?
|
205
|
+
u.path.chomp!("/")
|
206
|
+
next unless u.relative?
|
207
|
+
next if /^\./.match(u.path)
|
208
|
+
next if exclude?(u.path)
|
209
|
+
relative_paths.push(u.path)
|
210
|
+
}
|
211
|
+
return relative_paths
|
212
|
+
end
|
213
|
+
|
214
|
+
Fetcher.register(self)
|
215
|
+
end
|
216
|
+
|
217
|
+
class AptFetcher < AbstractFetcher
|
218
|
+
def self.scheme
|
219
|
+
"apt-get"
|
220
|
+
end
|
221
|
+
|
222
|
+
def need_extraction?
|
223
|
+
true
|
224
|
+
end
|
225
|
+
|
226
|
+
def get_extractor
|
227
|
+
package_name = @source_uri.path.prechop
|
228
|
+
return AptGet.new(@config, package_name)
|
229
|
+
end
|
230
|
+
|
231
|
+
Fetcher.register(self)
|
232
|
+
end
|
233
|
+
|
234
|
+
class CVSFetcher < AbstractFetcher
|
235
|
+
def self.scheme
|
236
|
+
"cvs"
|
237
|
+
end
|
238
|
+
|
239
|
+
def need_extraction?
|
240
|
+
true
|
241
|
+
end
|
242
|
+
|
243
|
+
def get_extractor
|
244
|
+
query = WEBrick::HTTPUtils.parse_query(@source_uri.query)
|
245
|
+
prefix = query["prefix"]
|
246
|
+
mozule = query["module"]
|
247
|
+
assert_non_nil(mozule)
|
248
|
+
root = @source_uri.path
|
249
|
+
root = @source_uri.host + ":" + root if @source_uri.host
|
250
|
+
root = prefix + "@" + root if prefix
|
251
|
+
return CVS.new(@config, root, mozule)
|
252
|
+
end
|
253
|
+
|
254
|
+
Fetcher.register(self)
|
255
|
+
end
|
256
|
+
|
257
|
+
class SubversionFetcher < AbstractFetcher
|
258
|
+
def self.scheme
|
259
|
+
"svn"
|
260
|
+
end
|
261
|
+
|
262
|
+
def need_extraction?
|
263
|
+
true
|
264
|
+
end
|
265
|
+
|
266
|
+
def get_extractor
|
267
|
+
query = WEBrick::HTTPUtils.parse_query(@source_uri.query)
|
268
|
+
mozule = query["module"]
|
269
|
+
assert_non_nil(mozule)
|
270
|
+
uri = @source_uri.dup
|
271
|
+
uri.scheme = query["original_scheme"] if query["original_scheme"]
|
272
|
+
uri.query = nil
|
273
|
+
root = uri.to_s
|
274
|
+
# FIXME: kludge for replacing file:/home/... ->
|
275
|
+
# file:///home/... because subversion doesn't allow
|
276
|
+
# the former URI.
|
277
|
+
root.gsub!(%r!^file:/+!, "file:///") if uri.scheme == "file"
|
278
|
+
return Subversion.new(@config, root, mozule)
|
279
|
+
end
|
280
|
+
|
281
|
+
Fetcher.register(self)
|
282
|
+
end
|
283
|
+
|
284
|
+
class GitFetcher < AbstractFetcher
|
285
|
+
def self.scheme
|
286
|
+
"git"
|
287
|
+
end
|
288
|
+
|
289
|
+
def need_extraction?
|
290
|
+
true
|
291
|
+
end
|
292
|
+
|
293
|
+
def get_extractor
|
294
|
+
query = WEBrick::HTTPUtils.parse_query(@source_uri.query)
|
295
|
+
mozule = query["module"]
|
296
|
+
uri = @source_uri.dup
|
297
|
+
uri.scheme = query["original_scheme"] if query["original_scheme"]
|
298
|
+
uri.query = nil
|
299
|
+
root = uri.to_s
|
300
|
+
# FIXME: kludge for replacing file:/home/... ->
|
301
|
+
# file:///home/... because git doesn't allow
|
302
|
+
# the former URI.
|
303
|
+
root.gsub!(%r!^file:/+!, "file:///") if uri.scheme == "file"
|
304
|
+
return Git.new(@config, root, mozule)
|
305
|
+
end
|
306
|
+
|
307
|
+
Fetcher.register(self)
|
308
|
+
end
|
309
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
#
|
2
|
+
# gettext.rb - a simple gettext-like module
|
3
|
+
#
|
4
|
+
# Copyright (C) 2004-2005 Satoru Takabayashi <satoru@namazu.org>
|
5
|
+
# All rights reserved.
|
6
|
+
# This is free software with ABSOLUTELY NO WARRANTY.
|
7
|
+
#
|
8
|
+
# You can redistribute it and/or modify it under the terms of
|
9
|
+
# the GNU General Public License version 2.
|
10
|
+
#
|
11
|
+
|
12
|
+
module Gonzui
|
13
|
+
module GetText
|
14
|
+
def gettext(text)
|
15
|
+
return text unless @gettext_catalog
|
16
|
+
return (@gettext_catalog[text] or text)
|
17
|
+
end
|
18
|
+
alias :_ :gettext
|
19
|
+
|
20
|
+
def gettext_noop(text)
|
21
|
+
text
|
22
|
+
end
|
23
|
+
alias :N_ :gettext_noop
|
24
|
+
|
25
|
+
def set_catalog(catalog)
|
26
|
+
@gettext_catalog = catalog
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_catalog(file_name)
|
30
|
+
return eval(File.read(file_name))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CatalogRepository
|
35
|
+
include GetText
|
36
|
+
|
37
|
+
def initialize(directory)
|
38
|
+
@catalogs = {}
|
39
|
+
Dir.entries(directory).each {|entry|
|
40
|
+
file_name = File.join(directory, entry)
|
41
|
+
if m = /^catalog\.([\w.-]+)$/.match(File.basename(file_name))
|
42
|
+
lang = m[1]
|
43
|
+
catalog = load_catalog(file_name)
|
44
|
+
@catalogs[lang] = catalog
|
45
|
+
end
|
46
|
+
}
|
47
|
+
@catalogs["en"] = Hash.new {|h, k| k }
|
48
|
+
end
|
49
|
+
|
50
|
+
public
|
51
|
+
def choose(lang_name)
|
52
|
+
@catalogs[lang_name]
|
53
|
+
end
|
54
|
+
|
55
|
+
def each
|
56
|
+
@catalogs.each {|lang_name, catalog|
|
57
|
+
yield(lang_name, catalog)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
class CatalogValidator
|
64
|
+
def initialize(source_file_name, messages)
|
65
|
+
@source_file_name = source_file_name
|
66
|
+
@gettext_catalog = messages
|
67
|
+
@error_messages = []
|
68
|
+
end
|
69
|
+
attr_reader :error_messages
|
70
|
+
|
71
|
+
def read_file_with_numbering(file_name)
|
72
|
+
content = ''
|
73
|
+
File.open(file_name).each_with_index {|line, idx|
|
74
|
+
lineno = idx + 1
|
75
|
+
content << line.gsub(/\bN?_\(/, "_[#{lineno}](")
|
76
|
+
}
|
77
|
+
content
|
78
|
+
end
|
79
|
+
|
80
|
+
def collect_messages(content)
|
81
|
+
messages = []
|
82
|
+
while content.sub!(/\bN?_\[(\d+)\]\(("(?:\\"|.)*?").*?\)/m, "")
|
83
|
+
lineno = $1.to_i
|
84
|
+
message = eval($2)
|
85
|
+
messages.push([lineno, message])
|
86
|
+
end
|
87
|
+
messages
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate
|
91
|
+
@gettext_catalog or return
|
92
|
+
content = read_file_with_numbering(@source_file_name)
|
93
|
+
messages = collect_messages(content)
|
94
|
+
messages.each {|lineno, message|
|
95
|
+
translated_message = @gettext_catalog[message]
|
96
|
+
if not translated_message
|
97
|
+
message =
|
98
|
+
sprintf("%s:%d: %s", @source_file_name, lineno, message.inspect)
|
99
|
+
@error_messages.push(message)
|
100
|
+
elsif message.count("%") != translated_message.count("%")
|
101
|
+
message = sprintf("%s:%d: %s => # of %% mismatch.",
|
102
|
+
@source_file_name,
|
103
|
+
lineno, message.inspect, translated_message)
|
104
|
+
@error_messages.push(message)
|
105
|
+
end
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
def ok?
|
110
|
+
@error_messages.empty?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if __FILE__ == $0
|
116
|
+
include Gonzui
|
117
|
+
include Gonzui::GetText
|
118
|
+
|
119
|
+
def main
|
120
|
+
if ARGV.length < 2
|
121
|
+
puts "usage: ruby catalog-validator.rb <catalog directory> <source...>"
|
122
|
+
exit
|
123
|
+
end
|
124
|
+
|
125
|
+
catalog_directory = ARGV.shift
|
126
|
+
catalog_repository = CatalogRepository.new(catalog_directory)
|
127
|
+
|
128
|
+
ok = true
|
129
|
+
catalog_repository.each {|lang_name, catalog|
|
130
|
+
set_catalog(catalog)
|
131
|
+
ARGV.each {|source_file|
|
132
|
+
validator = CatalogValidator.new(source_file, catalog)
|
133
|
+
validator.validate
|
134
|
+
validator.error_messages.each {|message|
|
135
|
+
printf("%s: %s\n", lang_name, message)
|
136
|
+
}
|
137
|
+
ok = (ok and validator.ok?)
|
138
|
+
}
|
139
|
+
}
|
140
|
+
if ok then exit else exit(1) end
|
141
|
+
end
|
142
|
+
|
143
|
+
main
|
144
|
+
end
|