libgems 0.0.1
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/ChangeLog +5811 -0
- data/History.txt +887 -0
- data/LICENSE.txt +51 -0
- data/README.md +87 -0
- data/Rakefile +113 -0
- data/lib/gauntlet_libgems.rb +50 -0
- data/lib/libgems.rb +1246 -0
- data/lib/libgems/builder.rb +102 -0
- data/lib/libgems/command.rb +534 -0
- data/lib/libgems/command_manager.rb +182 -0
- data/lib/libgems/commands/build_command.rb +53 -0
- data/lib/libgems/commands/cert_command.rb +86 -0
- data/lib/libgems/commands/check_command.rb +80 -0
- data/lib/libgems/commands/cleanup_command.rb +106 -0
- data/lib/libgems/commands/contents_command.rb +98 -0
- data/lib/libgems/commands/dependency_command.rb +195 -0
- data/lib/libgems/commands/environment_command.rb +133 -0
- data/lib/libgems/commands/fetch_command.rb +67 -0
- data/lib/libgems/commands/generate_index_command.rb +133 -0
- data/lib/libgems/commands/help_command.rb +172 -0
- data/lib/libgems/commands/install_command.rb +178 -0
- data/lib/libgems/commands/list_command.rb +35 -0
- data/lib/libgems/commands/lock_command.rb +110 -0
- data/lib/libgems/commands/mirror_command.rb +111 -0
- data/lib/libgems/commands/outdated_command.rb +33 -0
- data/lib/libgems/commands/owner_command.rb +75 -0
- data/lib/libgems/commands/pristine_command.rb +93 -0
- data/lib/libgems/commands/push_command.rb +56 -0
- data/lib/libgems/commands/query_command.rb +280 -0
- data/lib/libgems/commands/rdoc_command.rb +91 -0
- data/lib/libgems/commands/search_command.rb +31 -0
- data/lib/libgems/commands/server_command.rb +86 -0
- data/lib/libgems/commands/sources_command.rb +157 -0
- data/lib/libgems/commands/specification_command.rb +125 -0
- data/lib/libgems/commands/stale_command.rb +27 -0
- data/lib/libgems/commands/uninstall_command.rb +83 -0
- data/lib/libgems/commands/unpack_command.rb +121 -0
- data/lib/libgems/commands/update_command.rb +160 -0
- data/lib/libgems/commands/which_command.rb +86 -0
- data/lib/libgems/config_file.rb +345 -0
- data/lib/libgems/custom_require.rb +44 -0
- data/lib/libgems/defaults.rb +101 -0
- data/lib/libgems/dependency.rb +227 -0
- data/lib/libgems/dependency_installer.rb +286 -0
- data/lib/libgems/dependency_list.rb +208 -0
- data/lib/libgems/doc_manager.rb +242 -0
- data/lib/libgems/errors.rb +35 -0
- data/lib/libgems/exceptions.rb +91 -0
- data/lib/libgems/ext.rb +18 -0
- data/lib/libgems/ext/builder.rb +56 -0
- data/lib/libgems/ext/configure_builder.rb +25 -0
- data/lib/libgems/ext/ext_conf_builder.rb +24 -0
- data/lib/libgems/ext/rake_builder.rb +39 -0
- data/lib/libgems/format.rb +81 -0
- data/lib/libgems/gem_openssl.rb +92 -0
- data/lib/libgems/gem_path_searcher.rb +100 -0
- data/lib/libgems/gem_runner.rb +79 -0
- data/lib/libgems/gemcutter_utilities.rb +49 -0
- data/lib/libgems/indexer.rb +720 -0
- data/lib/libgems/install_update_options.rb +125 -0
- data/lib/libgems/installer.rb +604 -0
- data/lib/libgems/local_remote_options.rb +135 -0
- data/lib/libgems/old_format.rb +153 -0
- data/lib/libgems/package.rb +97 -0
- data/lib/libgems/package/f_sync_dir.rb +23 -0
- data/lib/libgems/package/tar_header.rb +266 -0
- data/lib/libgems/package/tar_input.rb +222 -0
- data/lib/libgems/package/tar_output.rb +144 -0
- data/lib/libgems/package/tar_reader.rb +106 -0
- data/lib/libgems/package/tar_reader/entry.rb +141 -0
- data/lib/libgems/package/tar_writer.rb +241 -0
- data/lib/libgems/package_task.rb +126 -0
- data/lib/libgems/platform.rb +183 -0
- data/lib/libgems/remote_fetcher.rb +414 -0
- data/lib/libgems/require_paths_builder.rb +18 -0
- data/lib/libgems/requirement.rb +153 -0
- data/lib/libgems/security.rb +814 -0
- data/lib/libgems/server.rb +872 -0
- data/lib/libgems/source_index.rb +597 -0
- data/lib/libgems/source_info_cache.rb +395 -0
- data/lib/libgems/source_info_cache_entry.rb +56 -0
- data/lib/libgems/spec_fetcher.rb +337 -0
- data/lib/libgems/specification.rb +1487 -0
- data/lib/libgems/test_utilities.rb +147 -0
- data/lib/libgems/text.rb +65 -0
- data/lib/libgems/uninstaller.rb +278 -0
- data/lib/libgems/user_interaction.rb +527 -0
- data/lib/libgems/validator.rb +240 -0
- data/lib/libgems/version.rb +316 -0
- data/lib/libgems/version_option.rb +65 -0
- data/lib/rbconfig/datadir.rb +20 -0
- data/test/bogussources.rb +8 -0
- data/test/data/gem-private_key.pem +27 -0
- data/test/data/gem-public_cert.pem +20 -0
- data/test/fake_certlib/openssl.rb +7 -0
- data/test/foo/discover.rb +0 -0
- data/test/gem_installer_test_case.rb +97 -0
- data/test/gem_package_tar_test_case.rb +132 -0
- data/test/gemutilities.rb +605 -0
- data/test/insure_session.rb +43 -0
- data/test/mockgemui.rb +56 -0
- data/test/plugin/exception/libgems_plugin.rb +2 -0
- data/test/plugin/load/libgems_plugin.rb +1 -0
- data/test/plugin/standarderror/libgems_plugin.rb +2 -0
- data/test/private_key.pem +27 -0
- data/test/public_cert.pem +20 -0
- data/test/rubygems_plugin.rb +21 -0
- data/test/simple_gem.rb +66 -0
- data/test/test_config.rb +12 -0
- data/test/test_gem.rb +780 -0
- data/test/test_gem_builder.rb +27 -0
- data/test/test_gem_command.rb +178 -0
- data/test/test_gem_command_manager.rb +207 -0
- data/test/test_gem_commands_build_command.rb +74 -0
- data/test/test_gem_commands_cert_command.rb +124 -0
- data/test/test_gem_commands_check_command.rb +18 -0
- data/test/test_gem_commands_contents_command.rb +156 -0
- data/test/test_gem_commands_dependency_command.rb +216 -0
- data/test/test_gem_commands_environment_command.rb +144 -0
- data/test/test_gem_commands_fetch_command.rb +76 -0
- data/test/test_gem_commands_generate_index_command.rb +135 -0
- data/test/test_gem_commands_install_command.rb +315 -0
- data/test/test_gem_commands_list_command.rb +36 -0
- data/test/test_gem_commands_lock_command.rb +68 -0
- data/test/test_gem_commands_mirror_command.rb +60 -0
- data/test/test_gem_commands_outdated_command.rb +40 -0
- data/test/test_gem_commands_owner_command.rb +105 -0
- data/test/test_gem_commands_pristine_command.rb +108 -0
- data/test/test_gem_commands_push_command.rb +81 -0
- data/test/test_gem_commands_query_command.rb +426 -0
- data/test/test_gem_commands_server_command.rb +59 -0
- data/test/test_gem_commands_sources_command.rb +209 -0
- data/test/test_gem_commands_specification_command.rb +139 -0
- data/test/test_gem_commands_stale_command.rb +38 -0
- data/test/test_gem_commands_uninstall_command.rb +83 -0
- data/test/test_gem_commands_unpack_command.rb +199 -0
- data/test/test_gem_commands_update_command.rb +207 -0
- data/test/test_gem_commands_which_command.rb +66 -0
- data/test/test_gem_config_file.rb +287 -0
- data/test/test_gem_dependency.rb +149 -0
- data/test/test_gem_dependency_installer.rb +661 -0
- data/test/test_gem_dependency_list.rb +230 -0
- data/test/test_gem_doc_manager.rb +31 -0
- data/test/test_gem_ext_configure_builder.rb +84 -0
- data/test/test_gem_ext_ext_conf_builder.rb +173 -0
- data/test/test_gem_ext_rake_builder.rb +81 -0
- data/test/test_gem_format.rb +70 -0
- data/test/test_gem_gem_path_searcher.rb +78 -0
- data/test/test_gem_gem_runner.rb +45 -0
- data/test/test_gem_gemcutter_utilities.rb +103 -0
- data/test/test_gem_indexer.rb +673 -0
- data/test/test_gem_install_update_options.rb +68 -0
- data/test/test_gem_installer.rb +857 -0
- data/test/test_gem_local_remote_options.rb +97 -0
- data/test/test_gem_package_tar_header.rb +130 -0
- data/test/test_gem_package_tar_input.rb +112 -0
- data/test/test_gem_package_tar_output.rb +97 -0
- data/test/test_gem_package_tar_reader.rb +46 -0
- data/test/test_gem_package_tar_reader_entry.rb +109 -0
- data/test/test_gem_package_tar_writer.rb +144 -0
- data/test/test_gem_package_task.rb +59 -0
- data/test/test_gem_platform.rb +264 -0
- data/test/test_gem_remote_fetcher.rb +740 -0
- data/test/test_gem_requirement.rb +292 -0
- data/test/test_gem_server.rb +356 -0
- data/test/test_gem_silent_ui.rb +113 -0
- data/test/test_gem_source_index.rb +461 -0
- data/test/test_gem_spec_fetcher.rb +410 -0
- data/test/test_gem_specification.rb +1334 -0
- data/test/test_gem_stream_ui.rb +218 -0
- data/test/test_gem_text.rb +43 -0
- data/test/test_gem_uninstaller.rb +146 -0
- data/test/test_gem_validator.rb +63 -0
- data/test/test_gem_version.rb +181 -0
- data/test/test_gem_version_option.rb +89 -0
- data/test/test_kernel.rb +59 -0
- metadata +402 -0
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
require 'webrick'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'zlib'
|
|
4
|
+
require 'erb'
|
|
5
|
+
|
|
6
|
+
require 'libgems'
|
|
7
|
+
require 'libgems/doc_manager'
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# LibGems::Server and allows users to serve gems for consumption by
|
|
11
|
+
# `gem --remote-install`.
|
|
12
|
+
#
|
|
13
|
+
# gem_server starts an HTTP server on the given port and serves the following:
|
|
14
|
+
# * "/" - Browsing of gem spec files for installed gems
|
|
15
|
+
# * "/specs.#{LibGems.marshal_version}.gz" - specs name/version/platform index
|
|
16
|
+
# * "/latest_specs.#{LibGems.marshal_version}.gz" - latest specs
|
|
17
|
+
# name/version/platform index
|
|
18
|
+
# * "/quick/" - Individual gemspecs
|
|
19
|
+
# * "/gems" - Direct access to download the installable gems
|
|
20
|
+
# * "/rdoc?q=" - Search for installed rdoc documentation
|
|
21
|
+
# * legacy indexes:
|
|
22
|
+
# * "/Marshal.#{LibGems.marshal_version}" - Full SourceIndex dump of metadata
|
|
23
|
+
# for installed gems
|
|
24
|
+
# * "/yaml" - YAML dump of metadata for installed gems - deprecated
|
|
25
|
+
#
|
|
26
|
+
# == Usage
|
|
27
|
+
#
|
|
28
|
+
# gem_server = LibGems::Server.new LibGems.dir, 8089, false
|
|
29
|
+
# gem_server.run
|
|
30
|
+
#
|
|
31
|
+
#--
|
|
32
|
+
# TODO Refactor into a real WEBrick servlet to remove code duplication.
|
|
33
|
+
|
|
34
|
+
class LibGems::Server
|
|
35
|
+
|
|
36
|
+
attr_reader :spec_dirs
|
|
37
|
+
|
|
38
|
+
include ERB::Util
|
|
39
|
+
include LibGems::UserInteraction
|
|
40
|
+
|
|
41
|
+
SEARCH = <<-SEARCH
|
|
42
|
+
<form class="headerSearch" name="headerSearchForm" method="get" action="/rdoc">
|
|
43
|
+
<div id="search" style="float:right">
|
|
44
|
+
<label for="q">Filter/Search</label>
|
|
45
|
+
<input id="q" type="text" style="width:10em" name="q">
|
|
46
|
+
<button type="submit" style="display:none"></button>
|
|
47
|
+
</div>
|
|
48
|
+
</form>
|
|
49
|
+
SEARCH
|
|
50
|
+
|
|
51
|
+
DOC_TEMPLATE = <<-'DOC_TEMPLATE'
|
|
52
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
53
|
+
<!DOCTYPE html
|
|
54
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
55
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
56
|
+
|
|
57
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
58
|
+
<head>
|
|
59
|
+
<title>#{LibGems::NAME} Documentation Index</title>
|
|
60
|
+
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
61
|
+
</head>
|
|
62
|
+
<body>
|
|
63
|
+
<div id="fileHeader">
|
|
64
|
+
<%= SEARCH %>
|
|
65
|
+
<h1>#{LibGems::NAME} Documentation Index</h1>
|
|
66
|
+
</div>
|
|
67
|
+
<!-- banner header -->
|
|
68
|
+
|
|
69
|
+
<div id="bodyContent">
|
|
70
|
+
<div id="contextContent">
|
|
71
|
+
<div id="description">
|
|
72
|
+
<h1>Summary</h1>
|
|
73
|
+
<p>There are <%=values["gem_count"]%> gems installed:</p>
|
|
74
|
+
<p>
|
|
75
|
+
<%= values["specs"].map { |v| "<a href=\"##{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
|
|
76
|
+
<h1>Gems</h1>
|
|
77
|
+
|
|
78
|
+
<dl>
|
|
79
|
+
<% values["specs"].each do |spec| %>
|
|
80
|
+
<dt>
|
|
81
|
+
<% if spec["first_name_entry"] then %>
|
|
82
|
+
<a name="<%=spec["name"]%>"></a>
|
|
83
|
+
<% end %>
|
|
84
|
+
|
|
85
|
+
<b><%=spec["name"]%> <%=spec["version"]%></b>
|
|
86
|
+
|
|
87
|
+
<% if spec["rdoc_installed"] then %>
|
|
88
|
+
<a href="<%=spec["doc_path"]%>">[rdoc]</a>
|
|
89
|
+
<% else %>
|
|
90
|
+
<span title="rdoc not installed">[rdoc]</span>
|
|
91
|
+
<% end %>
|
|
92
|
+
|
|
93
|
+
<% if spec["homepage"] then %>
|
|
94
|
+
<a href="<%=spec["homepage"]%>" title="<%=spec["homepage"]%>">[www]</a>
|
|
95
|
+
<% else %>
|
|
96
|
+
<span title="no homepage available">[www]</span>
|
|
97
|
+
<% end %>
|
|
98
|
+
|
|
99
|
+
<% if spec["has_deps"] then %>
|
|
100
|
+
- depends on
|
|
101
|
+
<%= spec["dependencies"].map { |v| "<a href=\"##{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
|
|
102
|
+
<% end %>
|
|
103
|
+
</dt>
|
|
104
|
+
<dd>
|
|
105
|
+
<%=spec["summary"]%>
|
|
106
|
+
<% if spec["executables"] then %>
|
|
107
|
+
<br/>
|
|
108
|
+
|
|
109
|
+
<% if spec["only_one_executable"] then %>
|
|
110
|
+
Executable is
|
|
111
|
+
<% else %>
|
|
112
|
+
Executables are
|
|
113
|
+
<%end%>
|
|
114
|
+
|
|
115
|
+
<%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{v["executable"]}</span>"}.join ', ' %>.
|
|
116
|
+
|
|
117
|
+
<%end%>
|
|
118
|
+
<br/>
|
|
119
|
+
<br/>
|
|
120
|
+
</dd>
|
|
121
|
+
<% end %>
|
|
122
|
+
</dl>
|
|
123
|
+
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div id="validator-badges">
|
|
128
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
129
|
+
</div>
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|
|
132
|
+
DOC_TEMPLATE
|
|
133
|
+
|
|
134
|
+
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
|
|
135
|
+
RDOC_CSS = <<-RDOC_CSS
|
|
136
|
+
body {
|
|
137
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
|
138
|
+
font-size: 90%;
|
|
139
|
+
margin: 0;
|
|
140
|
+
margin-left: 40px;
|
|
141
|
+
padding: 0;
|
|
142
|
+
background: white;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
|
146
|
+
h1 { font-size: 150%; }
|
|
147
|
+
h2,h3,h4 { margin-top: 1em; }
|
|
148
|
+
|
|
149
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
|
150
|
+
a:hover { background: #039; color: #eef; }
|
|
151
|
+
|
|
152
|
+
/* Override the base stylesheets Anchor inside a table cell */
|
|
153
|
+
td > a {
|
|
154
|
+
background: transparent;
|
|
155
|
+
color: #039;
|
|
156
|
+
text-decoration: none;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* and inside a section title */
|
|
160
|
+
.section-title > a {
|
|
161
|
+
background: transparent;
|
|
162
|
+
color: #eee;
|
|
163
|
+
text-decoration: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* === Structural elements =================================== */
|
|
167
|
+
|
|
168
|
+
div#index {
|
|
169
|
+
margin: 0;
|
|
170
|
+
margin-left: -40px;
|
|
171
|
+
padding: 0;
|
|
172
|
+
font-size: 90%;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
div#index a {
|
|
177
|
+
margin-left: 0.7em;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
div#index .section-bar {
|
|
181
|
+
margin-left: 0px;
|
|
182
|
+
padding-left: 0.7em;
|
|
183
|
+
background: #ccc;
|
|
184
|
+
font-size: small;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
div#classHeader, div#fileHeader {
|
|
189
|
+
width: auto;
|
|
190
|
+
color: white;
|
|
191
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
|
192
|
+
margin: 0;
|
|
193
|
+
margin-left: -40px;
|
|
194
|
+
border-bottom: 3px solid #006;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
div#classHeader a, div#fileHeader a {
|
|
198
|
+
background: inherit;
|
|
199
|
+
color: white;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
div#classHeader td, div#fileHeader td {
|
|
203
|
+
background: inherit;
|
|
204
|
+
color: white;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
div#fileHeader {
|
|
209
|
+
background: #057;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
div#classHeader {
|
|
213
|
+
background: #048;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
.class-name-in-header {
|
|
218
|
+
font-size: 180%;
|
|
219
|
+
font-weight: bold;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
div#bodyContent {
|
|
224
|
+
padding: 0 1.5em 0 1.5em;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
div#description {
|
|
228
|
+
padding: 0.5em 1.5em;
|
|
229
|
+
background: #efefef;
|
|
230
|
+
border: 1px dotted #999;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
|
234
|
+
color: #125;;
|
|
235
|
+
background: transparent;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
div#validator-badges {
|
|
239
|
+
text-align: center;
|
|
240
|
+
}
|
|
241
|
+
div#validator-badges img { border: 0; }
|
|
242
|
+
|
|
243
|
+
div#copyright {
|
|
244
|
+
color: #333;
|
|
245
|
+
background: #efefef;
|
|
246
|
+
font: 0.75em sans-serif;
|
|
247
|
+
margin-top: 5em;
|
|
248
|
+
margin-bottom: 0;
|
|
249
|
+
padding: 0.5em 2em;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
/* === Classes =================================== */
|
|
254
|
+
|
|
255
|
+
table.header-table {
|
|
256
|
+
color: white;
|
|
257
|
+
font-size: small;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.type-note {
|
|
261
|
+
font-size: small;
|
|
262
|
+
color: #DEDEDE;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.xxsection-bar {
|
|
266
|
+
background: #eee;
|
|
267
|
+
color: #333;
|
|
268
|
+
padding: 3px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.section-bar {
|
|
272
|
+
color: #333;
|
|
273
|
+
border-bottom: 1px solid #999;
|
|
274
|
+
margin-left: -20px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
.section-title {
|
|
279
|
+
background: #79a;
|
|
280
|
+
color: #eee;
|
|
281
|
+
padding: 3px;
|
|
282
|
+
margin-top: 2em;
|
|
283
|
+
margin-left: -30px;
|
|
284
|
+
border: 1px solid #999;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.top-aligned-row { vertical-align: top }
|
|
288
|
+
.bottom-aligned-row { vertical-align: bottom }
|
|
289
|
+
|
|
290
|
+
/* --- Context section classes ----------------------- */
|
|
291
|
+
|
|
292
|
+
.context-row { }
|
|
293
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
|
294
|
+
.context-item-value { font-size: small; color: #448; }
|
|
295
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
|
296
|
+
|
|
297
|
+
/* --- Method classes -------------------------- */
|
|
298
|
+
.method-detail {
|
|
299
|
+
background: #efefef;
|
|
300
|
+
padding: 0;
|
|
301
|
+
margin-top: 0.5em;
|
|
302
|
+
margin-bottom: 1em;
|
|
303
|
+
border: 1px dotted #ccc;
|
|
304
|
+
}
|
|
305
|
+
.method-heading {
|
|
306
|
+
color: black;
|
|
307
|
+
background: #ccc;
|
|
308
|
+
border-bottom: 1px solid #666;
|
|
309
|
+
padding: 0.2em 0.5em 0 0.5em;
|
|
310
|
+
}
|
|
311
|
+
.method-signature { color: black; background: inherit; }
|
|
312
|
+
.method-name { font-weight: bold; }
|
|
313
|
+
.method-args { font-style: italic; }
|
|
314
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
|
315
|
+
|
|
316
|
+
/* --- Source code sections -------------------- */
|
|
317
|
+
|
|
318
|
+
a.source-toggle { font-size: 90%; }
|
|
319
|
+
div.method-source-code {
|
|
320
|
+
background: #262626;
|
|
321
|
+
color: #ffdead;
|
|
322
|
+
margin: 1em;
|
|
323
|
+
padding: 0.5em;
|
|
324
|
+
border: 1px dashed #999;
|
|
325
|
+
overflow: hidden;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|
329
|
+
|
|
330
|
+
/* --- Ruby keyword styles --------------------- */
|
|
331
|
+
|
|
332
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
|
333
|
+
|
|
334
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
|
335
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
|
336
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
|
337
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
|
338
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
|
339
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
|
340
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
|
341
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
|
342
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
|
343
|
+
RDOC_CSS
|
|
344
|
+
|
|
345
|
+
RDOC_NO_DOCUMENTATION = <<-'NO_DOC'
|
|
346
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
347
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
348
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
349
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
350
|
+
<head>
|
|
351
|
+
<title>Found documentation</title>
|
|
352
|
+
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
353
|
+
</head>
|
|
354
|
+
<body>
|
|
355
|
+
<div id="fileHeader">
|
|
356
|
+
<%= SEARCH %>
|
|
357
|
+
<h1>No documentation found</h1>
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
<div id="bodyContent">
|
|
361
|
+
<div id="contextContent">
|
|
362
|
+
<div id="description">
|
|
363
|
+
<p>No gems matched <%= h query.inspect %></p>
|
|
364
|
+
|
|
365
|
+
<p>
|
|
366
|
+
Back to <a href="/">complete gem index</a>
|
|
367
|
+
</p>
|
|
368
|
+
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
<div id="validator-badges">
|
|
373
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
374
|
+
</div>
|
|
375
|
+
</body>
|
|
376
|
+
</html>
|
|
377
|
+
NO_DOC
|
|
378
|
+
|
|
379
|
+
RDOC_SEARCH_TEMPLATE = <<-'RDOC_SEARCH'
|
|
380
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
381
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
382
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
383
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
384
|
+
<head>
|
|
385
|
+
<title>Found documentation</title>
|
|
386
|
+
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
387
|
+
</head>
|
|
388
|
+
<body>
|
|
389
|
+
<div id="fileHeader">
|
|
390
|
+
<%= SEARCH %>
|
|
391
|
+
<h1>Found documentation</h1>
|
|
392
|
+
</div>
|
|
393
|
+
<!-- banner header -->
|
|
394
|
+
|
|
395
|
+
<div id="bodyContent">
|
|
396
|
+
<div id="contextContent">
|
|
397
|
+
<div id="description">
|
|
398
|
+
<h1>Summary</h1>
|
|
399
|
+
<p><%=doc_items.length%> documentation topics found.</p>
|
|
400
|
+
<h1>Topics</h1>
|
|
401
|
+
|
|
402
|
+
<dl>
|
|
403
|
+
<% doc_items.each do |doc_item| %>
|
|
404
|
+
<dt>
|
|
405
|
+
<b><%=doc_item[:name]%></b>
|
|
406
|
+
<a href="<%=doc_item[:url]%>">[rdoc]</a>
|
|
407
|
+
</dt>
|
|
408
|
+
<dd>
|
|
409
|
+
<%=doc_item[:summary]%>
|
|
410
|
+
<br/>
|
|
411
|
+
<br/>
|
|
412
|
+
</dd>
|
|
413
|
+
<% end %>
|
|
414
|
+
</dl>
|
|
415
|
+
|
|
416
|
+
<p>
|
|
417
|
+
Back to <a href="/">complete gem index</a>
|
|
418
|
+
</p>
|
|
419
|
+
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
<div id="validator-badges">
|
|
424
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
425
|
+
</div>
|
|
426
|
+
</body>
|
|
427
|
+
</html>
|
|
428
|
+
RDOC_SEARCH
|
|
429
|
+
|
|
430
|
+
def self.run(options)
|
|
431
|
+
new(options[:gemdir], options[:port], options[:daemon],
|
|
432
|
+
options[:launch], options[:addresses]).run
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
##
|
|
436
|
+
# Only the first directory in gem_dirs is used for serving gems
|
|
437
|
+
|
|
438
|
+
def initialize(gem_dirs, port, daemon, launch = nil, addresses = nil)
|
|
439
|
+
Socket.do_not_reverse_lookup = true
|
|
440
|
+
|
|
441
|
+
@gem_dirs = Array gem_dirs
|
|
442
|
+
@port = port
|
|
443
|
+
@daemon = daemon
|
|
444
|
+
@launch = launch
|
|
445
|
+
@addresses = addresses
|
|
446
|
+
logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
|
|
447
|
+
@server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
|
|
448
|
+
|
|
449
|
+
@spec_dirs = @gem_dirs.map do |gem_dir|
|
|
450
|
+
spec_dir = File.join gem_dir, 'specifications'
|
|
451
|
+
|
|
452
|
+
unless File.directory? spec_dir then
|
|
453
|
+
raise ArgumentError, "#{gem_dir} does not appear to be a gem repository"
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
spec_dir
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
@source_index = LibGems::SourceIndex.from_gems_in(*@spec_dirs)
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def Marshal(req, res)
|
|
463
|
+
@source_index.refresh!
|
|
464
|
+
|
|
465
|
+
add_date res
|
|
466
|
+
|
|
467
|
+
index = Marshal.dump @source_index
|
|
468
|
+
|
|
469
|
+
if req.request_method == 'HEAD' then
|
|
470
|
+
res['content-length'] = index.length
|
|
471
|
+
return
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
if req.path =~ /Z$/ then
|
|
475
|
+
res['content-type'] = 'application/x-deflate'
|
|
476
|
+
index = LibGems.deflate index
|
|
477
|
+
else
|
|
478
|
+
res['content-type'] = 'application/octet-stream'
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
res.body << index
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def add_date res
|
|
485
|
+
res['date'] = @spec_dirs.map do |spec_dir|
|
|
486
|
+
File.stat(spec_dir).mtime
|
|
487
|
+
end.max
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def latest_specs(req, res)
|
|
491
|
+
@source_index.refresh!
|
|
492
|
+
|
|
493
|
+
res['content-type'] = 'application/x-gzip'
|
|
494
|
+
|
|
495
|
+
add_date res
|
|
496
|
+
|
|
497
|
+
specs = @source_index.latest_specs.sort.map do |spec|
|
|
498
|
+
platform = spec.original_platform
|
|
499
|
+
platform = LibGems::Platform::RUBY if platform.nil?
|
|
500
|
+
[spec.name, spec.version, platform]
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
specs = Marshal.dump specs
|
|
504
|
+
|
|
505
|
+
if req.path =~ /\.gz$/ then
|
|
506
|
+
specs = LibGems.gzip specs
|
|
507
|
+
res['content-type'] = 'application/x-gzip'
|
|
508
|
+
else
|
|
509
|
+
res['content-type'] = 'application/octet-stream'
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
if req.request_method == 'HEAD' then
|
|
513
|
+
res['content-length'] = specs.length
|
|
514
|
+
else
|
|
515
|
+
res.body << specs
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
##
|
|
520
|
+
# Creates server sockets based on the addresses option. If no addresses
|
|
521
|
+
# were given a server socket for all interfaces is created.
|
|
522
|
+
|
|
523
|
+
def listen addresses = @addresses
|
|
524
|
+
addresses = [nil] unless addresses
|
|
525
|
+
|
|
526
|
+
listeners = 0
|
|
527
|
+
|
|
528
|
+
addresses.each do |address|
|
|
529
|
+
begin
|
|
530
|
+
@server.listen address, @port
|
|
531
|
+
@server.listeners[listeners..-1].each do |listener|
|
|
532
|
+
host, port = listener.addr.values_at 2, 1
|
|
533
|
+
host = "[#{host}]" if host =~ /:/ # we don't reverse lookup
|
|
534
|
+
say "Server started at http://#{host}:#{port}"
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
listeners = @server.listeners.length
|
|
538
|
+
rescue SystemCallError
|
|
539
|
+
next
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
if @server.listeners.empty? then
|
|
544
|
+
say "Unable to start a server."
|
|
545
|
+
say "Check for running servers or your --bind and --port arguments"
|
|
546
|
+
terminate_interaction 1
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def quick(req, res)
|
|
551
|
+
@source_index.refresh!
|
|
552
|
+
|
|
553
|
+
res['content-type'] = 'text/plain'
|
|
554
|
+
add_date res
|
|
555
|
+
|
|
556
|
+
case req.request_uri.path
|
|
557
|
+
when '/quick/index' then
|
|
558
|
+
res.body << @source_index.map { |name,| name }.sort.join("\n")
|
|
559
|
+
when '/quick/index.rz' then
|
|
560
|
+
index = @source_index.map { |name,| name }.sort.join("\n")
|
|
561
|
+
res['content-type'] = 'application/x-deflate'
|
|
562
|
+
res.body << LibGems.deflate(index)
|
|
563
|
+
when '/quick/latest_index' then
|
|
564
|
+
index = @source_index.latest_specs.map { |spec| spec.full_name }
|
|
565
|
+
res.body << index.sort.join("\n")
|
|
566
|
+
when '/quick/latest_index.rz' then
|
|
567
|
+
index = @source_index.latest_specs.map { |spec| spec.full_name }
|
|
568
|
+
res['content-type'] = 'application/x-deflate'
|
|
569
|
+
res.body << LibGems.deflate(index.sort.join("\n"))
|
|
570
|
+
when %r|^/quick/(Marshal.#{Regexp.escape LibGems.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then
|
|
571
|
+
dep = LibGems::Dependency.new $2, $3
|
|
572
|
+
specs = @source_index.search dep
|
|
573
|
+
marshal_format = $1
|
|
574
|
+
|
|
575
|
+
selector = [$2, $3, $4].map { |s| s.inspect }.join ' '
|
|
576
|
+
|
|
577
|
+
platform = if $4 then
|
|
578
|
+
LibGems::Platform.new $4.sub(/^-/, '')
|
|
579
|
+
else
|
|
580
|
+
LibGems::Platform::RUBY
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
specs = specs.select { |s| s.platform == platform }
|
|
584
|
+
|
|
585
|
+
if specs.empty? then
|
|
586
|
+
res.status = 404
|
|
587
|
+
res.body = "No gems found matching #{selector}"
|
|
588
|
+
elsif specs.length > 1 then
|
|
589
|
+
res.status = 500
|
|
590
|
+
res.body = "Multiple gems found matching #{selector}"
|
|
591
|
+
elsif marshal_format then
|
|
592
|
+
res['content-type'] = 'application/x-deflate'
|
|
593
|
+
res.body << LibGems.deflate(Marshal.dump(specs.first))
|
|
594
|
+
else # deprecated YAML format
|
|
595
|
+
res['content-type'] = 'application/x-deflate'
|
|
596
|
+
res.body << LibGems.deflate(specs.first.to_yaml)
|
|
597
|
+
end
|
|
598
|
+
else
|
|
599
|
+
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def root(req, res)
|
|
604
|
+
@source_index.refresh!
|
|
605
|
+
add_date res
|
|
606
|
+
|
|
607
|
+
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
|
|
608
|
+
req.path == '/'
|
|
609
|
+
|
|
610
|
+
specs = []
|
|
611
|
+
total_file_count = 0
|
|
612
|
+
|
|
613
|
+
@source_index.each do |path, spec|
|
|
614
|
+
total_file_count += spec.files.size
|
|
615
|
+
deps = spec.dependencies.map do |dep|
|
|
616
|
+
{ "name" => dep.name,
|
|
617
|
+
"type" => dep.type,
|
|
618
|
+
"version" => dep.requirement.to_s, }
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
|
|
622
|
+
deps.last["is_last"] = true unless deps.empty?
|
|
623
|
+
|
|
624
|
+
# executables
|
|
625
|
+
executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
|
|
626
|
+
executables = nil if executables.empty?
|
|
627
|
+
executables.last["is_last"] = true if executables
|
|
628
|
+
|
|
629
|
+
specs << {
|
|
630
|
+
"authors" => spec.authors.sort.join(", "),
|
|
631
|
+
"date" => spec.date.to_s,
|
|
632
|
+
"dependencies" => deps,
|
|
633
|
+
"doc_path" => "/doc_root/#{spec.full_name}/rdoc/index.html",
|
|
634
|
+
"executables" => executables,
|
|
635
|
+
"only_one_executable" => (executables && executables.size == 1),
|
|
636
|
+
"full_name" => spec.full_name,
|
|
637
|
+
"has_deps" => !deps.empty?,
|
|
638
|
+
"homepage" => spec.homepage,
|
|
639
|
+
"name" => spec.name,
|
|
640
|
+
"rdoc_installed" => LibGems::DocManager.new(spec).rdoc_installed?,
|
|
641
|
+
"summary" => spec.summary,
|
|
642
|
+
"version" => spec.version.to_s,
|
|
643
|
+
}
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
specs << {
|
|
647
|
+
"authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
|
|
648
|
+
"dependencies" => [],
|
|
649
|
+
"doc_path" => "/doc_root/rubygems-#{LibGems::GEM_VERSION}/rdoc/index.html",
|
|
650
|
+
"executables" => [{"executable" => 'gem', "is_last" => true}],
|
|
651
|
+
"only_one_executable" => true,
|
|
652
|
+
"full_name" => "libgems-#{LibGems::VERSION}",
|
|
653
|
+
"has_deps" => false,
|
|
654
|
+
"homepage" => "http://docs.rubygems.org/",
|
|
655
|
+
"name" => 'rubygems',
|
|
656
|
+
"rdoc_installed" => true,
|
|
657
|
+
"summary" => "#{LibGems::NAME} itself",
|
|
658
|
+
"version" => LibGems::VERSION,
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
|
|
662
|
+
specs.last["is_last"] = true
|
|
663
|
+
|
|
664
|
+
# tag all specs with first_name_entry
|
|
665
|
+
last_spec = nil
|
|
666
|
+
specs.each do |spec|
|
|
667
|
+
is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
|
|
668
|
+
spec["first_name_entry"] = is_first
|
|
669
|
+
last_spec = spec
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
# create page from template
|
|
673
|
+
template = ERB.new(DOC_TEMPLATE)
|
|
674
|
+
res['content-type'] = 'text/html'
|
|
675
|
+
|
|
676
|
+
values = { "gem_count" => specs.size.to_s, "specs" => specs,
|
|
677
|
+
"total_file_count" => total_file_count.to_s }
|
|
678
|
+
|
|
679
|
+
result = template.result binding
|
|
680
|
+
res.body = result
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
##
|
|
684
|
+
# Can be used for quick navigation to the rdoc documentation. You can then
|
|
685
|
+
# define a search shortcut for your browser. E.g. in Firefox connect
|
|
686
|
+
# 'shortcut:rdoc' to http://localhost:8808/rdoc?q=%s template. Then you can
|
|
687
|
+
# directly open the ActionPack documentation by typing 'rdoc actionp'. If
|
|
688
|
+
# there are multiple hits for the search term, they are presented as a list
|
|
689
|
+
# with links.
|
|
690
|
+
#
|
|
691
|
+
# Search algorithm aims for an intuitive search:
|
|
692
|
+
# 1. first try to find the gems and documentation folders which name
|
|
693
|
+
# starts with the search term
|
|
694
|
+
# 2. search for entries, that *contain* the search term
|
|
695
|
+
# 3. show all the gems
|
|
696
|
+
#
|
|
697
|
+
# If there is only one search hit, user is immediately redirected to the
|
|
698
|
+
# documentation for the particular gem, otherwise a list with results is
|
|
699
|
+
# shown.
|
|
700
|
+
#
|
|
701
|
+
# === Additional trick - install documentation for ruby core
|
|
702
|
+
#
|
|
703
|
+
# Note: please adjust paths accordingly use for example 'locate yaml.rb' and
|
|
704
|
+
# 'gem environment' to identify directories, that are specific for your
|
|
705
|
+
# local installation
|
|
706
|
+
#
|
|
707
|
+
# 1. install ruby sources
|
|
708
|
+
# cd /usr/src
|
|
709
|
+
# sudo apt-get source ruby
|
|
710
|
+
#
|
|
711
|
+
# 2. generate documentation
|
|
712
|
+
# rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc \
|
|
713
|
+
# /usr/lib/ruby/1.8 ruby1.8-1.8.7.72
|
|
714
|
+
#
|
|
715
|
+
# By typing 'rdoc core' you can now access the core documentation
|
|
716
|
+
|
|
717
|
+
def rdoc(req, res)
|
|
718
|
+
query = req.query['q']
|
|
719
|
+
show_rdoc_for_pattern("#{query}*", res) && return
|
|
720
|
+
show_rdoc_for_pattern("*#{query}*", res) && return
|
|
721
|
+
|
|
722
|
+
template = ERB.new RDOC_NO_DOCUMENTATION
|
|
723
|
+
|
|
724
|
+
res['content-type'] = 'text/html'
|
|
725
|
+
res.body = template.result binding
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
##
|
|
729
|
+
# Returns true and prepares http response, if rdoc for the requested gem
|
|
730
|
+
# name pattern was found.
|
|
731
|
+
#
|
|
732
|
+
# The search is based on the file system content, not on the gems metadata.
|
|
733
|
+
# This allows additional documentation folders like 'core' for the ruby core
|
|
734
|
+
# documentation - just put it underneath the main doc folder.
|
|
735
|
+
|
|
736
|
+
def show_rdoc_for_pattern(pattern, res)
|
|
737
|
+
found_gems = Dir.glob("{#{@gem_dirs.join ','}}/doc/#{pattern}").select {|path|
|
|
738
|
+
File.exist? File.join(path, 'rdoc/index.html')
|
|
739
|
+
}
|
|
740
|
+
case found_gems.length
|
|
741
|
+
when 0
|
|
742
|
+
return false
|
|
743
|
+
when 1
|
|
744
|
+
new_path = File.basename(found_gems[0])
|
|
745
|
+
res.status = 302
|
|
746
|
+
res['Location'] = "/doc_root/#{new_path}/rdoc/index.html"
|
|
747
|
+
return true
|
|
748
|
+
else
|
|
749
|
+
doc_items = []
|
|
750
|
+
found_gems.each do |file_name|
|
|
751
|
+
base_name = File.basename(file_name)
|
|
752
|
+
doc_items << {
|
|
753
|
+
:name => base_name,
|
|
754
|
+
:url => "/doc_root/#{base_name}/rdoc/index.html",
|
|
755
|
+
:summary => ''
|
|
756
|
+
}
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
template = ERB.new(RDOC_SEARCH_TEMPLATE)
|
|
760
|
+
res['content-type'] = 'text/html'
|
|
761
|
+
result = template.result binding
|
|
762
|
+
res.body = result
|
|
763
|
+
return true
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def run
|
|
768
|
+
listen
|
|
769
|
+
|
|
770
|
+
WEBrick::Daemon.start if @daemon
|
|
771
|
+
|
|
772
|
+
@server.mount_proc "/yaml", method(:yaml)
|
|
773
|
+
@server.mount_proc "/yaml.Z", method(:yaml)
|
|
774
|
+
|
|
775
|
+
@server.mount_proc "/Marshal.#{LibGems.marshal_version}", method(:Marshal)
|
|
776
|
+
@server.mount_proc "/Marshal.#{LibGems.marshal_version}.Z", method(:Marshal)
|
|
777
|
+
|
|
778
|
+
@server.mount_proc "/specs.#{LibGems.marshal_version}", method(:specs)
|
|
779
|
+
@server.mount_proc "/specs.#{LibGems.marshal_version}.gz", method(:specs)
|
|
780
|
+
|
|
781
|
+
@server.mount_proc "/latest_specs.#{LibGems.marshal_version}",
|
|
782
|
+
method(:latest_specs)
|
|
783
|
+
@server.mount_proc "/latest_specs.#{LibGems.marshal_version}.gz",
|
|
784
|
+
method(:latest_specs)
|
|
785
|
+
|
|
786
|
+
@server.mount_proc "/quick/", method(:quick)
|
|
787
|
+
|
|
788
|
+
@server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
|
|
789
|
+
res['content-type'] = 'text/css'
|
|
790
|
+
add_date res
|
|
791
|
+
res.body << RDOC_CSS
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
@server.mount_proc "/", method(:root)
|
|
795
|
+
|
|
796
|
+
@server.mount_proc "/rdoc", method(:rdoc)
|
|
797
|
+
|
|
798
|
+
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
|
|
799
|
+
paths.each do |mount_point, mount_dir|
|
|
800
|
+
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
|
|
801
|
+
File.join(@gem_dirs.first, mount_dir), true)
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
trap("INT") { @server.shutdown; exit! }
|
|
805
|
+
trap("TERM") { @server.shutdown; exit! }
|
|
806
|
+
|
|
807
|
+
launch if @launch
|
|
808
|
+
|
|
809
|
+
@server.start
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
def specs(req, res)
|
|
813
|
+
@source_index.refresh!
|
|
814
|
+
|
|
815
|
+
add_date res
|
|
816
|
+
|
|
817
|
+
specs = @source_index.sort.map do |_, spec|
|
|
818
|
+
platform = spec.original_platform
|
|
819
|
+
platform = LibGems::Platform::RUBY if platform.nil?
|
|
820
|
+
[spec.name, spec.version, platform]
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
specs = Marshal.dump specs
|
|
824
|
+
|
|
825
|
+
if req.path =~ /\.gz$/ then
|
|
826
|
+
specs = LibGems.gzip specs
|
|
827
|
+
res['content-type'] = 'application/x-gzip'
|
|
828
|
+
else
|
|
829
|
+
res['content-type'] = 'application/octet-stream'
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
if req.request_method == 'HEAD' then
|
|
833
|
+
res['content-length'] = specs.length
|
|
834
|
+
else
|
|
835
|
+
res.body << specs
|
|
836
|
+
end
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
def yaml(req, res)
|
|
840
|
+
@source_index.refresh!
|
|
841
|
+
|
|
842
|
+
add_date res
|
|
843
|
+
|
|
844
|
+
index = @source_index.to_yaml
|
|
845
|
+
|
|
846
|
+
if req.path =~ /Z$/ then
|
|
847
|
+
res['content-type'] = 'application/x-deflate'
|
|
848
|
+
index = LibGems.deflate index
|
|
849
|
+
else
|
|
850
|
+
res['content-type'] = 'text/plain'
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
if req.request_method == 'HEAD' then
|
|
854
|
+
res['content-length'] = index.length
|
|
855
|
+
return
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
res.body << index
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
def launch
|
|
862
|
+
listeners = @server.listeners.map{|l| l.addr[2] }
|
|
863
|
+
|
|
864
|
+
host = listeners.any?{|l| l == '0.0.0.0'} ? 'localhost' : listeners.first
|
|
865
|
+
|
|
866
|
+
say "Launching browser to http://#{host}:#{@port}"
|
|
867
|
+
|
|
868
|
+
system("#{@launch} http://#{host}:#{@port}")
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
end
|
|
872
|
+
|