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,337 @@
|
|
|
1
|
+
require 'zlib'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
require 'libgems/remote_fetcher'
|
|
5
|
+
require 'libgems/user_interaction'
|
|
6
|
+
require 'libgems/errors'
|
|
7
|
+
require 'libgems/text'
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# SpecFetcher handles metadata updates from remote gem repositories.
|
|
11
|
+
|
|
12
|
+
class LibGems::SpecFetcher
|
|
13
|
+
|
|
14
|
+
include LibGems::UserInteraction
|
|
15
|
+
include LibGems::Text
|
|
16
|
+
|
|
17
|
+
FILES = {
|
|
18
|
+
:all => 'specs',
|
|
19
|
+
:latest => 'latest_specs',
|
|
20
|
+
:prerelease => 'prerelease_specs',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# The SpecFetcher cache dir.
|
|
25
|
+
|
|
26
|
+
attr_reader :dir # :nodoc:
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Cache of latest specs
|
|
30
|
+
|
|
31
|
+
attr_reader :latest_specs # :nodoc:
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Cache of all released specs
|
|
35
|
+
|
|
36
|
+
attr_reader :specs # :nodoc:
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Cache of prerelease specs
|
|
40
|
+
|
|
41
|
+
attr_reader :prerelease_specs # :nodoc:
|
|
42
|
+
|
|
43
|
+
@fetcher = nil
|
|
44
|
+
|
|
45
|
+
def self.fetcher
|
|
46
|
+
@fetcher ||= new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.fetcher=(fetcher) # :nodoc:
|
|
50
|
+
@fetcher = fetcher
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def initialize
|
|
54
|
+
@dir = File.join LibGems.user_home, '.gem', 'specs'
|
|
55
|
+
@update_cache = File.stat(LibGems.user_home).uid == Process.uid
|
|
56
|
+
|
|
57
|
+
@specs = {}
|
|
58
|
+
@latest_specs = {}
|
|
59
|
+
@prerelease_specs = {}
|
|
60
|
+
|
|
61
|
+
@caches = {
|
|
62
|
+
:latest => @latest_specs,
|
|
63
|
+
:prerelease => @prerelease_specs,
|
|
64
|
+
:all => @specs
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@fetcher = LibGems::RemoteFetcher.fetcher
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# Returns the local directory to write +uri+ to.
|
|
72
|
+
|
|
73
|
+
def cache_dir(uri)
|
|
74
|
+
File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Fetch specs matching +dependency+. If +all+ is true, all matching
|
|
79
|
+
# (released) versions are returned. If +matching_platform+ is
|
|
80
|
+
# false, all platforms are returned. If +prerelease+ is true,
|
|
81
|
+
# prerelease versions are included.
|
|
82
|
+
|
|
83
|
+
def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
|
|
84
|
+
specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease
|
|
85
|
+
|
|
86
|
+
ss = specs_and_sources.map do |spec_tuple, source_uri|
|
|
87
|
+
[fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
return [ss, errors]
|
|
91
|
+
|
|
92
|
+
rescue LibGems::RemoteFetcher::FetchError => e
|
|
93
|
+
raise unless warn_legacy e do
|
|
94
|
+
require 'libgems/source_info_cache'
|
|
95
|
+
|
|
96
|
+
return [LibGems::SourceInfoCache.search_with_source(dependency,
|
|
97
|
+
matching_platform, all), nil]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def fetch(*args)
|
|
102
|
+
fetch_with_errors(*args).first
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def fetch_spec(spec, source_uri)
|
|
106
|
+
spec = spec - [nil, 'ruby', '']
|
|
107
|
+
spec_file_name = "#{spec.join '-'}.gemspec"
|
|
108
|
+
|
|
109
|
+
uri = source_uri + "#{LibGems::MARSHAL_SPEC_DIR}#{spec_file_name}"
|
|
110
|
+
|
|
111
|
+
cache_dir = cache_dir uri
|
|
112
|
+
|
|
113
|
+
local_spec = File.join cache_dir, spec_file_name
|
|
114
|
+
|
|
115
|
+
if File.exist? local_spec then
|
|
116
|
+
spec = LibGems.read_binary local_spec
|
|
117
|
+
else
|
|
118
|
+
uri.path << '.rz'
|
|
119
|
+
|
|
120
|
+
spec = @fetcher.fetch_path uri
|
|
121
|
+
spec = LibGems.inflate spec
|
|
122
|
+
|
|
123
|
+
if @update_cache then
|
|
124
|
+
FileUtils.mkdir_p cache_dir
|
|
125
|
+
|
|
126
|
+
open local_spec, 'wb' do |io|
|
|
127
|
+
io.write spec
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# TODO: Investigate setting LibGems::Specification#loaded_from to a URI
|
|
133
|
+
Marshal.load spec
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
##
|
|
137
|
+
# Find spec names that match +dependency+. If +all+ is true, all
|
|
138
|
+
# matching released versions are returned. If +matching_platform+
|
|
139
|
+
# is false, gems for all platforms are returned.
|
|
140
|
+
|
|
141
|
+
def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
|
|
142
|
+
found = {}
|
|
143
|
+
|
|
144
|
+
rejected_specs = {}
|
|
145
|
+
|
|
146
|
+
list(all, prerelease).each do |source_uri, specs|
|
|
147
|
+
found[source_uri] = specs.select do |spec_name, version, spec_platform|
|
|
148
|
+
if dependency.match?(spec_name, version)
|
|
149
|
+
if matching_platform and !LibGems::Platform.match(spec_platform)
|
|
150
|
+
pm = (rejected_specs[dependency] ||= LibGems::PlatformMismatch.new(spec_name, version))
|
|
151
|
+
pm.add_platform spec_platform
|
|
152
|
+
false
|
|
153
|
+
else
|
|
154
|
+
true
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
errors = rejected_specs.values
|
|
161
|
+
|
|
162
|
+
specs_and_sources = []
|
|
163
|
+
|
|
164
|
+
found.each do |source_uri, specs|
|
|
165
|
+
uri_str = source_uri.to_s
|
|
166
|
+
specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
[specs_and_sources, errors]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def find_matching(*args)
|
|
173
|
+
find_matching_with_errors(*args).first
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
##
|
|
177
|
+
# Returns Array of gem repositories that were generated with SlimGems less
|
|
178
|
+
# than 1.2.
|
|
179
|
+
|
|
180
|
+
def legacy_repos
|
|
181
|
+
LibGems.sources.reject do |source_uri|
|
|
182
|
+
source_uri = URI.parse source_uri
|
|
183
|
+
spec_path = source_uri + "specs.#{LibGems.marshal_version}.gz"
|
|
184
|
+
|
|
185
|
+
begin
|
|
186
|
+
@fetcher.fetch_size spec_path
|
|
187
|
+
rescue LibGems::RemoteFetcher::FetchError
|
|
188
|
+
begin
|
|
189
|
+
@fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
|
|
190
|
+
rescue LibGems::RemoteFetcher::FetchError
|
|
191
|
+
alert_error "#{source_uri} does not appear to be a repository"
|
|
192
|
+
raise
|
|
193
|
+
end
|
|
194
|
+
false
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
##
|
|
200
|
+
# Suggests a gem based on the supplied +gem_name+. Returns a string
|
|
201
|
+
# of the gem name if an approximate match can be found or nil
|
|
202
|
+
# otherwise. NOTE: for performance reasons only gems which exactly
|
|
203
|
+
# match the first character of +gem_name+ are considered.
|
|
204
|
+
|
|
205
|
+
def suggest_gems_from_name gem_name
|
|
206
|
+
gem_name = gem_name.downcase
|
|
207
|
+
gem_starts_with = gem_name[0,1]
|
|
208
|
+
max = gem_name.size / 2
|
|
209
|
+
specs = list.values.flatten(1) # flatten(1) is 1.8.7 and up
|
|
210
|
+
|
|
211
|
+
matches = specs.map { |name, version, platform|
|
|
212
|
+
next unless LibGems::Platform.match platform
|
|
213
|
+
|
|
214
|
+
distance = levenshtein_distance gem_name, name.downcase
|
|
215
|
+
|
|
216
|
+
next if distance >= max
|
|
217
|
+
|
|
218
|
+
return [name] if distance == 0
|
|
219
|
+
|
|
220
|
+
[name, distance]
|
|
221
|
+
}.compact
|
|
222
|
+
|
|
223
|
+
matches = matches.uniq.sort_by { |name, dist| dist }
|
|
224
|
+
|
|
225
|
+
matches.first(5).map { |name, dist| name }
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
##
|
|
229
|
+
# Returns a list of gems available for each source in LibGems::sources. If
|
|
230
|
+
# +all+ is true, all released versions are returned instead of only latest
|
|
231
|
+
# versions. If +prerelease+ is true, include prerelease versions.
|
|
232
|
+
|
|
233
|
+
def list(all = false, prerelease = false)
|
|
234
|
+
# TODO: make type the only argument
|
|
235
|
+
type = if all
|
|
236
|
+
:all
|
|
237
|
+
elsif prerelease
|
|
238
|
+
:prerelease
|
|
239
|
+
else
|
|
240
|
+
:latest
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
list = {}
|
|
244
|
+
file = FILES[type]
|
|
245
|
+
cache = @caches[type]
|
|
246
|
+
|
|
247
|
+
LibGems.sources.each do |source_uri|
|
|
248
|
+
source_uri = URI.parse source_uri
|
|
249
|
+
|
|
250
|
+
unless cache.include? source_uri
|
|
251
|
+
cache[source_uri] = load_specs source_uri, file
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
list[source_uri] = cache[source_uri]
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
if type == :all
|
|
258
|
+
list.values.map do |gems|
|
|
259
|
+
gems.reject! { |g| !g[1] || g[1].prerelease? }
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
list
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
##
|
|
267
|
+
# Loads specs in +file+, fetching from +source_uri+ if the on-disk cache is
|
|
268
|
+
# out of date.
|
|
269
|
+
|
|
270
|
+
def load_specs(source_uri, file)
|
|
271
|
+
file_name = "#{file}.#{LibGems.marshal_version}"
|
|
272
|
+
spec_path = source_uri + "#{file_name}.gz"
|
|
273
|
+
cache_dir = cache_dir spec_path
|
|
274
|
+
local_file = File.join(cache_dir, file_name)
|
|
275
|
+
loaded = false
|
|
276
|
+
|
|
277
|
+
if File.exist? local_file then
|
|
278
|
+
spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
|
|
279
|
+
|
|
280
|
+
if spec_dump.nil? then
|
|
281
|
+
spec_dump = LibGems.read_binary local_file
|
|
282
|
+
else
|
|
283
|
+
loaded = true
|
|
284
|
+
end
|
|
285
|
+
else
|
|
286
|
+
spec_dump = @fetcher.fetch_path spec_path
|
|
287
|
+
loaded = true
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
specs = begin
|
|
291
|
+
Marshal.load spec_dump
|
|
292
|
+
rescue ArgumentError
|
|
293
|
+
spec_dump = @fetcher.fetch_path spec_path
|
|
294
|
+
loaded = true
|
|
295
|
+
|
|
296
|
+
Marshal.load spec_dump
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
if loaded and @update_cache then
|
|
300
|
+
begin
|
|
301
|
+
FileUtils.mkdir_p cache_dir
|
|
302
|
+
|
|
303
|
+
open local_file, 'wb' do |io|
|
|
304
|
+
io << spec_dump
|
|
305
|
+
end
|
|
306
|
+
rescue
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
specs
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
##
|
|
314
|
+
# Warn about legacy repositories if +exception+ indicates only legacy
|
|
315
|
+
# repositories are available, and yield to the block. Returns false if the
|
|
316
|
+
# exception indicates some other FetchError.
|
|
317
|
+
|
|
318
|
+
def warn_legacy(exception)
|
|
319
|
+
uri = exception.uri.to_s
|
|
320
|
+
if uri =~ /specs\.#{Regexp.escape LibGems.marshal_version}\.gz$/ then
|
|
321
|
+
alert_warning <<-EOF
|
|
322
|
+
#{LibGems::NAME} 1.2+ index not found for:
|
|
323
|
+
\t#{legacy_repos.join "\n\t"}
|
|
324
|
+
|
|
325
|
+
#{LibGems::NAME} will revert to legacy indexes degrading performance.
|
|
326
|
+
EOF
|
|
327
|
+
|
|
328
|
+
yield
|
|
329
|
+
|
|
330
|
+
return true
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
false
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
end
|
|
337
|
+
|
|
@@ -0,0 +1,1487 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
require 'libgems/version'
|
|
8
|
+
require 'libgems/requirement'
|
|
9
|
+
require 'libgems/platform'
|
|
10
|
+
|
|
11
|
+
# :stopdoc:
|
|
12
|
+
class Date; end # for ruby_code if date.rb wasn't required
|
|
13
|
+
# :startdoc:
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# The Specification class contains the metadata for a LibGems. Typically
|
|
17
|
+
# defined in a .gemspec file or a Rakefile, and looks like this:
|
|
18
|
+
#
|
|
19
|
+
# spec = LibGems::Specification.new do |s|
|
|
20
|
+
# s.name = 'example'
|
|
21
|
+
# s.version = '1.0'
|
|
22
|
+
# s.summary = 'Example gem specification'
|
|
23
|
+
# ...
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# For a great way to package gems, use Hoe.
|
|
27
|
+
|
|
28
|
+
class LibGems::Specification
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Allows deinstallation of gems with legacy platforms.
|
|
32
|
+
|
|
33
|
+
attr_accessor :original_platform # :nodoc:
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# The the version number of a specification that does not specify one
|
|
37
|
+
# (i.e. SlimGems 0.7 or earlier).
|
|
38
|
+
|
|
39
|
+
NONEXISTENT_SPECIFICATION_VERSION = -1
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# The specification version applied to any new Specification instances
|
|
43
|
+
# created. This should be bumped whenever something in the spec format
|
|
44
|
+
# changes.
|
|
45
|
+
#--
|
|
46
|
+
# When updating this number, be sure to also update #to_ruby.
|
|
47
|
+
#
|
|
48
|
+
# NOTE SlimGems < 1.2 cannot load specification versions > 2.
|
|
49
|
+
|
|
50
|
+
CURRENT_SPECIFICATION_VERSION = 3
|
|
51
|
+
|
|
52
|
+
##
|
|
53
|
+
# An informal list of changes to the specification. The highest-valued
|
|
54
|
+
# key should be equal to the CURRENT_SPECIFICATION_VERSION.
|
|
55
|
+
|
|
56
|
+
SPECIFICATION_VERSION_HISTORY = {
|
|
57
|
+
-1 => ["(#{LibGems::NAME} versions up to and including 0.7 did not have versioned specifications)"],
|
|
58
|
+
1 => [
|
|
59
|
+
'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
|
|
60
|
+
'"test_file=x" is a shortcut for "test_files=[x]"'
|
|
61
|
+
],
|
|
62
|
+
2 => [
|
|
63
|
+
'Added "required_rubygems_version"',
|
|
64
|
+
'Now forward-compatible with future versions',
|
|
65
|
+
],
|
|
66
|
+
3 => [
|
|
67
|
+
'Added Fixnum validation to the specification_version'
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# :stopdoc:
|
|
72
|
+
MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 }
|
|
73
|
+
|
|
74
|
+
now = Time.at(Time.now.to_i)
|
|
75
|
+
TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
|
|
76
|
+
# :startdoc:
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Optional block used to gather newly defined instances.
|
|
80
|
+
|
|
81
|
+
@@gather = nil
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# List of attribute names: [:name, :version, ...]
|
|
85
|
+
|
|
86
|
+
@@required_attributes = []
|
|
87
|
+
|
|
88
|
+
##
|
|
89
|
+
# List of _all_ attributes and default values:
|
|
90
|
+
#
|
|
91
|
+
# [[:name, nil],
|
|
92
|
+
# [:bindir, 'bin'],
|
|
93
|
+
# ...]
|
|
94
|
+
|
|
95
|
+
@@attributes = []
|
|
96
|
+
|
|
97
|
+
@@nil_attributes = []
|
|
98
|
+
@@non_nil_attributes = [:@original_platform]
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# List of array attributes
|
|
102
|
+
|
|
103
|
+
@@array_attributes = []
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# Map of attribute names to default values.
|
|
107
|
+
|
|
108
|
+
@@default_value = {}
|
|
109
|
+
|
|
110
|
+
##
|
|
111
|
+
# Names of all specification attributes
|
|
112
|
+
|
|
113
|
+
def self.attribute_names
|
|
114
|
+
@@attributes.map { |name, default| name }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# Default values for specification attributes
|
|
119
|
+
|
|
120
|
+
def self.attribute_defaults
|
|
121
|
+
@@attributes.dup
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
##
|
|
125
|
+
# The default value for specification attribute +name+
|
|
126
|
+
|
|
127
|
+
def self.default_value(name)
|
|
128
|
+
@@default_value[name]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# Required specification attributes
|
|
133
|
+
|
|
134
|
+
def self.required_attributes
|
|
135
|
+
@@required_attributes.dup
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
##
|
|
139
|
+
# Is +name+ a required attribute?
|
|
140
|
+
|
|
141
|
+
def self.required_attribute?(name)
|
|
142
|
+
@@required_attributes.include? name.to_sym
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
##
|
|
146
|
+
# Specification attributes that are arrays (appendable and so-forth)
|
|
147
|
+
|
|
148
|
+
def self.array_attributes
|
|
149
|
+
@@array_attributes.dup
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
##
|
|
153
|
+
# Specifies the +name+ and +default+ for a specification attribute, and
|
|
154
|
+
# creates a reader and writer method like Module#attr_accessor.
|
|
155
|
+
#
|
|
156
|
+
# The reader method returns the default if the value hasn't been set.
|
|
157
|
+
|
|
158
|
+
def self.attribute(name, default=nil)
|
|
159
|
+
ivar_name = "@#{name}".intern
|
|
160
|
+
if default.nil? then
|
|
161
|
+
@@nil_attributes << ivar_name
|
|
162
|
+
else
|
|
163
|
+
@@non_nil_attributes << [ivar_name, default]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
@@attributes << [name, default]
|
|
167
|
+
@@default_value[name] = default
|
|
168
|
+
attr_accessor(name)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
##
|
|
172
|
+
# Same as :attribute, but ensures that values assigned to the attribute
|
|
173
|
+
# are array values by applying :to_a to the value.
|
|
174
|
+
|
|
175
|
+
def self.array_attribute(name)
|
|
176
|
+
@@non_nil_attributes << ["@#{name}".intern, []]
|
|
177
|
+
|
|
178
|
+
@@array_attributes << name
|
|
179
|
+
@@attributes << [name, []]
|
|
180
|
+
@@default_value[name] = []
|
|
181
|
+
code = %{
|
|
182
|
+
def #{name}
|
|
183
|
+
@#{name} ||= []
|
|
184
|
+
end
|
|
185
|
+
def #{name}=(value)
|
|
186
|
+
@#{name} = Array(value)
|
|
187
|
+
end
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
module_eval code, __FILE__, __LINE__ - 9
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
##
|
|
194
|
+
# Same as attribute above, but also records this attribute as mandatory.
|
|
195
|
+
|
|
196
|
+
def self.required_attribute(*args)
|
|
197
|
+
@@required_attributes << args.first
|
|
198
|
+
attribute(*args)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
##
|
|
202
|
+
# Sometimes we don't want the world to use a setter method for a
|
|
203
|
+
# particular attribute.
|
|
204
|
+
#
|
|
205
|
+
# +read_only+ makes it private so we can still use it internally.
|
|
206
|
+
|
|
207
|
+
def self.read_only(*names)
|
|
208
|
+
names.each do |name|
|
|
209
|
+
private "#{name}="
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Shortcut for creating several attributes at once (each with a default
|
|
214
|
+
# value of +nil+).
|
|
215
|
+
|
|
216
|
+
def self.attributes(*args)
|
|
217
|
+
args.each do |arg|
|
|
218
|
+
attribute(arg, nil)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
##
|
|
223
|
+
# Some attributes require special behaviour when they are accessed. This
|
|
224
|
+
# allows for that.
|
|
225
|
+
|
|
226
|
+
def self.overwrite_accessor(name, &block)
|
|
227
|
+
remove_method name
|
|
228
|
+
define_method(name, &block)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
##
|
|
232
|
+
# Defines a _singular_ version of an existing _plural_ attribute (i.e. one
|
|
233
|
+
# whose value is expected to be an array). This means just creating a
|
|
234
|
+
# helper method that takes a single value and appends it to the array.
|
|
235
|
+
# These are created for convenience, so that in a spec, one can write
|
|
236
|
+
#
|
|
237
|
+
# s.require_path = 'mylib'
|
|
238
|
+
#
|
|
239
|
+
# instead of:
|
|
240
|
+
#
|
|
241
|
+
# s.require_paths = ['mylib']
|
|
242
|
+
#
|
|
243
|
+
# That above convenience is available courtesy of:
|
|
244
|
+
#
|
|
245
|
+
# attribute_alias_singular :require_path, :require_paths
|
|
246
|
+
|
|
247
|
+
def self.attribute_alias_singular(singular, plural)
|
|
248
|
+
define_method("#{singular}=") { |val|
|
|
249
|
+
send("#{plural}=", [val])
|
|
250
|
+
}
|
|
251
|
+
define_method("#{singular}") {
|
|
252
|
+
val = send("#{plural}")
|
|
253
|
+
val.nil? ? nil : val.first
|
|
254
|
+
}
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
##
|
|
258
|
+
# Dump only crucial instance variables.
|
|
259
|
+
#--
|
|
260
|
+
# MAINTAIN ORDER!
|
|
261
|
+
|
|
262
|
+
def _dump(limit)
|
|
263
|
+
Marshal.dump [
|
|
264
|
+
@rubygems_version,
|
|
265
|
+
@specification_version,
|
|
266
|
+
@name,
|
|
267
|
+
@version,
|
|
268
|
+
(Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))),
|
|
269
|
+
@summary,
|
|
270
|
+
@required_ruby_version,
|
|
271
|
+
@required_rubygems_version,
|
|
272
|
+
@original_platform,
|
|
273
|
+
@dependencies,
|
|
274
|
+
@rubyforge_project,
|
|
275
|
+
@email,
|
|
276
|
+
@authors,
|
|
277
|
+
@description,
|
|
278
|
+
@homepage,
|
|
279
|
+
@has_rdoc,
|
|
280
|
+
@new_platform,
|
|
281
|
+
@licenses
|
|
282
|
+
]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
##
|
|
286
|
+
# Load custom marshal format, re-initializing defaults as needed
|
|
287
|
+
|
|
288
|
+
def self._load(str)
|
|
289
|
+
array = Marshal.load str
|
|
290
|
+
|
|
291
|
+
spec = LibGems::Specification.new
|
|
292
|
+
spec.instance_variable_set :@specification_version, array[1]
|
|
293
|
+
|
|
294
|
+
current_version = CURRENT_SPECIFICATION_VERSION
|
|
295
|
+
|
|
296
|
+
field_count = if spec.specification_version > current_version then
|
|
297
|
+
spec.instance_variable_set :@specification_version,
|
|
298
|
+
current_version
|
|
299
|
+
MARSHAL_FIELDS[current_version]
|
|
300
|
+
else
|
|
301
|
+
MARSHAL_FIELDS[spec.specification_version]
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
if array.size < field_count then
|
|
305
|
+
raise TypeError, "invalid LibGems::Specification format #{array.inspect}"
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
spec.instance_variable_set :@rubygems_version, array[0]
|
|
309
|
+
# spec version
|
|
310
|
+
spec.instance_variable_set :@name, array[2]
|
|
311
|
+
spec.instance_variable_set :@version, array[3]
|
|
312
|
+
spec.instance_variable_set :@date, array[4]
|
|
313
|
+
spec.instance_variable_set :@summary, array[5]
|
|
314
|
+
spec.instance_variable_set :@required_ruby_version, array[6]
|
|
315
|
+
spec.instance_variable_set :@required_rubygems_version, array[7]
|
|
316
|
+
spec.instance_variable_set :@original_platform, array[8]
|
|
317
|
+
spec.instance_variable_set :@dependencies, array[9]
|
|
318
|
+
spec.instance_variable_set :@rubyforge_project, array[10]
|
|
319
|
+
spec.instance_variable_set :@email, array[11]
|
|
320
|
+
spec.instance_variable_set :@authors, array[12]
|
|
321
|
+
spec.instance_variable_set :@description, array[13]
|
|
322
|
+
spec.instance_variable_set :@homepage, array[14]
|
|
323
|
+
spec.instance_variable_set :@has_rdoc, array[15]
|
|
324
|
+
spec.instance_variable_set :@new_platform, array[16]
|
|
325
|
+
spec.instance_variable_set :@platform, array[16].to_s
|
|
326
|
+
spec.instance_variable_set :@license, array[17]
|
|
327
|
+
spec.instance_variable_set :@loaded, false
|
|
328
|
+
|
|
329
|
+
spec
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
##
|
|
333
|
+
# List of depedencies that will automatically be activated at runtime.
|
|
334
|
+
|
|
335
|
+
def runtime_dependencies
|
|
336
|
+
dependencies.select { |d| d.type == :runtime || d.type == nil }
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
##
|
|
340
|
+
# List of dependencies that are used for development
|
|
341
|
+
|
|
342
|
+
def development_dependencies
|
|
343
|
+
dependencies.select { |d| d.type == :development }
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def test_suite_file # :nodoc:
|
|
347
|
+
warn 'test_suite_file deprecated, use test_files'
|
|
348
|
+
test_files.first
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def test_suite_file=(val) # :nodoc:
|
|
352
|
+
warn 'test_suite_file= deprecated, use test_files='
|
|
353
|
+
@test_files = [] unless defined? @test_files
|
|
354
|
+
@test_files << val
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
##
|
|
358
|
+
# true when this gemspec has been loaded from a specifications directory.
|
|
359
|
+
# This attribute is not persisted.
|
|
360
|
+
|
|
361
|
+
attr_accessor :loaded
|
|
362
|
+
|
|
363
|
+
##
|
|
364
|
+
# Path this gemspec was loaded from. This attribute is not persisted.
|
|
365
|
+
|
|
366
|
+
attr_accessor :loaded_from
|
|
367
|
+
|
|
368
|
+
##
|
|
369
|
+
# Returns an array with bindir attached to each executable in the
|
|
370
|
+
# executables list
|
|
371
|
+
|
|
372
|
+
def add_bindir(executables)
|
|
373
|
+
return nil if executables.nil?
|
|
374
|
+
|
|
375
|
+
if @bindir then
|
|
376
|
+
Array(executables).map { |e| File.join(@bindir, e) }
|
|
377
|
+
else
|
|
378
|
+
executables
|
|
379
|
+
end
|
|
380
|
+
rescue
|
|
381
|
+
return nil
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
##
|
|
385
|
+
# Files in the LibGems under one of the require_paths
|
|
386
|
+
|
|
387
|
+
def lib_files
|
|
388
|
+
@files.select do |file|
|
|
389
|
+
require_paths.any? do |path|
|
|
390
|
+
file.index(path) == 0
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
##
|
|
396
|
+
# True if this gem was loaded from disk
|
|
397
|
+
|
|
398
|
+
alias :loaded? :loaded
|
|
399
|
+
|
|
400
|
+
##
|
|
401
|
+
# True if this gem has files in test_files
|
|
402
|
+
|
|
403
|
+
def has_unit_tests?
|
|
404
|
+
not test_files.empty?
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# :stopdoc:
|
|
408
|
+
alias has_test_suite? has_unit_tests?
|
|
409
|
+
# :startdoc:
|
|
410
|
+
|
|
411
|
+
##
|
|
412
|
+
# Specification constructor. Assigns the default values to the
|
|
413
|
+
# attributes and yields itself for further
|
|
414
|
+
# initialization. Optionally takes +name+ and +version+.
|
|
415
|
+
|
|
416
|
+
def initialize name = nil, version = nil
|
|
417
|
+
@new_platform = nil
|
|
418
|
+
assign_defaults
|
|
419
|
+
@loaded = false
|
|
420
|
+
@loaded_from = nil
|
|
421
|
+
|
|
422
|
+
self.name = name if name
|
|
423
|
+
self.version = version if version
|
|
424
|
+
|
|
425
|
+
yield self if block_given?
|
|
426
|
+
|
|
427
|
+
@@gather.call(self) if @@gather
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
##
|
|
431
|
+
# Duplicates array_attributes from +other_spec+ so state isn't shared.
|
|
432
|
+
|
|
433
|
+
def initialize_copy(other_spec)
|
|
434
|
+
other_ivars = other_spec.instance_variables
|
|
435
|
+
other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9
|
|
436
|
+
other_ivars.any? { |ivar| String === ivar }
|
|
437
|
+
|
|
438
|
+
self.class.array_attributes.each do |name|
|
|
439
|
+
name = :"@#{name}"
|
|
440
|
+
next unless other_ivars.include? name
|
|
441
|
+
instance_variable_set name, other_spec.instance_variable_get(name).dup
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
##
|
|
446
|
+
# Each attribute has a default value (possibly nil). Here, we initialize
|
|
447
|
+
# all attributes to their default value. This is done through the
|
|
448
|
+
# accessor methods, so special behaviours will be honored. Furthermore,
|
|
449
|
+
# we take a _copy_ of the default so each specification instance has its
|
|
450
|
+
# own empty arrays, etc.
|
|
451
|
+
|
|
452
|
+
def assign_defaults
|
|
453
|
+
@@nil_attributes.each do |name|
|
|
454
|
+
instance_variable_set name, nil
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
@@non_nil_attributes.each do |name, default|
|
|
458
|
+
value = case default
|
|
459
|
+
when Time, Numeric, Symbol, true, false, nil then default
|
|
460
|
+
else default.dup
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
instance_variable_set name, value
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# HACK
|
|
467
|
+
instance_variable_set :@new_platform, LibGems::Platform::RUBY
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
##
|
|
471
|
+
# Special loader for YAML files. When a Specification object is loaded
|
|
472
|
+
# from a YAML file, it bypasses the normal Ruby object initialization
|
|
473
|
+
# routine (#initialize). This method makes up for that and deals with
|
|
474
|
+
# gems of different ages.
|
|
475
|
+
#
|
|
476
|
+
# 'input' can be anything that YAML.load() accepts: String or IO.
|
|
477
|
+
|
|
478
|
+
def self.from_yaml(input)
|
|
479
|
+
input = normalize_yaml_input input
|
|
480
|
+
spec = LibGems.with_rubygems_compat{ YAML.load input }
|
|
481
|
+
|
|
482
|
+
if spec && spec.class == FalseClass then
|
|
483
|
+
raise LibGems::EndOfYAMLException
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
unless LibGems::Specification === spec then
|
|
487
|
+
raise LibGems::Exception, "YAML data doesn't evaluate to gem specification"
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
unless (spec.instance_variables.include? '@specification_version' or
|
|
491
|
+
spec.instance_variables.include? :@specification_version) and
|
|
492
|
+
spec.instance_variable_get :@specification_version
|
|
493
|
+
spec.instance_variable_set :@specification_version,
|
|
494
|
+
NONEXISTENT_SPECIFICATION_VERSION
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
spec
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
##
|
|
501
|
+
# Loads ruby format gemspec from +filename+
|
|
502
|
+
|
|
503
|
+
def self.load(filename)
|
|
504
|
+
gemspec = nil
|
|
505
|
+
raise "NESTED Specification.load calls not allowed!" if @@gather
|
|
506
|
+
@@gather = proc { |gs| gemspec = gs }
|
|
507
|
+
data = File.read filename
|
|
508
|
+
LibGems.gemspec_eval(data, nil, filename)
|
|
509
|
+
gemspec
|
|
510
|
+
ensure
|
|
511
|
+
@@gather = nil
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
##
|
|
515
|
+
# Make sure the YAML specification is properly formatted with dashes
|
|
516
|
+
|
|
517
|
+
def self.normalize_yaml_input(input)
|
|
518
|
+
result = input.respond_to?(:read) ? input.read : input
|
|
519
|
+
result = "--- " + result unless result =~ /\A--- /
|
|
520
|
+
result.gsub(/ !!null \n/, " \n")
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
##
|
|
524
|
+
# Sets the rubygems_version to the current SlimGems version
|
|
525
|
+
|
|
526
|
+
def mark_version
|
|
527
|
+
@rubygems_version = LibGems::GEM_VERSION
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
##
|
|
531
|
+
# Ignore unknown attributes while loading
|
|
532
|
+
|
|
533
|
+
def method_missing(sym, *a, &b) # :nodoc:
|
|
534
|
+
if @specification_version > CURRENT_SPECIFICATION_VERSION and
|
|
535
|
+
sym.to_s =~ /=$/ then
|
|
536
|
+
warn "ignoring #{sym} loading #{full_name}" if $DEBUG
|
|
537
|
+
else
|
|
538
|
+
super
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
##
|
|
543
|
+
# Adds a development dependency named +gem+ with +requirements+ to this
|
|
544
|
+
# LibGems. For example:
|
|
545
|
+
#
|
|
546
|
+
# spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
|
|
547
|
+
#
|
|
548
|
+
# Development dependencies aren't installed by default and aren't
|
|
549
|
+
# activated when a gem is required.
|
|
550
|
+
|
|
551
|
+
def add_development_dependency(gem, *requirements)
|
|
552
|
+
add_dependency_with_type(gem, :development, *requirements)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
##
|
|
556
|
+
# Adds a runtime dependency named +gem+ with +requirements+ to this LibGems.
|
|
557
|
+
# For example:
|
|
558
|
+
#
|
|
559
|
+
# spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
|
|
560
|
+
|
|
561
|
+
def add_runtime_dependency(gem, *requirements)
|
|
562
|
+
add_dependency_with_type(gem, :runtime, *requirements)
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
##
|
|
566
|
+
# Adds a runtime dependency
|
|
567
|
+
|
|
568
|
+
alias add_dependency add_runtime_dependency
|
|
569
|
+
|
|
570
|
+
##
|
|
571
|
+
# Returns the full name (name-version) of this LibGems. Platform information
|
|
572
|
+
# is included (name-version-platform) if it is specified and not the
|
|
573
|
+
# default Ruby platform.
|
|
574
|
+
|
|
575
|
+
def full_name
|
|
576
|
+
if platform == LibGems::Platform::RUBY or platform.nil? then
|
|
577
|
+
"#{@name}-#{@version}"
|
|
578
|
+
else
|
|
579
|
+
"#{@name}-#{@version}-#{platform}"
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
##
|
|
584
|
+
# Returns the full name (name-version) of this gemspec using the original
|
|
585
|
+
# platform. For use with legacy gems.
|
|
586
|
+
|
|
587
|
+
def original_name # :nodoc:
|
|
588
|
+
if platform == LibGems::Platform::RUBY or platform.nil? then
|
|
589
|
+
"#{@name}-#{@version}"
|
|
590
|
+
else
|
|
591
|
+
"#{@name}-#{@version}-#{@original_platform}"
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
##
|
|
596
|
+
# The full path to the gem (install path + full name).
|
|
597
|
+
|
|
598
|
+
def full_gem_path
|
|
599
|
+
path = File.join installation_path, 'gems', full_name
|
|
600
|
+
return path if File.directory? path
|
|
601
|
+
File.join installation_path, 'gems', original_name
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
##
|
|
605
|
+
# The default (generated) file name of the gem. See also #spec_name.
|
|
606
|
+
#
|
|
607
|
+
# spec.file_name # => "example-1.0.gem"
|
|
608
|
+
|
|
609
|
+
def file_name
|
|
610
|
+
full_name + '.gem'
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
##
|
|
614
|
+
# The directory that this gem was installed into.
|
|
615
|
+
|
|
616
|
+
def installation_path
|
|
617
|
+
unless @loaded_from then
|
|
618
|
+
raise LibGems::Exception, "spec #{full_name} is not from an installed gem"
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
File.expand_path File.dirname(File.dirname(@loaded_from))
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
##
|
|
625
|
+
# Checks if this specification meets the requirement of +dependency+.
|
|
626
|
+
|
|
627
|
+
def satisfies_requirement?(dependency)
|
|
628
|
+
return @name == dependency.name &&
|
|
629
|
+
dependency.requirement.satisfied_by?(@version)
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
##
|
|
633
|
+
# Returns an object you can use to sort specifications in #sort_by.
|
|
634
|
+
|
|
635
|
+
def sort_obj
|
|
636
|
+
[@name, @version, @new_platform == LibGems::Platform::RUBY ? -1 : 1]
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
##
|
|
640
|
+
# The default name of the gemspec. See also #file_name
|
|
641
|
+
#
|
|
642
|
+
# spec.spec_name # => "example-1.0.gemspec"
|
|
643
|
+
|
|
644
|
+
def spec_name
|
|
645
|
+
full_name + '.gemspec'
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def <=>(other) # :nodoc:
|
|
649
|
+
sort_obj <=> other.sort_obj
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
##
|
|
653
|
+
# Tests specs for equality (across all attributes).
|
|
654
|
+
|
|
655
|
+
def ==(other) # :nodoc:
|
|
656
|
+
self.class === other && same_attributes?(other)
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
alias eql? == # :nodoc:
|
|
660
|
+
|
|
661
|
+
##
|
|
662
|
+
# True if this gem has the same attributes as +other+.
|
|
663
|
+
|
|
664
|
+
def same_attributes?(other)
|
|
665
|
+
@@attributes.each do |name, default|
|
|
666
|
+
return false unless self.send(name) == other.send(name)
|
|
667
|
+
end
|
|
668
|
+
true
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
private :same_attributes?
|
|
672
|
+
|
|
673
|
+
def hash # :nodoc:
|
|
674
|
+
@@attributes.inject(0) { |hash_code, (name, default_value)|
|
|
675
|
+
hash_code ^ self.send(name).hash
|
|
676
|
+
}
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
def encode_with coder # :nodoc:
|
|
680
|
+
mark_version
|
|
681
|
+
|
|
682
|
+
attributes = @@attributes.map { |name,| name.to_s }.sort
|
|
683
|
+
attributes = attributes - %w[name version platform]
|
|
684
|
+
|
|
685
|
+
coder.add 'name', @name
|
|
686
|
+
coder.add 'version', @version
|
|
687
|
+
platform = case @original_platform
|
|
688
|
+
when nil, '' then
|
|
689
|
+
'ruby'
|
|
690
|
+
when String then
|
|
691
|
+
@original_platform
|
|
692
|
+
else
|
|
693
|
+
@original_platform.to_s
|
|
694
|
+
end
|
|
695
|
+
coder.add 'platform', platform
|
|
696
|
+
|
|
697
|
+
attributes.each do |name|
|
|
698
|
+
coder.add name, instance_variable_get("@#{name}")
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def to_yaml(opts = {}) # :nodoc:
|
|
703
|
+
if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then
|
|
704
|
+
super.gsub(/ !!null \n/, " \n")
|
|
705
|
+
else
|
|
706
|
+
YAML.quick_emit object_id, opts do |out|
|
|
707
|
+
out.map taguri, to_yaml_style do |map|
|
|
708
|
+
encode_with map
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def init_with coder # :nodoc:
|
|
715
|
+
yaml_initialize coder.tag, coder.map
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
def yaml_initialize(tag, vals) # :nodoc:
|
|
719
|
+
vals.each do |ivar, val|
|
|
720
|
+
instance_variable_set "@#{ivar}", val
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
@original_platform = @platform # for backwards compatibility
|
|
724
|
+
self.platform = LibGems::Platform.new @platform
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
##
|
|
728
|
+
# Returns a Ruby code representation of this specification, such that it
|
|
729
|
+
# can be eval'ed and reconstruct the same specification later. Attributes
|
|
730
|
+
# that still have their default values are omitted.
|
|
731
|
+
|
|
732
|
+
def to_ruby
|
|
733
|
+
mark_version
|
|
734
|
+
result = []
|
|
735
|
+
result << "# -*- encoding: utf-8 -*-"
|
|
736
|
+
result << nil
|
|
737
|
+
result << "LibGems::Specification.new do |s|"
|
|
738
|
+
|
|
739
|
+
result << " s.name = #{ruby_code name}"
|
|
740
|
+
result << " s.version = #{ruby_code version}"
|
|
741
|
+
unless platform.nil? or platform == LibGems::Platform::RUBY then
|
|
742
|
+
result << " s.platform = #{ruby_code original_platform}"
|
|
743
|
+
end
|
|
744
|
+
result << ""
|
|
745
|
+
result << " s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
|
|
746
|
+
|
|
747
|
+
handled = [
|
|
748
|
+
:dependencies,
|
|
749
|
+
:name,
|
|
750
|
+
:platform,
|
|
751
|
+
:required_rubygems_version,
|
|
752
|
+
:specification_version,
|
|
753
|
+
:version,
|
|
754
|
+
]
|
|
755
|
+
|
|
756
|
+
attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
|
|
757
|
+
|
|
758
|
+
attributes.each do |attr_name, default|
|
|
759
|
+
next if handled.include? attr_name
|
|
760
|
+
current_value = self.send(attr_name)
|
|
761
|
+
if current_value != default or
|
|
762
|
+
self.class.required_attribute? attr_name then
|
|
763
|
+
result << " s.#{attr_name} = #{ruby_code current_value}"
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
result << nil
|
|
768
|
+
result << " if s.respond_to? :specification_version then"
|
|
769
|
+
result << " s.specification_version = #{specification_version}"
|
|
770
|
+
result << nil
|
|
771
|
+
|
|
772
|
+
result << " if LibGems::Version.new(LibGems::GEM_VERSION) >= LibGems::Version.new('1.2.0') then"
|
|
773
|
+
|
|
774
|
+
unless dependencies.empty? then
|
|
775
|
+
dependencies.each do |dep|
|
|
776
|
+
version_reqs_param = dep.requirements_list.inspect
|
|
777
|
+
dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
|
|
778
|
+
result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
result << " else"
|
|
783
|
+
|
|
784
|
+
unless dependencies.empty? then
|
|
785
|
+
dependencies.each do |dep|
|
|
786
|
+
version_reqs_param = dep.requirements_list.inspect
|
|
787
|
+
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
result << ' end'
|
|
792
|
+
|
|
793
|
+
result << " else"
|
|
794
|
+
dependencies.each do |dep|
|
|
795
|
+
version_reqs_param = dep.requirements_list.inspect
|
|
796
|
+
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
|
|
797
|
+
end
|
|
798
|
+
result << " end"
|
|
799
|
+
|
|
800
|
+
result << "end"
|
|
801
|
+
result << nil
|
|
802
|
+
|
|
803
|
+
result.join "\n"
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
##
|
|
807
|
+
# Checks that the specification contains all required fields, and does a
|
|
808
|
+
# very basic sanity check.
|
|
809
|
+
#
|
|
810
|
+
# Raises InvalidSpecificationException if the spec does not pass the
|
|
811
|
+
# checks..
|
|
812
|
+
|
|
813
|
+
def validate
|
|
814
|
+
extend LibGems::UserInteraction
|
|
815
|
+
normalize
|
|
816
|
+
|
|
817
|
+
# TODO: Fix the versioning here
|
|
818
|
+
if rubygems_version != LibGems::GEM_VERSION then
|
|
819
|
+
raise LibGems::InvalidSpecificationException,
|
|
820
|
+
"expected RubyGems version #{LibGems::GEM_VERSION}, was #{rubygems_version}"
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
@@required_attributes.each do |symbol|
|
|
824
|
+
unless self.send symbol then
|
|
825
|
+
raise LibGems::InvalidSpecificationException,
|
|
826
|
+
"missing value for attribute #{symbol}"
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
unless String === name then
|
|
831
|
+
raise LibGems::InvalidSpecificationException,
|
|
832
|
+
"invalid value for attribute name: \"#{name.inspect}\""
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
if require_paths.empty? then
|
|
836
|
+
raise LibGems::InvalidSpecificationException,
|
|
837
|
+
'specification must have at least one require_path'
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
@files.delete_if do |file| File.directory? file end
|
|
841
|
+
@test_files.delete_if do |file| File.directory? file end
|
|
842
|
+
@executables.delete_if do |file|
|
|
843
|
+
File.directory? File.join(bindir, file)
|
|
844
|
+
end
|
|
845
|
+
@extra_rdoc_files.delete_if do |file| File.directory? file end
|
|
846
|
+
@extensions.delete_if do |file| File.directory? file end
|
|
847
|
+
|
|
848
|
+
non_files = files.select do |file|
|
|
849
|
+
!File.file? file
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
unless non_files.empty? then
|
|
853
|
+
non_files = non_files.map { |file| file.inspect }
|
|
854
|
+
raise LibGems::InvalidSpecificationException,
|
|
855
|
+
"[#{non_files.join ", "}] are not files"
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
unless specification_version.is_a?(Fixnum)
|
|
859
|
+
raise LibGems::InvalidSpecificationException,
|
|
860
|
+
'specification_version must be a Fixnum (did you mean version?)'
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
case platform
|
|
864
|
+
when LibGems::Platform, LibGems::Platform::RUBY then # ok
|
|
865
|
+
else
|
|
866
|
+
raise LibGems::InvalidSpecificationException,
|
|
867
|
+
"invalid platform #{platform.inspect}, see LibGems::Platform"
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
unless Array === authors and
|
|
871
|
+
authors.all? { |author| String === author } then
|
|
872
|
+
raise LibGems::InvalidSpecificationException,
|
|
873
|
+
'authors must be Array of Strings'
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
licenses.each { |license|
|
|
877
|
+
if license.length > 64
|
|
878
|
+
raise LibGems::InvalidSpecificationException,
|
|
879
|
+
"each license must be 64 characters or less"
|
|
880
|
+
end
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
# reject FIXME and TODO
|
|
884
|
+
|
|
885
|
+
unless authors.grep(/FIXME|TODO/).empty? then
|
|
886
|
+
raise LibGems::InvalidSpecificationException,
|
|
887
|
+
'"FIXME" or "TODO" is not an author'
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
unless Array(email).grep(/FIXME|TODO/).empty? then
|
|
891
|
+
raise LibGems::InvalidSpecificationException,
|
|
892
|
+
'"FIXME" or "TODO" is not an email address'
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
if description =~ /FIXME|TODO/ then
|
|
896
|
+
raise LibGems::InvalidSpecificationException,
|
|
897
|
+
'"FIXME" or "TODO" is not a description'
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
if summary =~ /FIXME|TODO/ then
|
|
901
|
+
raise LibGems::InvalidSpecificationException,
|
|
902
|
+
'"FIXME" or "TODO" is not a summary'
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
if homepage and not homepage.empty? and
|
|
906
|
+
homepage !~ /\A[a-z][a-z\d+.-]*:/i then
|
|
907
|
+
raise LibGems::InvalidSpecificationException,
|
|
908
|
+
"\"#{homepage}\" is not a URI"
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
# Warnings
|
|
912
|
+
|
|
913
|
+
%w[author description email homepage summary].each do |attribute|
|
|
914
|
+
value = self.send attribute
|
|
915
|
+
alert_warning "no #{attribute} specified" if value.nil? or value.empty?
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
if summary and not summary.empty? and description == summary then
|
|
919
|
+
alert_warning 'description and summary are identical'
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
alert_warning "deprecated autorequire specified" if autorequire
|
|
923
|
+
|
|
924
|
+
executables.each do |executable|
|
|
925
|
+
executable_path = File.join bindir, executable
|
|
926
|
+
shebang = File.read(executable_path, 2) == '#!'
|
|
927
|
+
|
|
928
|
+
alert_warning "#{executable_path} is missing #! line" unless shebang
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
true
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
##
|
|
935
|
+
# Normalize the list of files so that:
|
|
936
|
+
# * All file lists have redundancies removed.
|
|
937
|
+
# * Files referenced in the extra_rdoc_files are included in the package
|
|
938
|
+
# file list.
|
|
939
|
+
|
|
940
|
+
def normalize
|
|
941
|
+
if defined?(@extra_rdoc_files) and @extra_rdoc_files then
|
|
942
|
+
@extra_rdoc_files.uniq!
|
|
943
|
+
@files ||= []
|
|
944
|
+
@files.concat(@extra_rdoc_files)
|
|
945
|
+
end
|
|
946
|
+
@files.uniq! if @files
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
##
|
|
950
|
+
# Return a list of all gems that have a dependency on this gemspec. The
|
|
951
|
+
# list is structured with entries that conform to:
|
|
952
|
+
#
|
|
953
|
+
# [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
|
|
954
|
+
|
|
955
|
+
def dependent_gems
|
|
956
|
+
out = []
|
|
957
|
+
LibGems.source_index.each do |name,gem|
|
|
958
|
+
gem.dependencies.each do |dep|
|
|
959
|
+
if self.satisfies_requirement?(dep) then
|
|
960
|
+
sats = []
|
|
961
|
+
find_all_satisfiers(dep) do |sat|
|
|
962
|
+
sats << sat
|
|
963
|
+
end
|
|
964
|
+
out << [gem, dep, sats]
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
out
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def to_s # :nodoc:
|
|
972
|
+
"#<LibGems::Specification name=#{@name} version=#{@version}>"
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def pretty_print(q) # :nodoc:
|
|
976
|
+
q.group 2, 'LibGems::Specification.new do |s|', 'end' do
|
|
977
|
+
q.breakable
|
|
978
|
+
|
|
979
|
+
attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
|
|
980
|
+
|
|
981
|
+
attributes.each do |attr_name, default|
|
|
982
|
+
current_value = self.send attr_name
|
|
983
|
+
if current_value != default or
|
|
984
|
+
self.class.required_attribute? attr_name then
|
|
985
|
+
|
|
986
|
+
q.text "s.#{attr_name} = "
|
|
987
|
+
|
|
988
|
+
if attr_name == :date then
|
|
989
|
+
current_value = current_value.utc
|
|
990
|
+
|
|
991
|
+
q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
|
|
992
|
+
else
|
|
993
|
+
q.pp current_value
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
q.breakable
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
end
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
##
|
|
1003
|
+
# Adds a dependency on gem +dependency+ with type +type+ that requires
|
|
1004
|
+
# +requirements+. Valid types are currently <tt>:runtime</tt> and
|
|
1005
|
+
# <tt>:development</tt>.
|
|
1006
|
+
|
|
1007
|
+
def add_dependency_with_type(dependency, type, *requirements)
|
|
1008
|
+
requirements = if requirements.empty? then
|
|
1009
|
+
LibGems::Requirement.default
|
|
1010
|
+
else
|
|
1011
|
+
requirements.flatten
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
unless dependency.respond_to?(:name) &&
|
|
1015
|
+
dependency.respond_to?(:version_requirements)
|
|
1016
|
+
|
|
1017
|
+
dependency = LibGems::Dependency.new(dependency, requirements, type)
|
|
1018
|
+
end
|
|
1019
|
+
|
|
1020
|
+
dependencies << dependency
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
private :add_dependency_with_type
|
|
1024
|
+
|
|
1025
|
+
##
|
|
1026
|
+
# Finds all gems that satisfy +dep+
|
|
1027
|
+
|
|
1028
|
+
def find_all_satisfiers(dep)
|
|
1029
|
+
LibGems.source_index.each do |_, gem|
|
|
1030
|
+
yield gem if gem.satisfies_requirement? dep
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
private :find_all_satisfiers
|
|
1035
|
+
|
|
1036
|
+
##
|
|
1037
|
+
# Return a string containing a Ruby code representation of the given
|
|
1038
|
+
# object.
|
|
1039
|
+
|
|
1040
|
+
def ruby_code(obj)
|
|
1041
|
+
case obj
|
|
1042
|
+
when String then '%q{' + obj + '}'
|
|
1043
|
+
when Array then obj.inspect
|
|
1044
|
+
when LibGems::Version then obj.to_s.inspect
|
|
1045
|
+
when Date then '%q{' + obj.strftime('%Y-%m-%d') + '}'
|
|
1046
|
+
when Time then '%q{' + obj.strftime('%Y-%m-%d') + '}'
|
|
1047
|
+
when Numeric then obj.inspect
|
|
1048
|
+
when true, false, nil then obj.inspect
|
|
1049
|
+
when LibGems::Platform then "LibGems::Platform.new(#{obj.to_a.inspect})"
|
|
1050
|
+
when LibGems::Requirement then "LibGems::Requirement.new(#{obj.to_s.inspect})"
|
|
1051
|
+
else raise LibGems::Exception, "ruby_code case not handled: #{obj.class}"
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
private :ruby_code
|
|
1056
|
+
|
|
1057
|
+
# :section: Required gemspec attributes
|
|
1058
|
+
|
|
1059
|
+
##
|
|
1060
|
+
# :attr_accessor: rubygems_version
|
|
1061
|
+
#
|
|
1062
|
+
# The version of SlimGems used to create this gem.
|
|
1063
|
+
#
|
|
1064
|
+
# Do not set this, it is set automatically when the gem is packaged.
|
|
1065
|
+
|
|
1066
|
+
required_attribute :rubygems_version, LibGems::GEM_VERSION
|
|
1067
|
+
|
|
1068
|
+
##
|
|
1069
|
+
# :attr_accessor: specification_version
|
|
1070
|
+
#
|
|
1071
|
+
# The LibGems::Specification version of this gemspec.
|
|
1072
|
+
#
|
|
1073
|
+
# Do not set this, it is set automatically when the gem is packaged.
|
|
1074
|
+
|
|
1075
|
+
required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
|
|
1076
|
+
|
|
1077
|
+
##
|
|
1078
|
+
# :attr_accessor: name
|
|
1079
|
+
#
|
|
1080
|
+
# This gem's name
|
|
1081
|
+
|
|
1082
|
+
required_attribute :name
|
|
1083
|
+
|
|
1084
|
+
##
|
|
1085
|
+
# :attr_accessor: version
|
|
1086
|
+
#
|
|
1087
|
+
# This gem's version
|
|
1088
|
+
|
|
1089
|
+
required_attribute :version
|
|
1090
|
+
|
|
1091
|
+
##
|
|
1092
|
+
# :attr_accessor: date
|
|
1093
|
+
#
|
|
1094
|
+
# The date this gem was created
|
|
1095
|
+
#
|
|
1096
|
+
# Do not set this, it is set automatically when the gem is packaged.
|
|
1097
|
+
|
|
1098
|
+
required_attribute :date, TODAY
|
|
1099
|
+
|
|
1100
|
+
##
|
|
1101
|
+
# :attr_accessor: summary
|
|
1102
|
+
#
|
|
1103
|
+
# A short summary of this gem's description. Displayed in `gem list -d`.
|
|
1104
|
+
#
|
|
1105
|
+
# The description should be more detailed than the summary. For example,
|
|
1106
|
+
# you might wish to copy the entire README into the description.
|
|
1107
|
+
#
|
|
1108
|
+
# As of SlimGems 1.3.2 newlines are no longer stripped.
|
|
1109
|
+
|
|
1110
|
+
required_attribute :summary
|
|
1111
|
+
|
|
1112
|
+
##
|
|
1113
|
+
# :attr_accessor: require_paths
|
|
1114
|
+
#
|
|
1115
|
+
# Paths in the gem to add to $LOAD_PATH when this gem is activated.
|
|
1116
|
+
#
|
|
1117
|
+
# The default 'lib' is typically sufficient.
|
|
1118
|
+
|
|
1119
|
+
required_attribute :require_paths, ['lib']
|
|
1120
|
+
|
|
1121
|
+
# :section: Optional gemspec attributes
|
|
1122
|
+
|
|
1123
|
+
##
|
|
1124
|
+
# :attr_accessor: email
|
|
1125
|
+
#
|
|
1126
|
+
# A contact email for this gem
|
|
1127
|
+
#
|
|
1128
|
+
# If you are providing multiple authors and multiple emails they should be
|
|
1129
|
+
# in the same order such that:
|
|
1130
|
+
#
|
|
1131
|
+
# Hash[*spec.authors.zip(spec.emails).flatten]
|
|
1132
|
+
#
|
|
1133
|
+
# Gives a hash of author name to email address.
|
|
1134
|
+
|
|
1135
|
+
attribute :email
|
|
1136
|
+
|
|
1137
|
+
##
|
|
1138
|
+
# :attr_accessor: homepage
|
|
1139
|
+
#
|
|
1140
|
+
# The URL of this gem's home page
|
|
1141
|
+
|
|
1142
|
+
attribute :homepage
|
|
1143
|
+
|
|
1144
|
+
##
|
|
1145
|
+
# :attr_accessor: rubyforge_project
|
|
1146
|
+
#
|
|
1147
|
+
# The rubyforge project this gem lives under. i.e. SlimGems'
|
|
1148
|
+
# rubyforge_project is "libgems".
|
|
1149
|
+
|
|
1150
|
+
attribute :rubyforge_project
|
|
1151
|
+
|
|
1152
|
+
##
|
|
1153
|
+
# :attr_accessor: description
|
|
1154
|
+
#
|
|
1155
|
+
# A long description of this gem
|
|
1156
|
+
|
|
1157
|
+
attribute :description
|
|
1158
|
+
|
|
1159
|
+
##
|
|
1160
|
+
# :attr_accessor: autorequire
|
|
1161
|
+
#
|
|
1162
|
+
# Autorequire was used by old SlimGems to automatically require a file.
|
|
1163
|
+
# It no longer is supported.
|
|
1164
|
+
|
|
1165
|
+
attribute :autorequire
|
|
1166
|
+
|
|
1167
|
+
##
|
|
1168
|
+
# :attr_accessor: default_executable
|
|
1169
|
+
#
|
|
1170
|
+
# The default executable for this gem.
|
|
1171
|
+
#
|
|
1172
|
+
# This is not used.
|
|
1173
|
+
|
|
1174
|
+
attribute :default_executable
|
|
1175
|
+
|
|
1176
|
+
##
|
|
1177
|
+
# :attr_accessor: bindir
|
|
1178
|
+
#
|
|
1179
|
+
# The path in the gem for executable scripts
|
|
1180
|
+
|
|
1181
|
+
attribute :bindir, 'bin'
|
|
1182
|
+
|
|
1183
|
+
##
|
|
1184
|
+
# :attr_accessor: has_rdoc
|
|
1185
|
+
#
|
|
1186
|
+
# Indicates that this gem is RDoc-capable.
|
|
1187
|
+
|
|
1188
|
+
attribute :has_rdoc, true
|
|
1189
|
+
|
|
1190
|
+
##
|
|
1191
|
+
# True if this gem supports RDoc
|
|
1192
|
+
|
|
1193
|
+
alias :has_rdoc? :has_rdoc
|
|
1194
|
+
|
|
1195
|
+
##
|
|
1196
|
+
# :attr_accessor: required_ruby_version
|
|
1197
|
+
#
|
|
1198
|
+
# The version of ruby required by this gem
|
|
1199
|
+
|
|
1200
|
+
attribute :required_ruby_version, LibGems::Requirement.default
|
|
1201
|
+
|
|
1202
|
+
##
|
|
1203
|
+
# :attr_accessor: required_rubygems_version
|
|
1204
|
+
#
|
|
1205
|
+
# The SlimGems version required by this gem
|
|
1206
|
+
|
|
1207
|
+
attribute :required_rubygems_version, LibGems::Requirement.default
|
|
1208
|
+
|
|
1209
|
+
##
|
|
1210
|
+
# :attr_accessor: platform
|
|
1211
|
+
#
|
|
1212
|
+
# The platform this gem runs on. See LibGems::Platform for details.
|
|
1213
|
+
#
|
|
1214
|
+
# Setting this to any value other than LibGems::Platform::RUBY or
|
|
1215
|
+
# LibGems::Platform::CURRENT is probably wrong.
|
|
1216
|
+
|
|
1217
|
+
attribute :platform, LibGems::Platform::RUBY
|
|
1218
|
+
|
|
1219
|
+
##
|
|
1220
|
+
# :attr_accessor: signing_key
|
|
1221
|
+
#
|
|
1222
|
+
# The key used to sign this gem. See LibGems::Security for details.
|
|
1223
|
+
|
|
1224
|
+
attribute :signing_key, nil
|
|
1225
|
+
|
|
1226
|
+
##
|
|
1227
|
+
# :attr_accessor: cert_chain
|
|
1228
|
+
#
|
|
1229
|
+
# The certificate chain used to sign this gem. See LibGems::Security for
|
|
1230
|
+
# details.
|
|
1231
|
+
|
|
1232
|
+
attribute :cert_chain, []
|
|
1233
|
+
|
|
1234
|
+
##
|
|
1235
|
+
# :attr_accessor: post_install_message
|
|
1236
|
+
#
|
|
1237
|
+
# A message that gets displayed after the gem is installed
|
|
1238
|
+
|
|
1239
|
+
attribute :post_install_message, nil
|
|
1240
|
+
|
|
1241
|
+
##
|
|
1242
|
+
# :attr_accessor: authors
|
|
1243
|
+
#
|
|
1244
|
+
# The list of author names who wrote this gem.
|
|
1245
|
+
#
|
|
1246
|
+
# If you are providing multiple authors and multiple emails they should be
|
|
1247
|
+
# in the same order such that:
|
|
1248
|
+
#
|
|
1249
|
+
# Hash[*spec.authors.zip(spec.emails).flatten]
|
|
1250
|
+
#
|
|
1251
|
+
# Gives a hash of author name to email address.
|
|
1252
|
+
|
|
1253
|
+
array_attribute :authors
|
|
1254
|
+
|
|
1255
|
+
##
|
|
1256
|
+
# :attr_accessor: licenses
|
|
1257
|
+
#
|
|
1258
|
+
# The license(s) for the library. Each license must be a short name, no
|
|
1259
|
+
# more than 64 characters.
|
|
1260
|
+
|
|
1261
|
+
array_attribute :licenses
|
|
1262
|
+
|
|
1263
|
+
##
|
|
1264
|
+
# :attr_accessor: files
|
|
1265
|
+
#
|
|
1266
|
+
# Files included in this gem. You cannot append to this accessor, you must
|
|
1267
|
+
# assign to it.
|
|
1268
|
+
#
|
|
1269
|
+
# Only add files you can require to this list, not directories, etc.
|
|
1270
|
+
#
|
|
1271
|
+
# Directories are automatically stripped from this list when building a gem,
|
|
1272
|
+
# other non-files cause an error.
|
|
1273
|
+
|
|
1274
|
+
array_attribute :files
|
|
1275
|
+
|
|
1276
|
+
##
|
|
1277
|
+
# :attr_accessor: test_files
|
|
1278
|
+
#
|
|
1279
|
+
# Test files included in this gem. You cannot append to this accessor, you
|
|
1280
|
+
# must assign to it.
|
|
1281
|
+
|
|
1282
|
+
array_attribute :test_files
|
|
1283
|
+
|
|
1284
|
+
##
|
|
1285
|
+
# :attr_accessor: rdoc_options
|
|
1286
|
+
#
|
|
1287
|
+
# An ARGV style array of options to RDoc
|
|
1288
|
+
|
|
1289
|
+
array_attribute :rdoc_options
|
|
1290
|
+
|
|
1291
|
+
##
|
|
1292
|
+
# :attr_accessor: extra_rdoc_files
|
|
1293
|
+
#
|
|
1294
|
+
# Extra files to add to RDoc such as README or doc/examples.txt
|
|
1295
|
+
|
|
1296
|
+
array_attribute :extra_rdoc_files
|
|
1297
|
+
|
|
1298
|
+
##
|
|
1299
|
+
# :attr_accessor: executables
|
|
1300
|
+
#
|
|
1301
|
+
# Executables included in the gem.
|
|
1302
|
+
|
|
1303
|
+
array_attribute :executables
|
|
1304
|
+
|
|
1305
|
+
##
|
|
1306
|
+
# :attr_accessor: extensions
|
|
1307
|
+
#
|
|
1308
|
+
# Extensions to build when installing the gem. See
|
|
1309
|
+
# LibGems::Installer#build_extensions for valid values.
|
|
1310
|
+
|
|
1311
|
+
array_attribute :extensions
|
|
1312
|
+
|
|
1313
|
+
##
|
|
1314
|
+
# :attr_accessor: requirements
|
|
1315
|
+
#
|
|
1316
|
+
# An array or things required by this gem. Not used by anything
|
|
1317
|
+
# presently.
|
|
1318
|
+
|
|
1319
|
+
array_attribute :requirements
|
|
1320
|
+
|
|
1321
|
+
##
|
|
1322
|
+
# :attr_reader: dependencies
|
|
1323
|
+
#
|
|
1324
|
+
# A list of LibGems::Dependency objects this gem depends on.
|
|
1325
|
+
#
|
|
1326
|
+
# Use #add_dependency or #add_development_dependency to add dependencies to
|
|
1327
|
+
# a gem.
|
|
1328
|
+
|
|
1329
|
+
array_attribute :dependencies
|
|
1330
|
+
|
|
1331
|
+
read_only :dependencies
|
|
1332
|
+
|
|
1333
|
+
# :section: Aliased gemspec attributes
|
|
1334
|
+
|
|
1335
|
+
##
|
|
1336
|
+
# Singular accessor for #executables
|
|
1337
|
+
|
|
1338
|
+
attribute_alias_singular :executable, :executables
|
|
1339
|
+
|
|
1340
|
+
##
|
|
1341
|
+
# Singular accessor for #authors
|
|
1342
|
+
|
|
1343
|
+
attribute_alias_singular :author, :authors
|
|
1344
|
+
|
|
1345
|
+
##
|
|
1346
|
+
# Singular accessor for #licenses
|
|
1347
|
+
|
|
1348
|
+
attribute_alias_singular :license, :licenses
|
|
1349
|
+
|
|
1350
|
+
##
|
|
1351
|
+
# Singular accessor for #require_paths
|
|
1352
|
+
|
|
1353
|
+
attribute_alias_singular :require_path, :require_paths
|
|
1354
|
+
|
|
1355
|
+
##
|
|
1356
|
+
# Singular accessor for #test_files
|
|
1357
|
+
|
|
1358
|
+
attribute_alias_singular :test_file, :test_files
|
|
1359
|
+
|
|
1360
|
+
overwrite_accessor :version= do |version|
|
|
1361
|
+
@version = LibGems::Version.create(version)
|
|
1362
|
+
self.required_rubygems_version = '> 1.3.1' if @version.prerelease?
|
|
1363
|
+
return @version
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
overwrite_accessor :platform do
|
|
1367
|
+
@new_platform
|
|
1368
|
+
end
|
|
1369
|
+
|
|
1370
|
+
overwrite_accessor :platform= do |platform|
|
|
1371
|
+
if @original_platform.nil? or
|
|
1372
|
+
@original_platform == LibGems::Platform::RUBY then
|
|
1373
|
+
@original_platform = platform
|
|
1374
|
+
end
|
|
1375
|
+
|
|
1376
|
+
case platform
|
|
1377
|
+
when LibGems::Platform::CURRENT then
|
|
1378
|
+
@new_platform = LibGems::Platform.local
|
|
1379
|
+
@original_platform = @new_platform.to_s
|
|
1380
|
+
|
|
1381
|
+
when LibGems::Platform then
|
|
1382
|
+
@new_platform = platform
|
|
1383
|
+
|
|
1384
|
+
# legacy constants
|
|
1385
|
+
when nil, LibGems::Platform::RUBY then
|
|
1386
|
+
@new_platform = LibGems::Platform::RUBY
|
|
1387
|
+
when 'mswin32' then # was LibGems::Platform::WIN32
|
|
1388
|
+
@new_platform = LibGems::Platform.new 'x86-mswin32'
|
|
1389
|
+
when 'i586-linux' then # was LibGems::Platform::LINUX_586
|
|
1390
|
+
@new_platform = LibGems::Platform.new 'x86-linux'
|
|
1391
|
+
when 'powerpc-darwin' then # was LibGems::Platform::DARWIN
|
|
1392
|
+
@new_platform = LibGems::Platform.new 'ppc-darwin'
|
|
1393
|
+
else
|
|
1394
|
+
@new_platform = LibGems::Platform.new platform
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
@platform = @new_platform.to_s
|
|
1398
|
+
|
|
1399
|
+
@new_platform
|
|
1400
|
+
end
|
|
1401
|
+
|
|
1402
|
+
overwrite_accessor :required_ruby_version= do |value|
|
|
1403
|
+
@required_ruby_version = LibGems::Requirement.create(value)
|
|
1404
|
+
end
|
|
1405
|
+
|
|
1406
|
+
overwrite_accessor :required_rubygems_version= do |value|
|
|
1407
|
+
@required_rubygems_version = LibGems::Requirement.create(value)
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
overwrite_accessor :date= do |date|
|
|
1411
|
+
# We want to end up with a Time object with one-day resolution.
|
|
1412
|
+
# This is the cleanest, most-readable, faster-than-using-Date
|
|
1413
|
+
# way to do it.
|
|
1414
|
+
case date
|
|
1415
|
+
when String then
|
|
1416
|
+
@date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
|
|
1417
|
+
Time.local($1.to_i, $2.to_i, $3.to_i)
|
|
1418
|
+
else
|
|
1419
|
+
require 'time'
|
|
1420
|
+
Time.parse date
|
|
1421
|
+
end
|
|
1422
|
+
when Time then
|
|
1423
|
+
@date = Time.local(date.year, date.month, date.day)
|
|
1424
|
+
when Date then
|
|
1425
|
+
@date = Time.local(date.year, date.month, date.day)
|
|
1426
|
+
else
|
|
1427
|
+
@date = TODAY
|
|
1428
|
+
end
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
overwrite_accessor :date do
|
|
1432
|
+
self.date = nil if @date.nil? # HACK Sets the default value for date
|
|
1433
|
+
@date
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1436
|
+
overwrite_accessor :summary= do |str|
|
|
1437
|
+
@summary = if str then
|
|
1438
|
+
str.strip.
|
|
1439
|
+
gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
|
|
1440
|
+
gsub(/\n[ \t]*/, " ")
|
|
1441
|
+
end
|
|
1442
|
+
end
|
|
1443
|
+
|
|
1444
|
+
overwrite_accessor :description= do |str|
|
|
1445
|
+
@description = str.to_s
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
overwrite_accessor :default_executable do
|
|
1449
|
+
begin
|
|
1450
|
+
if defined?(@default_executable) and @default_executable
|
|
1451
|
+
result = @default_executable
|
|
1452
|
+
elsif @executables and @executables.size == 1
|
|
1453
|
+
result = Array(@executables).first
|
|
1454
|
+
else
|
|
1455
|
+
result = nil
|
|
1456
|
+
end
|
|
1457
|
+
result
|
|
1458
|
+
rescue
|
|
1459
|
+
nil
|
|
1460
|
+
end
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1463
|
+
overwrite_accessor :test_files do
|
|
1464
|
+
# Handle the possibility that we have @test_suite_file but not
|
|
1465
|
+
# @test_files. This will happen when an old gem is loaded via
|
|
1466
|
+
# YAML.
|
|
1467
|
+
if defined? @test_suite_file then
|
|
1468
|
+
@test_files = [@test_suite_file].flatten
|
|
1469
|
+
@test_suite_file = nil
|
|
1470
|
+
end
|
|
1471
|
+
if defined?(@test_files) and @test_files then
|
|
1472
|
+
@test_files
|
|
1473
|
+
else
|
|
1474
|
+
@test_files = []
|
|
1475
|
+
end
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
overwrite_accessor :files do
|
|
1479
|
+
# DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks)
|
|
1480
|
+
@files = [@files,
|
|
1481
|
+
@test_files,
|
|
1482
|
+
add_bindir(@executables),
|
|
1483
|
+
@extra_rdoc_files,
|
|
1484
|
+
@extensions,
|
|
1485
|
+
].flatten.uniq.compact
|
|
1486
|
+
end
|
|
1487
|
+
end
|