gonzui 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/AUTHORS.txt +9 -0
  2. data/History.txt +5539 -0
  3. data/Manifest.txt +115 -0
  4. data/PostInstall.txt +17 -0
  5. data/README.rdoc +149 -0
  6. data/Rakefile +28 -0
  7. data/bin/gonzui-db +167 -0
  8. data/bin/gonzui-import +177 -0
  9. data/bin/gonzui-remove +58 -0
  10. data/bin/gonzui-search +68 -0
  11. data/bin/gonzui-server +176 -0
  12. data/bin/gonzui-update +53 -0
  13. data/data/gonzui/catalog/catalog.ja +80 -0
  14. data/data/gonzui/doc/favicon.ico +0 -0
  15. data/data/gonzui/doc/folder.png +0 -0
  16. data/data/gonzui/doc/gonzui.css +279 -0
  17. data/data/gonzui/doc/gonzui.js +111 -0
  18. data/data/gonzui/doc/text.png +0 -0
  19. data/data/gonzuirc.sample +29 -0
  20. data/ext/autopack/autopack.c +88 -0
  21. data/ext/autopack/extconf.rb +3 -0
  22. data/ext/delta/delta.c +147 -0
  23. data/ext/delta/extconf.rb +5 -0
  24. data/ext/texttokenizer/extconf.rb +5 -0
  25. data/ext/texttokenizer/texttokenizer.c +93 -0
  26. data/ext/xmlformatter/extconf.rb +5 -0
  27. data/ext/xmlformatter/xmlformatter.c +207 -0
  28. data/lib/gonzui.rb +59 -0
  29. data/lib/gonzui/apt.rb +193 -0
  30. data/lib/gonzui/bdbdbm.rb +118 -0
  31. data/lib/gonzui/cmdapp.rb +14 -0
  32. data/lib/gonzui/cmdapp/app.rb +175 -0
  33. data/lib/gonzui/cmdapp/search.rb +134 -0
  34. data/lib/gonzui/config.rb +117 -0
  35. data/lib/gonzui/content.rb +19 -0
  36. data/lib/gonzui/dbm.rb +673 -0
  37. data/lib/gonzui/deindexer.rb +162 -0
  38. data/lib/gonzui/delta.rb +49 -0
  39. data/lib/gonzui/extractor.rb +347 -0
  40. data/lib/gonzui/fetcher.rb +309 -0
  41. data/lib/gonzui/gettext.rb +144 -0
  42. data/lib/gonzui/importer.rb +84 -0
  43. data/lib/gonzui/indexer.rb +316 -0
  44. data/lib/gonzui/info.rb +80 -0
  45. data/lib/gonzui/license.rb +100 -0
  46. data/lib/gonzui/logger.rb +48 -0
  47. data/lib/gonzui/monitor.rb +177 -0
  48. data/lib/gonzui/progressbar.rb +235 -0
  49. data/lib/gonzui/remover.rb +38 -0
  50. data/lib/gonzui/searcher.rb +330 -0
  51. data/lib/gonzui/searchquery.rb +235 -0
  52. data/lib/gonzui/searchresult.rb +111 -0
  53. data/lib/gonzui/updater.rb +254 -0
  54. data/lib/gonzui/util.rb +415 -0
  55. data/lib/gonzui/vcs.rb +128 -0
  56. data/lib/gonzui/webapp.rb +25 -0
  57. data/lib/gonzui/webapp/advsearch.rb +123 -0
  58. data/lib/gonzui/webapp/filehandler.rb +24 -0
  59. data/lib/gonzui/webapp/jsfeed.rb +61 -0
  60. data/lib/gonzui/webapp/markup.rb +445 -0
  61. data/lib/gonzui/webapp/search.rb +269 -0
  62. data/lib/gonzui/webapp/servlet.rb +319 -0
  63. data/lib/gonzui/webapp/snippet.rb +155 -0
  64. data/lib/gonzui/webapp/source.rb +37 -0
  65. data/lib/gonzui/webapp/stat.rb +137 -0
  66. data/lib/gonzui/webapp/top.rb +63 -0
  67. data/lib/gonzui/webapp/uri.rb +140 -0
  68. data/lib/gonzui/webapp/webrick.rb +48 -0
  69. data/script/console +10 -0
  70. data/script/destroy +14 -0
  71. data/script/generate +14 -0
  72. data/script/makemanifest.rb +21 -0
  73. data/tasks/extconf.rake +13 -0
  74. data/tasks/extconf/autopack.rake +43 -0
  75. data/tasks/extconf/delta.rake +43 -0
  76. data/tasks/extconf/texttokenizer.rake +43 -0
  77. data/tasks/extconf/xmlformatter.rake +43 -0
  78. data/test/_external_tools.rb +13 -0
  79. data/test/_test-util.rb +142 -0
  80. data/test/foo/Makefile.foo +66 -0
  81. data/test/foo/bar.c +5 -0
  82. data/test/foo/bar.h +6 -0
  83. data/test/foo/foo.c +25 -0
  84. data/test/foo/foo.spec +33 -0
  85. data/test/test_apt.rb +42 -0
  86. data/test/test_autopack_extn.rb +7 -0
  87. data/test/test_bdbdbm.rb +79 -0
  88. data/test/test_cmdapp-app.rb +35 -0
  89. data/test/test_cmdapp-search.rb +99 -0
  90. data/test/test_config.rb +28 -0
  91. data/test/test_content.rb +15 -0
  92. data/test/test_dbm.rb +171 -0
  93. data/test/test_deindexer.rb +50 -0
  94. data/test/test_delta.rb +66 -0
  95. data/test/test_extractor.rb +78 -0
  96. data/test/test_fetcher.rb +75 -0
  97. data/test/test_gettext.rb +50 -0
  98. data/test/test_gonzui.rb +11 -0
  99. data/test/test_helper.rb +10 -0
  100. data/test/test_importer.rb +56 -0
  101. data/test/test_indexer.rb +37 -0
  102. data/test/test_info.rb +82 -0
  103. data/test/test_license.rb +49 -0
  104. data/test/test_logger.rb +60 -0
  105. data/test/test_monitor.rb +23 -0
  106. data/test/test_searcher.rb +37 -0
  107. data/test/test_searchquery.rb +27 -0
  108. data/test/test_searchresult.rb +43 -0
  109. data/test/test_texttokenizer.rb +47 -0
  110. data/test/test_updater.rb +95 -0
  111. data/test/test_util.rb +149 -0
  112. data/test/test_vcs.rb +61 -0
  113. data/test/test_webapp-markup.rb +42 -0
  114. data/test/test_webapp-util.rb +19 -0
  115. data/test/test_webapp-xmlformatter.rb +19 -0
  116. metadata +291 -0
@@ -0,0 +1,128 @@
1
+ #
2
+ # vcs.rb - simple interface to version control systems
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
+ class VCSError < GonzuiError; end
14
+
15
+ class AbstractVCS
16
+ include Util
17
+
18
+ def initialize(config, root, mozule)
19
+ @config = config
20
+ @root = root
21
+ @mozule = mozule
22
+ end
23
+
24
+ private
25
+ def run_command(command_line, message)
26
+ printf("running %s...\n", message) unless @config.quiet
27
+ dn = "/dev/null"
28
+ dn = "nul" if (/mswin|mingw|bccwin/ =~ RUBY_PLATFORM)
29
+ command_line += ">#{dn} 2>&1" unless @config.verbose
30
+ status = system(command_line)
31
+ raise VCSError.new("command execution failed") if status == false
32
+ end
33
+
34
+ public
35
+ def extract
36
+ File.mkpath(@config.cache_directory)
37
+ output_directory = File.join(@config.cache_directory, @mozule)
38
+ if not File.exist?(output_directory)
39
+ do_checkout(output_directory)
40
+ elsif File.directory?(output_directory)
41
+ do_update(output_directory)
42
+ else
43
+ raise VCSError.new("#{output_directory}: obstacle found")
44
+ end
45
+ return output_directory
46
+ end
47
+
48
+ def clean
49
+ end
50
+ end
51
+
52
+ class CVS < AbstractVCS
53
+ def initialize(config, root, mozule)
54
+ require_command("cvs")
55
+ super(config, root, mozule)
56
+ end
57
+
58
+ def do_checkout(output_directory)
59
+ Dir.chdir(@config.cache_directory) {
60
+ command_line = sprintf("cvs -z3 -d %s co -P %s",
61
+ shell_escape(@root),
62
+ shell_escape(@mozule))
63
+ run_command(command_line, "cvs checkout")
64
+ }
65
+ end
66
+
67
+ def do_update(output_directory)
68
+ Dir.chdir(output_directory) {
69
+ run_command("cvs -z3 update -dP", "cvs update")
70
+ }
71
+ end
72
+
73
+ def do_extract
74
+ File.mkpath(@config.cache_directory)
75
+ output_directory = File.join(@config.cache_directory, @mozule)
76
+ if File.exist?(output_directory)
77
+ run_cvs_update(output_directory)
78
+ else
79
+ run_cvs_checkout
80
+ end
81
+ return output_directory
82
+ end
83
+ end
84
+
85
+ class Subversion < AbstractVCS
86
+ def initialize(config, root, mozule)
87
+ require_command("svn")
88
+ super(config, root, mozule)
89
+ end
90
+
91
+ def do_checkout(output_directory)
92
+ Dir.chdir(@config.cache_directory) {
93
+ command_line = sprintf("svn co %s %s",
94
+ shell_escape(@root),
95
+ shell_escape(@mozule))
96
+ run_command(command_line, "svn checkout")
97
+ }
98
+ end
99
+
100
+ def do_update(output_directory)
101
+ Dir.chdir(output_directory) {
102
+ run_command("svn update","svn update")
103
+ }
104
+ end
105
+ end
106
+
107
+ class Git < AbstractVCS
108
+ def initialize(config, root, mozule = nil)
109
+ require_command("git")
110
+ mozule = File.basename(URI.parse(root).path, ".git") unless mozule
111
+ super(config, root, mozule)
112
+ end
113
+
114
+ def do_checkout(output_directory)
115
+ Dir.chdir(@config.cache_directory) {
116
+ command_line = sprintf("git clone %s",
117
+ shell_escape(@root))
118
+ run_command(command_line, "git clone")
119
+ }
120
+ end
121
+
122
+ def do_update(output_directory)
123
+ Dir.chdir(output_directory) {
124
+ run_command("git pull","git pull")
125
+ }
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # webapp.rb - a library for web-based applications
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 'gonzui/webapp/xmlformatter'
13
+ require 'gonzui/webapp/webrick'
14
+ require 'gonzui/webapp/uri'
15
+ require 'gonzui/webapp/servlet'
16
+ require 'gonzui/webapp/snippet'
17
+
18
+ require 'gonzui/webapp/advsearch'
19
+ require 'gonzui/webapp/filehandler'
20
+ require 'gonzui/webapp/jsfeed'
21
+ require 'gonzui/webapp/markup'
22
+ require 'gonzui/webapp/search'
23
+ require 'gonzui/webapp/source'
24
+ require 'gonzui/webapp/stat'
25
+ require 'gonzui/webapp/top'
@@ -0,0 +1,123 @@
1
+ #
2
+ # advsearch.rb - advanced search servlet
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
+ class AdvancedSearchServlet < GonzuiAbstractServlet
14
+ def self.mount_point
15
+ "advsearch"
16
+ end
17
+
18
+ def do_make_status_line
19
+ []
20
+ end
21
+
22
+ def make_target_select
23
+ tt = get_short_name(:target_type)
24
+ select = [:select, {:name => tt}]
25
+ oall = [:option, {:type => "radio", :name => tt,
26
+ :value => ""}, _("All")]
27
+ select.push(oall)
28
+ LangScan::Type.each_group {|group|
29
+ og = [:optgroup, {:label => _(group.name)}]
30
+ added_p = false
31
+ group.each {|type_info|
32
+ if @dbm.has_type?(type_info.type)
33
+ o = [:option, {:type => "radio", :name => tt,
34
+ :value => type_info.type}, _(type_info.name)]
35
+ og.push(o)
36
+ added_p = true
37
+ end
38
+ }
39
+ select.push(og) if added_p
40
+ }
41
+ return select
42
+ end
43
+
44
+ def make_nresults_select
45
+ nr = get_short_name(:nresults_per_page)
46
+ select = [:select, {:name => nr}]
47
+ @config.nresults_candidates.each {|n|
48
+ o = [:option, {:type => "radio", :name => nr,
49
+ :value => n}, sprintf(_("%d results"), n)]
50
+ select.push(o)
51
+ }
52
+ return select
53
+ end
54
+
55
+ def make_target_specific_search_form
56
+ form = [:form, { :method => "get",
57
+ :action => make_uri_general(SearchServlet)}]
58
+
59
+ ikeyword = [:input, {:type => "text", :size => 30,
60
+ :name => get_short_name(:basic_query),
61
+ :value => @search_query.keywords.join(" ")}]
62
+ iphrase = [:input, {:type => "text", :size => 30,
63
+ :name => get_short_name(:phrase_query),
64
+ :value => (@search_query.phrases.first or []).join(" ")}]
65
+
66
+ nresults_select = make_nresults_select
67
+
68
+ isubmit = [:input, {:type => "submit", :value => _("Search")}]
69
+
70
+ table = [:table]
71
+ table.push([:tr, [:td, {:width => "20%"}, _("Keyword")],
72
+ [:td, {:width => "30%"}, ikeyword],
73
+ [:td, {:width => "15%"}, nresults_select],
74
+ [:td, {:width => "15%"}, isubmit]])
75
+ table.push([:tr, [:td, {:width => "20%"}, _("Phrase")],
76
+ [:td, {:width => "30%"}, iphrase]])
77
+
78
+ table.push([:tr])
79
+
80
+ target_select = make_target_select
81
+ table.push([:tr, [:td, _("Target")],
82
+ [:td, target_select], [:td]])
83
+
84
+ format_select = make_format_select
85
+ table.push([:tr, [:td, _("Format")], [:td, format_select], [:td]])
86
+
87
+ license_select = make_license_select
88
+ table.push([:tr, [:td, _("License")], [:td, license_select], [:td]])
89
+
90
+ form.push(table)
91
+ return form
92
+ end
93
+
94
+ def make_advanced_search_form
95
+ form = make_target_specific_search_form
96
+ return [:div, {:class =>"advanced-search"}, form]
97
+ end
98
+
99
+ def do_GET(request, response)
100
+ init_servlet(request, response)
101
+ log()
102
+
103
+ html = make_html
104
+ title = make_title(_("Advanced Search"))
105
+ head = [:head, title, *make_meta_and_css]
106
+ body = [:body]
107
+
108
+ h1 = make_h1
109
+ status_line = make_status_line(_("Advanced Search"))
110
+ content = make_advanced_search_form
111
+ footer = make_footer
112
+ body.push(h1, status_line, content, footer)
113
+
114
+ html.push(head)
115
+ html.push(body)
116
+ set_content_type_text_html
117
+ response.body = format_html(html)
118
+ end
119
+
120
+ GonzuiServlet.register(self)
121
+ end
122
+ end
123
+
@@ -0,0 +1,24 @@
1
+ #
2
+ # filehandler.rb - file handler servlet
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
+ class FileHandler < WEBrick::HTTPServlet::FileHandler
14
+ def self.mount_point
15
+ "doc"
16
+ end
17
+
18
+ def initialize(server, config, logger, dbm, catalogs)
19
+ super(server, config.doc_directory)
20
+ end
21
+
22
+ GonzuiServlet.register(self)
23
+ end
24
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # jsfeed - javascript-feed servlet
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
+ class JSFeedServlet < GonzuiAbstractServlet
14
+ def self.mount_point
15
+ "jsfeed"
16
+ end
17
+
18
+ def do_GET(request, response)
19
+ init_servlet(request, response)
20
+ path = make_path
21
+ log(path)
22
+
23
+ from = to = nil
24
+ if m = /^(\d+)-(\d+)$/.match(request.query_string)
25
+ from = m[1].to_i
26
+ to = m[2].to_i
27
+ end
28
+
29
+ if from and to
30
+ path_id = @dbm.get_path_id(path)
31
+ if path_id
32
+ content = @dbm.get_content(path_id)
33
+ lineno = 0
34
+ lines = []
35
+ range = Range.new(from, to)
36
+ content.each_line {|line|
37
+ lineno += 1
38
+ if range.include?(lineno)
39
+ line_with_lineno = sprintf("%5d: %s", lineno, line)
40
+ line_with_lineno.chop!
41
+ lines.push(HTMLUtils.escape(line_with_lineno))
42
+ end
43
+ }
44
+ snippet = lines.join("<br />")
45
+ response.body = sprintf("document.writeln('<pre>%s</pre>');",
46
+ snippet)
47
+ response['Content-Type'] = "application/x-javascript"
48
+ else
49
+ response.body = sprintf("%s: not found", path)
50
+ response.status = 404
51
+ response['Content-Type'] = "text/html"
52
+ end
53
+ else
54
+ response.body = "invalid query"
55
+ response['Content-Type'] = "text/html"
56
+ end
57
+ end
58
+
59
+ GonzuiServlet.register(self)
60
+ end
61
+ end
@@ -0,0 +1,445 @@
1
+ #
2
+ # markup.rb - markup servlet
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 'stringio'
13
+ require 'zlib'
14
+ require 'strscan'
15
+
16
+ module Gonzui
17
+ class TextBeautifier
18
+ def initialize(content, digest, occurrences, search_uri)
19
+ @content = content
20
+ @digest = digest # to be destroyed
21
+ @occurrences = occurrences # to be destroyed
22
+ @search_uri = search_uri
23
+
24
+ @break_points = [0, @content.length]
25
+ @lines = {}
26
+ pos = lineno = 0
27
+ @content.each_line {|line|
28
+ lineno += 1
29
+ @break_points.push(pos)
30
+ @lines[pos] = [lineno, line]
31
+ pos += line.length
32
+ }
33
+ @digest.each {|info|
34
+ @break_points.push(info.byteno)
35
+ @break_points.push(info.end_byteno)
36
+ }
37
+ @occurrences.each {|occ|
38
+ @break_points.push(occ.byteno)
39
+ @break_points.push(occ.end_byteno)
40
+ }
41
+ @break_points.uniq!
42
+ @break_points.sort!
43
+
44
+ @info = @digest.shift
45
+ @occ = @occurrences.shift
46
+ @seen_ids = {}
47
+ @latest_id = "0"
48
+ end
49
+
50
+ def make_line_mark(lineno)
51
+ anchor = "l" + lineno.to_s
52
+ [:span, {:class => "lineno", :onclick => "olnc(this);"},
53
+ [:a, {:id => anchor, :name => anchor, :href => "#" + anchor},
54
+ sprintf("%5d: ", lineno)]]
55
+ end
56
+
57
+ def choose_target_type
58
+ case @info.type
59
+ when :fundef
60
+ :funcall
61
+ when :funcall
62
+ :fundef
63
+ when :fundecl
64
+ :fundef
65
+ else
66
+ assert_not_reached
67
+ end
68
+ end
69
+
70
+ def decorate(text)
71
+ unless @seen_ids.include?(text)
72
+ @seen_ids[text] = @latest_id
73
+ @latest_id = @latest_id.next
74
+ end
75
+ id = @seen_ids[text]
76
+ inner = [:span, {:class => id, :onmouseover => "hl('#{id}');"}, text]
77
+ part = [:span, {:class => @info.type.to_s}, inner]
78
+
79
+ if LangScan::Type.function?(@info.type)
80
+ tt = choose_target_type
81
+ query_string = sprintf("%s:%s", tt, HTTPUtils.escape_form(text))
82
+ uri = @search_uri + query_string
83
+ part = [:a, {:href => uri}, part]
84
+ end
85
+ return part
86
+ end
87
+
88
+ def markup_part(bp, ep)
89
+ part = @content[bp...ep]
90
+ if @info and (bp == @info.byteno or @info.range.include?(bp))
91
+ part = decorate(part)
92
+ @info = @digest.shift if @info.end_byteno <= ep
93
+ end
94
+ if @occ and (bp == @occ.byteno or @occ.range.include?(bp))
95
+ part = [:strong, {:class => "highlight"}, part]
96
+ @occ = @occurrences.shift if @occ.end_byteno <= ep
97
+ end
98
+ return part
99
+ end
100
+
101
+ def make_lineno_part(bp)
102
+ lineno, line = @lines[bp]
103
+ [:span, {:class => "line", :title => line}, make_line_mark(lineno)]
104
+ end
105
+
106
+ def beautify
107
+ code = []
108
+ bp = @break_points.shift
109
+ line = nil
110
+ while not @break_points.empty?
111
+ ep = @break_points.shift
112
+ if @lines.include?(bp)
113
+ code.push(line) if line
114
+ line = make_lineno_part(bp)
115
+ end
116
+ part = markup_part(bp, ep)
117
+ line.push(part)
118
+ bp = ep
119
+ end
120
+ code.push(line) if line
121
+ return code
122
+ end
123
+ end
124
+
125
+ class MarkupServlet < GonzuiAbstractServlet
126
+ def self.mount_point
127
+ "markup"
128
+ end
129
+
130
+ def make_breadcrumbs(path)
131
+ parts = path.split("/")
132
+ breadcrumbs = (1 .. parts.length).map {|i|
133
+ [ parts[i - 1], parts[0, i]]
134
+ }.map {|part, parts|
135
+ path = parts.join("/")
136
+ uri = make_markup_uri(parts.join("/"), @search_query)
137
+ [:a, {:href => uri}, part]
138
+ }
139
+ (breadcrumbs.length - 1).times {|i|
140
+ breadcrumbs.insert(i * 2 + 1, "/")
141
+ }
142
+ return [:span, *breadcrumbs]
143
+ end
144
+
145
+ def do_make_status_line(method)
146
+ items = []
147
+
148
+ case method
149
+ when :markup_file
150
+ if @path_id
151
+ bare = [:a, {:href => make_source_uri(@path)},
152
+ _("bare source")]
153
+ permlink = [:a, {:href => make_markup_uri(@path)},
154
+ _("permlink")]
155
+ items.push(bare)
156
+ items.push(permlink)
157
+ end
158
+ when :list_files
159
+ if @total
160
+ items.push([:span, [:strong, @total], _(" contents.")])
161
+ end
162
+ when :list_packages
163
+ if @to and @total
164
+ packages = [:span, _("Packages "),
165
+ [:strong, commify(@from + 1)], " - ",
166
+ [:strong, commify(@to)], _(" of "),
167
+ [:strong, commify(@total)], _(".")]
168
+ items.push(packages)
169
+ end
170
+ end
171
+ return items
172
+ end
173
+
174
+ def calc_ncolumns(items)
175
+ sum = items.inject(0) {|a, b|
176
+ name = b.first
177
+ a + name.length
178
+ }
179
+ average = sum / items.length
180
+ ncolumns = [40 / average, items.length].min
181
+ ncolumns = 1 if ncolumns == 0
182
+ return ncolumns
183
+ end
184
+
185
+ def make_table(items)
186
+ table = [:table, {:class => "fullwidth"}]
187
+ return table if items.empty?
188
+ ncolumns = calc_ncolumns(items)
189
+ width = sprintf("%d%%", 100/ncolumns)
190
+
191
+ nrows = (items.length - 1) / ncolumns + 1
192
+ nrows.times {|i|
193
+ k = if (i + 1) % 2 == 0 then "even" else "odd" end
194
+ row = [:tr, {:class => k}]
195
+ ncolumns.times {|j|
196
+ # item = items[j * nrows + i] # for vertical arrange
197
+ item = items[i * ncolumns + j]
198
+ value = if item
199
+ name, klass, image, uri, title = item
200
+ tr = [:tr]
201
+ if image
202
+ img = [:img, {:src => image, :alt => ""}]
203
+ tr << [:td, [:a, {:href => uri}, img]]
204
+ end
205
+ a = [:a, {:class => klass, :href =>uri,:title =>title}, name]
206
+ tr << [:td, a]
207
+ [:table, {:class => "item"}, tr]
208
+ else
209
+ make_spacer
210
+ end
211
+ k = if j == 0 then "first" else "nonfirst" end
212
+ td = [:td, {:width => width, :class => k}, value]
213
+ row.push(td)
214
+ }
215
+ table.push(row)
216
+ }
217
+ return table
218
+ end
219
+
220
+ def make_title_for_path(path, file_p)
221
+ title = if file_p
222
+ path_id = @dbm.get_path_id(path)
223
+ info = @dbm.get_content_info(path_id)
224
+ sprintf(_("Size: %s (%s lines)"),
225
+ format_bytes(info.size),
226
+ commify(info.nlines))
227
+ else
228
+ ""
229
+ end
230
+ return title
231
+ end
232
+
233
+ def make_table_of_files(paths)
234
+ items = paths.map {|path, file_p|
235
+ basename = File.basename(path)
236
+ klass = if file_p then "file" else "directory" end
237
+ image = if file_p
238
+ make_doc_uri("text.png")
239
+ else
240
+ make_doc_uri("folder.png")
241
+ end
242
+ uri = make_markup_uri(path, @search_query)
243
+ title = make_title_for_path(path, file_p)
244
+ [basename, klass, image, uri, title]
245
+ }
246
+ return make_table(items)
247
+ end
248
+
249
+ def make_table_of_packages(package_names)
250
+ items = package_names.map {|package_name|
251
+ package_id = @dbm.get_package_id(package_name)
252
+ uri = make_markup_uri(package_name)
253
+ title = ""
254
+ [package_name, "directory", nil, uri, title]
255
+ }
256
+ return make_table(items)
257
+ end
258
+
259
+ def list_files
260
+ path_parts = @path.split("/")
261
+ depth = path_parts.length
262
+
263
+ package_id = @dbm.get_package_id(@package_name)
264
+ path_ids = @dbm.get_path_ids(package_id)
265
+ paths = path_ids.map {|path_id|
266
+ @dbm.get_path(path_id)
267
+ }.map {|path|
268
+ path.split("/")
269
+ }.find_all {|parts|
270
+ parts.length > depth and parts[0, depth] == path_parts
271
+ }.map {|parts|
272
+ file_p = parts.length == depth + 1
273
+ [parts[0, depth + 1].join("/"), file_p]
274
+ }.uniq
275
+ if paths.empty?
276
+ return ""
277
+ else
278
+ @total = paths.length
279
+ return make_table_of_files(paths)
280
+ end
281
+ end
282
+
283
+ def do_make_navi(from)
284
+ make_markup_uri("", nil, :from => from)
285
+ end
286
+
287
+ def list_packages
288
+ # FIXME: sorting every time is not efficient.
289
+ all = []
290
+ @dbm.each_package_name {|package_name|
291
+ all.push(package_name)
292
+ }
293
+ all.sort!
294
+
295
+ package_names = all[@from, @config.max_packages_per_page]
296
+ if package_names
297
+ @to = @from + package_names.length
298
+ @total = all.length
299
+ table = make_table_of_packages(package_names)
300
+ navi = make_navi(all.length, @from, @config.max_packages_per_page)
301
+ return [:div, table, navi]
302
+ else
303
+ return ""
304
+ end
305
+ end
306
+
307
+ def markup_source
308
+ content = @dbm.get_content(@path_id)
309
+ digest = @dbm.get_digest(@path_id)
310
+ occurrences = if @search_query.string.empty?
311
+ []
312
+ else
313
+ search_query = @search_query.clone
314
+ search_query.path ||= @path
315
+ searcher = Searcher.new(@dbm, search_query,
316
+ @config.max_results_overall)
317
+ result = searcher.search
318
+ item = result.first
319
+ if item and not item.list.empty?
320
+ item.list
321
+ else
322
+ []
323
+ end
324
+ end
325
+ search_uri = make_search_uri_partial("")
326
+ beautifier = TextBeautifier.new(content, digest, occurrences, search_uri)
327
+ return beautifier.beautify
328
+ end
329
+
330
+ def make_isearch_form
331
+ isearch = [:div, {:class => "isearch"}]
332
+ form = [:form, {:method => "get", :action => "",
333
+ :onsubmit => "return false;"}]
334
+ p = [:p]
335
+ p.push(_("Search this content: "))
336
+ p.push([:input, {:type => "text", :name => "g", :size => "20",
337
+ :onkeyup => "isearch(this.value);",
338
+ :value => ""
339
+ }])
340
+ p.push(" ")
341
+ form.push(p)
342
+ isearch.push(form)
343
+ return isearch
344
+ end
345
+
346
+ def markup_file
347
+ path = @dbm.get_path(@path_id)
348
+
349
+ mime_type = get_mime_type(path)
350
+ media_type = get_media_type(path)
351
+ if media_type == "image"
352
+ img = [:img, {:src => make_source_uri(path),
353
+ :alt => path }]
354
+ content = [:div, {:class => "image"}, img]
355
+ elsif mime_type == "text/html"
356
+ iframe = [:iframe, {:src => make_source_uri(path),
357
+ :width => "100%", :height => "400"},
358
+ [:a, {:href => make_source_uri(path)}, path]
359
+ ]
360
+ content = iframe
361
+ else
362
+ content = [:div]
363
+ isearch = make_isearch_form
364
+ content.push(isearch)
365
+ code = markup_source
366
+ content.push([:pre, *code])
367
+ end
368
+ return content
369
+ end
370
+
371
+ def make_not_found
372
+ sprintf(_("No contents were found matching %s"),
373
+ @path)
374
+ end
375
+
376
+ def gzip(string)
377
+ strio = StringIO.new
378
+ writer = Zlib::GzipWriter.new(strio)
379
+ writer.print(string)
380
+ writer.finish
381
+ return strio.string
382
+ end
383
+
384
+ def set_response(html)
385
+ set_content_type_text_html
386
+ body = format_html(html)
387
+ if @request.gzip_encoding_supported?
388
+ @response["Content-Encoding"] = "gzip"
389
+ @response.body = gzip(body)
390
+ else
391
+ @response.body = body
392
+ end
393
+ end
394
+
395
+ def choose_method
396
+ method = :make_not_found
397
+ if @path.empty?
398
+ method = :list_packages
399
+ title = make_title(_("List of Packages"))
400
+ status_title = _("List of Packages")
401
+ else
402
+ @path_id = @dbm.get_path_id(@path)
403
+ @package_name = @path.split("/").first
404
+ if @path_id
405
+ method = :markup_file
406
+ elsif @dbm.has_package?(@package_name)
407
+ method = :list_files
408
+ end
409
+ title = make_title(@path)
410
+ status_title = make_breadcrumbs(@path)
411
+ end
412
+ return method, title, status_title
413
+ end
414
+
415
+ def do_GET(request, response)
416
+ init_servlet(request, response)
417
+ log(@path)
418
+
419
+ @path = make_path
420
+ @to = nil
421
+ @total = nil
422
+
423
+ method, title, status_title = choose_method
424
+
425
+ html = make_html
426
+ head = [:head, title, make_script, *make_meta_and_css]
427
+ body = [:body, {:onload => "initCache();",
428
+ :onclick => "clearHighlight();" }]
429
+ body.push(make_h1)
430
+ body.push(make_search_form)
431
+ content = self.send(method)
432
+
433
+ status_line = make_status_line(status_title, method)
434
+ body.push(status_line)
435
+ body.push(content)
436
+ body.push(make_footer)
437
+
438
+ html.push(head)
439
+ html.push(body)
440
+ set_response(html)
441
+ end
442
+
443
+ GonzuiServlet.register(self)
444
+ end
445
+ end