rubygems-update 0.8.3
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.
Potentially problematic release.
This version of rubygems-update might be problematic. Click here for more details.
- data/ChangeLog +2335 -0
- data/README +54 -0
- data/Rakefile +293 -0
- data/Releases +98 -0
- data/TODO +7 -0
- data/bin/gem +11 -0
- data/bin/gem_server +111 -0
- data/bin/generate_yaml_index.rb +58 -0
- data/bin/update_rubygems +18 -0
- data/doc/doc.css +73 -0
- data/doc/makedoc.rb +4 -0
- data/examples/application/an-app.gemspec +26 -0
- data/examples/application/bin/myapp +3 -0
- data/examples/application/lib/somefunctionality.rb +3 -0
- data/gemspecs/README +4 -0
- data/gemspecs/cgikit-1.1.0.gemspec +18 -0
- data/gemspecs/jabber4r.gemspec +26 -0
- data/gemspecs/linguistics.gemspec +22 -0
- data/gemspecs/ook.gemspec +21 -0
- data/gemspecs/progressbar.gemspec +22 -0
- data/gemspecs/redcloth.gemspec +22 -0
- data/gemspecs/rublog.gemspec +23 -0
- data/gemspecs/ruby-doom.gemspec +21 -0
- data/gemspecs/rubyjdwp.gemspec +21 -0
- data/gemspecs/statistics.gemspec +21 -0
- data/lib/rubygems.rb +353 -0
- data/lib/rubygems/builder.rb +54 -0
- data/lib/rubygems/cmd_manager.rb +127 -0
- data/lib/rubygems/command.rb +191 -0
- data/lib/rubygems/config_file.rb +57 -0
- data/lib/rubygems/doc_manager.rb +94 -0
- data/lib/rubygems/format.rb +65 -0
- data/lib/rubygems/gem_commands.rb +925 -0
- data/lib/rubygems/gem_runner.rb +23 -0
- data/lib/rubygems/installer.rb +621 -0
- data/lib/rubygems/loadpath_manager.rb +108 -0
- data/lib/rubygems/old_format.rb +150 -0
- data/lib/rubygems/open-uri.rb +604 -0
- data/lib/rubygems/package.rb +740 -0
- data/lib/rubygems/remote_installer.rb +499 -0
- data/lib/rubygems/rubygems_version.rb +6 -0
- data/lib/rubygems/source_index.rb +130 -0
- data/lib/rubygems/specification.rb +613 -0
- data/lib/rubygems/user_interaction.rb +176 -0
- data/lib/rubygems/validator.rb +148 -0
- data/lib/rubygems/version.rb +279 -0
- data/lib/ubygems.rb +4 -0
- data/pkgs/sources/lib/sources.rb +6 -0
- data/pkgs/sources/sources.gemspec +14 -0
- data/post-install.rb +75 -0
- data/redist/session.gem +433 -0
- data/scripts/buildtests.rb +25 -0
- data/scripts/gemdoc.rb +62 -0
- data/scripts/runtest.rb +17 -0
- data/scripts/specdoc.rb +164 -0
- data/setup.rb +1360 -0
- data/test/bogussources.rb +5 -0
- data/test/data/legacy/keyedlist-0.4.0.ruby +11 -0
- data/test/data/legacy/keyedlist-0.4.0.yaml +16 -0
- data/test/data/lib/code.rb +1 -0
- data/test/data/one/README.one +1 -0
- data/test/data/one/lib/one.rb +3 -0
- data/test/data/one/one.gemspec +17 -0
- data/test/data/one/one.yaml +40 -0
- data/test/functional.rb +145 -0
- data/test/gemenvironment.rb +45 -0
- data/test/gemutilities.rb +18 -0
- data/test/insure_session.rb +46 -0
- data/test/mock/gems/gems/sources-0.0.1/lib/sources.rb +5 -0
- data/test/mock/gems/specifications/sources-0.0.1.gemspec +8 -0
- data/test/mockgemui.rb +45 -0
- data/test/onegem.rb +23 -0
- data/test/simple_gem.rb +66 -0
- data/test/test_builder.rb +13 -0
- data/test/test_cached_fetcher.rb +60 -0
- data/test/test_check_command.rb +28 -0
- data/test/test_command.rb +130 -0
- data/test/test_configfile.rb +36 -0
- data/test/test_format.rb +70 -0
- data/test/test_gemloadpaths.rb +45 -0
- data/test/test_gempaths.rb +115 -0
- data/test/test_loadmanager.rb +40 -0
- data/test/test_local_cache.rb +157 -0
- data/test/test_package.rb +600 -0
- data/test/test_parse_commands.rb +179 -0
- data/test/test_process_commands.rb +21 -0
- data/test/test_remote_fetcher.rb +162 -0
- data/test/test_remote_installer.rb +154 -0
- data/test/test_source_index.rb +58 -0
- data/test/test_specification.rb +286 -0
- data/test/test_validator.rb +53 -0
- data/test/test_version_comparison.rb +204 -0
- data/test/testgem.rc +6 -0
- data/test/user_capture.rb +1 -0
- data/test/yaml_data.rb +59 -0
- metadata +151 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'rubygems/user_interaction'
|
2
|
+
module Gem
|
3
|
+
|
4
|
+
# The SourceIndex object indexes all the gems available from a
|
5
|
+
# particular source (e.g. a list of gem directories, or a remote
|
6
|
+
# source). A SourceIndex maps a gem full name to a gem
|
7
|
+
# specification.
|
8
|
+
#
|
9
|
+
# NOTE:: The class used to be named Cache, but that became
|
10
|
+
# confusing when cached source fetchers where introduced.
|
11
|
+
# The constant Gem::Cache is an alias for this class to allow
|
12
|
+
# old YAMLized source index objects to load properly.
|
13
|
+
#
|
14
|
+
class SourceIndex
|
15
|
+
class << self
|
16
|
+
include Gem::UserInteraction
|
17
|
+
end
|
18
|
+
|
19
|
+
# Constructs a source index instance from the provided
|
20
|
+
# specifications
|
21
|
+
#
|
22
|
+
# specifications::
|
23
|
+
# [Hash] hash of [Gem name, Gem::Specification] pairs
|
24
|
+
#
|
25
|
+
def initialize(specifications)
|
26
|
+
@gems = specifications
|
27
|
+
end
|
28
|
+
|
29
|
+
# Factory method to construct a source index instance for a given
|
30
|
+
# path.
|
31
|
+
#
|
32
|
+
# source_dirs::
|
33
|
+
# List of gem directories to search for specifications. The
|
34
|
+
# default is the "specification" directories under each
|
35
|
+
# directory in Gem.path.
|
36
|
+
#
|
37
|
+
# return::
|
38
|
+
# SourceIndex instance
|
39
|
+
#
|
40
|
+
def self.from_installed_gems(*spec_dirs)
|
41
|
+
gems = {}
|
42
|
+
if spec_dirs.empty?
|
43
|
+
spec_dirs = Gem.path.collect {|dir| File.join(dir, "specifications")}
|
44
|
+
end
|
45
|
+
Dir.glob("{#{spec_dirs.join(',')}}/*.gemspec").each do |file_name|
|
46
|
+
gemspec = load_specification(file_name)
|
47
|
+
gems[gemspec.full_name] = gemspec if gemspec
|
48
|
+
end
|
49
|
+
self.new(gems)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Load a specification from a file (eval'd Ruby code)
|
53
|
+
#
|
54
|
+
# file_name:: [String] The .gemspec file
|
55
|
+
# return:: Specification instance or nil if an error occurs
|
56
|
+
#
|
57
|
+
def self.load_specification(file_name)
|
58
|
+
begin
|
59
|
+
spec_code = File.read(file_name)
|
60
|
+
gemspec = eval(spec_code)
|
61
|
+
if gemspec.is_a?(Gem::Specification)
|
62
|
+
gemspec.loaded_from = file_name
|
63
|
+
return gemspec
|
64
|
+
end
|
65
|
+
alert_warning "File '#{file_name}' does not evaluate to a gem specification"
|
66
|
+
rescue SyntaxError => e
|
67
|
+
alert_warning e
|
68
|
+
alert_warning spec_code
|
69
|
+
rescue Exception => e
|
70
|
+
alert_warning(e.inspect.to_s + "\n" + spec_code)
|
71
|
+
alert_warning "Invalid .gemspec format in '#{file_name}'"
|
72
|
+
end
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# Iterate over the specifications in the source index.
|
77
|
+
#
|
78
|
+
# &block:: [yields gem.long_name, Gem::Specification]
|
79
|
+
#
|
80
|
+
def each(&block)
|
81
|
+
@gems.each(&block)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Search for a gem by name and optional version
|
85
|
+
#
|
86
|
+
# gem_name::
|
87
|
+
# [String] the (short) name of the gem
|
88
|
+
# version_requirement::
|
89
|
+
# [String | default=Version::Requirement.new(">= 0")] version to
|
90
|
+
# find
|
91
|
+
# return::
|
92
|
+
# [Array] list of Gem::Specification objects in sorted (version)
|
93
|
+
# order. Empty if not found.
|
94
|
+
#
|
95
|
+
def search(gem_name, version_requirement=Version::Requirement.new(">= 0"))
|
96
|
+
#FIXME - remove duplication between this and RemoteInstaller.search
|
97
|
+
gem_name = /#{ gem_name }/i if String === gem_name
|
98
|
+
version_requirement = Gem::Version::Requirement.create(version_requirement)
|
99
|
+
result = []
|
100
|
+
@gems.each do |full_spec_name, spec|
|
101
|
+
next unless spec.name =~ gem_name
|
102
|
+
result << spec if version_requirement.satisfied_by?(spec.version)
|
103
|
+
end
|
104
|
+
result = result.sort
|
105
|
+
result
|
106
|
+
end
|
107
|
+
|
108
|
+
# Refresh the source index from the local file system.
|
109
|
+
#
|
110
|
+
# return:: Returns a pointer to itself.
|
111
|
+
#
|
112
|
+
def refresh!
|
113
|
+
spec_dirs = Gem.path.collect {|dir| File.join(dir, "specifications")}
|
114
|
+
files = Dir.glob("{#{spec_dirs.join(',')}}/*.gemspec")
|
115
|
+
current_loaded_files = @gems.values.collect {|spec| spec.loaded_from}
|
116
|
+
(files - current_loaded_files).each do |spec_file|
|
117
|
+
gemspec = Gem::SourceIndex.load_specification(spec_file)
|
118
|
+
|
119
|
+
@gems[gemspec.full_name] = gemspec if gemspec
|
120
|
+
end
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
# Cache is an alias for SourceIndex to allow older YAMLized source
|
127
|
+
# index objects to load properly.
|
128
|
+
Cache = SourceIndex
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,613 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/version'
|
4
|
+
|
5
|
+
module Gem
|
6
|
+
|
7
|
+
##
|
8
|
+
# == Gem::Platform
|
9
|
+
#
|
10
|
+
# Available list of platforms for targeting Gem installations.
|
11
|
+
# Platform::RUBY is the default platform (pure Ruby Gem).
|
12
|
+
#
|
13
|
+
module Platform
|
14
|
+
RUBY = 'ruby'
|
15
|
+
WIN32 = 'mswin32'
|
16
|
+
LINUX_586 = 'i586-linux'
|
17
|
+
DARWIN = 'powerpc-darwin'
|
18
|
+
CURRENT = 'current'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Potentially raised when a specification is validated.
|
22
|
+
class InvalidSpecificationException < Gem::Exception; end
|
23
|
+
class EndOfYAMLException < Gem::Exception; end
|
24
|
+
|
25
|
+
##
|
26
|
+
# == Gem::Specification
|
27
|
+
#
|
28
|
+
# The Specification class contains the metadata for a Gem. Typically defined in a
|
29
|
+
# .gemspec file or a Rakefile, and looks like this:
|
30
|
+
#
|
31
|
+
# spec = Gem::Specification.new do |s|
|
32
|
+
# s.name = 'rfoo'
|
33
|
+
# s.version = '1.0'
|
34
|
+
# s.summary = 'Example gem specification'
|
35
|
+
# ...
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# There are many <em>gemspec attributes</em>, and the best place to learn about them in
|
39
|
+
# the "Gemspec Reference" linked from the RubyGems wiki.
|
40
|
+
#
|
41
|
+
class Specification
|
42
|
+
|
43
|
+
# ------------------------- Specification version contstants.
|
44
|
+
|
45
|
+
# The the version number of a specification that does not specify one (i.e. RubyGems 0.7
|
46
|
+
# or earlier).
|
47
|
+
NONEXISTENT_SPECIFICATION_VERSION = -1
|
48
|
+
|
49
|
+
# The specification version applied to any new Specification instances created. This
|
50
|
+
# should be bumped whenever something in the spec format changes.
|
51
|
+
CURRENT_SPECIFICATION_VERSION = 1
|
52
|
+
|
53
|
+
# An informal list of changes to the specification. The highest-valued key should be
|
54
|
+
# equal to the CURRENT_SPECIFICATION_VERSION.
|
55
|
+
SPECIFICATION_VERSION_HISTORY = {
|
56
|
+
-1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
|
57
|
+
1 => [
|
58
|
+
'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
|
59
|
+
'"test_file=x" is a shortcut for "test_files=[x]"'
|
60
|
+
]
|
61
|
+
}
|
62
|
+
|
63
|
+
# ------------------------- Class variables.
|
64
|
+
|
65
|
+
# List of Specification instances.
|
66
|
+
@@list = []
|
67
|
+
|
68
|
+
# Optional block used to gather newly defined instances.
|
69
|
+
@@gather = nil
|
70
|
+
|
71
|
+
# List of attribute names: [:name, :version, ...]
|
72
|
+
@@required_attributes = []
|
73
|
+
|
74
|
+
# List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...]
|
75
|
+
@@attributes = []
|
76
|
+
|
77
|
+
# Map of attribute names to default values.
|
78
|
+
@@default_value = {}
|
79
|
+
|
80
|
+
# ------------------------- Convenience class methods.
|
81
|
+
|
82
|
+
def self.attribute_names
|
83
|
+
@@attributes.map { |name, default| name }
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.attribute_defaults
|
87
|
+
@@attributes.dup
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.default_value(name)
|
91
|
+
@@default_value[name]
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.required_attributes
|
95
|
+
@@required_attributes.dup
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.required_attribute?(name)
|
99
|
+
@@required_attributes.include? name.to_sym
|
100
|
+
end
|
101
|
+
|
102
|
+
# ------------------------- Infrastructure class methods.
|
103
|
+
|
104
|
+
# A list of Specification instances that have been defined in this Ruby instance.
|
105
|
+
def self.list
|
106
|
+
@@list
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Used to specify the name and default value of a specification attribute. The side
|
111
|
+
# effects are:
|
112
|
+
# * the name and default value are added to the @@attributes list and
|
113
|
+
# @@default_value map
|
114
|
+
# * a standard _writer_ method (<tt>attribute=</tt>) is created
|
115
|
+
# * a non-standard _reader method (<tt>attribute</tt>) is created
|
116
|
+
#
|
117
|
+
# The reader method behaves like this:
|
118
|
+
# def attribute
|
119
|
+
# @attribute ||= (copy of default value)
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# This allows lazy initialization of attributes to their default values.
|
123
|
+
#
|
124
|
+
def self.attribute(name, default=nil)
|
125
|
+
@@attributes << [name, default]
|
126
|
+
@@default_value[name] = default
|
127
|
+
attr_writer(name)
|
128
|
+
class_eval %{
|
129
|
+
def #{name}
|
130
|
+
@#{name} ||= copy_of(@@default_value[:#{name}])
|
131
|
+
end
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
# Same as attribute above, but also records this attribute as mandatory.
|
136
|
+
def self.required_attribute(*args)
|
137
|
+
@@required_attributes << args.first
|
138
|
+
attribute(*args)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Sometimes we don't want the world to use a setter method for a particular attribute.
|
142
|
+
# +read_only+ makes it private so we can still use it internally.
|
143
|
+
def self.read_only(*names)
|
144
|
+
names.each do |name|
|
145
|
+
private "#{name}="
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Shortcut for creating several attributes at once (each with a default value of
|
150
|
+
# +nil+).
|
151
|
+
def self.attributes(*args)
|
152
|
+
args.each do |arg|
|
153
|
+
attribute(arg, nil)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Some attributes require special behaviour when they are accessed. This allows for
|
158
|
+
# that.
|
159
|
+
def self.overwrite_accessor(name, &block)
|
160
|
+
remove_method name
|
161
|
+
define_method(name, &block)
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Defines a _singular_ version of an existing _plural_ attribute (i.e. one whose value
|
166
|
+
# is expected to be an array). This means just creating a helper method that takes a
|
167
|
+
# single value and appends it to the array. These are created for convenience, so
|
168
|
+
# that in a spec, one can write
|
169
|
+
#
|
170
|
+
# s.require_path = 'mylib'
|
171
|
+
#
|
172
|
+
# instead of
|
173
|
+
#
|
174
|
+
# s.require_paths = ['mylib']
|
175
|
+
#
|
176
|
+
# That above convenience is available courtesy of
|
177
|
+
#
|
178
|
+
# attribute_alias_singular :require_path, :require_paths
|
179
|
+
#
|
180
|
+
def self.attribute_alias_singular(singular, plural)
|
181
|
+
define_method("#{singular}=") { |val|
|
182
|
+
send("#{plural}=", [val])
|
183
|
+
}
|
184
|
+
define_method("#{singular}") {
|
185
|
+
val = send("#{plural}")
|
186
|
+
val.nil? ? nil : val.first
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
def warn_deprecated(old, new)
|
191
|
+
# How (if at all) to implement this? We only want to warn when a gem is being
|
192
|
+
# built, I should think.
|
193
|
+
end
|
194
|
+
|
195
|
+
# ------------------------- REQUIRED gemspec attributes.
|
196
|
+
|
197
|
+
required_attribute :rubygems_version, RubyGemsVersion
|
198
|
+
required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
|
199
|
+
required_attribute :name
|
200
|
+
required_attribute :version
|
201
|
+
required_attribute :date
|
202
|
+
required_attribute :summary
|
203
|
+
required_attribute :require_paths, ['lib']
|
204
|
+
|
205
|
+
read_only :specification_version
|
206
|
+
|
207
|
+
# ------------------------- OPTIONAL gemspec attributes.
|
208
|
+
|
209
|
+
attributes :email, :homepage, :rubyforge_project, :description
|
210
|
+
attributes :autorequire, :default_executable
|
211
|
+
attribute :bindir, 'bin'
|
212
|
+
attribute :has_rdoc, false
|
213
|
+
attribute :required_ruby_version, Gem::Version::Requirement.default
|
214
|
+
attribute :platform, Gem::Platform::RUBY
|
215
|
+
attribute :authors, []
|
216
|
+
attribute :files, []
|
217
|
+
attribute :test_files, []
|
218
|
+
attribute :rdoc_options, []
|
219
|
+
attribute :extra_rdoc_files, []
|
220
|
+
attribute :executables, []
|
221
|
+
attribute :extensions, []
|
222
|
+
attribute :requirements, []
|
223
|
+
attribute :dependencies, []
|
224
|
+
|
225
|
+
read_only :dependencies
|
226
|
+
|
227
|
+
# ------------------------- ALIASED gemspec attributes.
|
228
|
+
|
229
|
+
attribute_alias_singular :executable, :executables
|
230
|
+
attribute_alias_singular :author, :authors
|
231
|
+
attribute_alias_singular :require_path, :require_paths
|
232
|
+
attribute_alias_singular :test_file, :test_files
|
233
|
+
|
234
|
+
# ------------------------- DEPRECATED gemspec attributes.
|
235
|
+
|
236
|
+
def test_suite_file
|
237
|
+
warn_deprecated(:test_suite_file, :test_files)
|
238
|
+
test_files.first
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_suite_file=(val)
|
242
|
+
warn_deprecated(:test_suite_file, :test_files)
|
243
|
+
@test_files << val
|
244
|
+
end
|
245
|
+
|
246
|
+
# ------------------------- RUNTIME attributes (not persisted).
|
247
|
+
|
248
|
+
attr_writer :loaded
|
249
|
+
attr_accessor :loaded_from
|
250
|
+
|
251
|
+
# ------------------------- Special accessor behaviours (overwriting default).
|
252
|
+
|
253
|
+
overwrite_accessor :version= do |version|
|
254
|
+
@version = Version.create(version)
|
255
|
+
end
|
256
|
+
|
257
|
+
overwrite_accessor :platform= do |platform|
|
258
|
+
# Checks the provided platform for the special value Platform::CURRENT and
|
259
|
+
# changes it to be binary specific to the current platform (i386-mswin32, etc).
|
260
|
+
@platform = (platform == Platform::CURRENT ? RUBY_PLATFORM : platform)
|
261
|
+
end
|
262
|
+
|
263
|
+
overwrite_accessor :required_ruby_version= do |value|
|
264
|
+
@required_ruby_version = Version::Requirement.create(value)
|
265
|
+
#STDERR.puts @name, @required_ruby_version
|
266
|
+
end
|
267
|
+
|
268
|
+
overwrite_accessor :date= do |date|
|
269
|
+
# We want to end up with a Date object. If _date_ responds to :to_str, or :day,
|
270
|
+
# :month, and :year, it is duly converted. Otherwise, today's date is used.
|
271
|
+
if date.respond_to? :to_str
|
272
|
+
date = Date.parse(date.to_str)
|
273
|
+
elsif [:year, :month, :day].all? { |m| date.respond_to? m }
|
274
|
+
date = Date.new(date.year, date.month, date.day)
|
275
|
+
else
|
276
|
+
date = nil
|
277
|
+
end
|
278
|
+
@date = date || Date.today
|
279
|
+
end
|
280
|
+
|
281
|
+
overwrite_accessor :date do
|
282
|
+
# Legacy gems might have a Time object directly loaded from the YAML. We fix it here.
|
283
|
+
unless @date.is_a? Date
|
284
|
+
self.date = @date
|
285
|
+
end
|
286
|
+
@date
|
287
|
+
end
|
288
|
+
|
289
|
+
overwrite_accessor :summary= do |str|
|
290
|
+
if str
|
291
|
+
@summary = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ")
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
overwrite_accessor :description= do |str|
|
296
|
+
if str
|
297
|
+
@description = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
overwrite_accessor :default_executable do
|
302
|
+
return @default_executable if @default_executable
|
303
|
+
# Special case: if there is only one executable specified, then that's obviously the
|
304
|
+
# default one.
|
305
|
+
return @executables.first if @executables.size == 1
|
306
|
+
nil
|
307
|
+
end
|
308
|
+
|
309
|
+
def add_bindir(executables)
|
310
|
+
if(@executables.nil?)
|
311
|
+
return nil
|
312
|
+
end
|
313
|
+
if(@bindir)
|
314
|
+
@executables.map {|e| File.join(@bindir, e) }
|
315
|
+
else
|
316
|
+
@executables
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
overwrite_accessor :files do
|
321
|
+
(@files || []) | (@test_files || []) | (add_bindir(@executables) || []) |
|
322
|
+
(@extra_rdoc_files || []) | (@extensions || [])
|
323
|
+
end
|
324
|
+
|
325
|
+
overwrite_accessor :test_files do
|
326
|
+
# Handle the possibility that we have @test_suite_file but not @test_files. This will
|
327
|
+
# happen when an old gem is loaded via YAML.
|
328
|
+
if @test_suite_file
|
329
|
+
@test_files = [@test_suite_file].flatten
|
330
|
+
@test_suite_file = nil
|
331
|
+
end
|
332
|
+
@test_files ||= []
|
333
|
+
end
|
334
|
+
|
335
|
+
# ------------------------- Predicates.
|
336
|
+
|
337
|
+
def loaded?; @loaded ? true : false ; end
|
338
|
+
def has_rdoc?; has_rdoc ? true : false ; end
|
339
|
+
def has_unit_tests?; not test_files.empty?; end
|
340
|
+
alias has_test_suite? has_unit_tests? # (deprecated)
|
341
|
+
|
342
|
+
# ------------------------- Constructors.
|
343
|
+
|
344
|
+
##
|
345
|
+
# Specification constructor. Assigns the default values to the attributes, adds this
|
346
|
+
# spec to the list of loaded specs (see Specification.list), and yields itself for
|
347
|
+
# further initialization.
|
348
|
+
#
|
349
|
+
def initialize
|
350
|
+
# Each attribute has a default value (possibly nil). Here, we initialize all
|
351
|
+
# attributes to their default value. This is done through the accessor
|
352
|
+
# methods, so special behaviours will be honored. Furthermore, we take a
|
353
|
+
# _copy_ of the default so each specification instance has its own empty
|
354
|
+
# arrays, etc.
|
355
|
+
@@attributes.each do |name, default|
|
356
|
+
self.send "#{name}=", copy_of(default)
|
357
|
+
end
|
358
|
+
@loaded = false
|
359
|
+
@@list << self
|
360
|
+
yield self if block_given?
|
361
|
+
@@gather.call(self) if @@gather
|
362
|
+
end
|
363
|
+
|
364
|
+
##
|
365
|
+
# Special loader for YAML files. When a Specification object is loaded from a YAML file,
|
366
|
+
# it bypasses the normal Ruby object initialization routine (#initialize). This method
|
367
|
+
# makes up for that and deals with gems of different ages.
|
368
|
+
#
|
369
|
+
# 'input' can be anything that YAML.load() accepts: String or IO.
|
370
|
+
#
|
371
|
+
def Specification.from_yaml(input)
|
372
|
+
spec = YAML.load(input)
|
373
|
+
if(spec.class == FalseClass) then
|
374
|
+
raise Gem::EndOfYAMLException
|
375
|
+
end
|
376
|
+
unless Specification === spec
|
377
|
+
raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
|
378
|
+
end
|
379
|
+
unless spec.instance_variable_get :@specification_version
|
380
|
+
spec.instance_variable_set :@specification_version, NONEXISTENT_SPECIFICATION_VERSION
|
381
|
+
end
|
382
|
+
spec
|
383
|
+
end
|
384
|
+
|
385
|
+
def Specification.load(filename)
|
386
|
+
gemspec = nil
|
387
|
+
fail "NESTED Specification.load calls not allowed!" if @@gather
|
388
|
+
@@gather = proc { |gs| gemspec = gs }
|
389
|
+
data = File.read(filename)
|
390
|
+
eval(data)
|
391
|
+
gemspec
|
392
|
+
ensure
|
393
|
+
@@gather = nil
|
394
|
+
end
|
395
|
+
|
396
|
+
# ------------------------- Instance methods.
|
397
|
+
|
398
|
+
##
|
399
|
+
# Sets the rubygems_version to Gem::RubyGemsVersion.
|
400
|
+
#
|
401
|
+
def mark_version
|
402
|
+
@rubygems_version = RubyGemsVersion
|
403
|
+
end
|
404
|
+
|
405
|
+
##
|
406
|
+
# Adds a dependency to this Gem. For example,
|
407
|
+
#
|
408
|
+
# spec.add_dependency('jabber4r', '> 0.1', '<= 0.5')
|
409
|
+
#
|
410
|
+
# gem:: [String or Gem::Dependency] The Gem name/dependency.
|
411
|
+
# requirements:: [default="> 0.0.0"] The version requirements.
|
412
|
+
#
|
413
|
+
def add_dependency(gem, *requirements)
|
414
|
+
requirements = ['> 0.0.0'] if requirements.empty?
|
415
|
+
requirements.flatten!
|
416
|
+
unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
|
417
|
+
gem = Dependency.new(gem, requirements)
|
418
|
+
end
|
419
|
+
dependencies << gem
|
420
|
+
end
|
421
|
+
|
422
|
+
##
|
423
|
+
# Returns the full name (name-version) of this Gem. Platform information is included
|
424
|
+
# (name-version-platform) if it is specified (and not the default Ruby platform).
|
425
|
+
#
|
426
|
+
def full_name
|
427
|
+
if platform == Gem::Platform::RUBY
|
428
|
+
"#{@name}-#{@version}"
|
429
|
+
else
|
430
|
+
"#{@name}-#{@version}-#{platform}"
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
##
|
435
|
+
# The full path to the gem (install path + full name).
|
436
|
+
#
|
437
|
+
# return:: [String] the full gem path
|
438
|
+
#
|
439
|
+
def full_gem_path
|
440
|
+
File.join(installation_path, "gems", full_name)
|
441
|
+
end
|
442
|
+
|
443
|
+
##
|
444
|
+
# The root directory that the gem was installed into.
|
445
|
+
#
|
446
|
+
# return:: [String] the installation path
|
447
|
+
#
|
448
|
+
def installation_path
|
449
|
+
(File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]).join(File::SEPARATOR)
|
450
|
+
end
|
451
|
+
|
452
|
+
##
|
453
|
+
# Checks if this Specification meets the requirement of the supplied
|
454
|
+
# dependency.
|
455
|
+
#
|
456
|
+
# dependency:: [Gem::Dependency] the dependency to check
|
457
|
+
# return:: [Boolean] true if dependency is met, otherwise false
|
458
|
+
#
|
459
|
+
def satisfies_requirement?(dependency)
|
460
|
+
return @name == dependency.name &&
|
461
|
+
dependency.version_requirements.satisfied_by?(@version)
|
462
|
+
end
|
463
|
+
|
464
|
+
# ------------------------- Comparison methods.
|
465
|
+
|
466
|
+
##
|
467
|
+
# Compare specs (name then version).
|
468
|
+
#
|
469
|
+
def <=>(other)
|
470
|
+
[@name, @version] <=> [other.name, other.version]
|
471
|
+
end
|
472
|
+
|
473
|
+
# Tests specs for equality (across all attributes).
|
474
|
+
def ==(other)
|
475
|
+
@@attributes.each do |name, default|
|
476
|
+
return false unless self.send(name) == other.send(name)
|
477
|
+
end
|
478
|
+
true
|
479
|
+
end
|
480
|
+
|
481
|
+
# ------------------------- Export methods (YAML and Ruby code).
|
482
|
+
|
483
|
+
# Returns an array of attribute names to be used when generating a YAML representation
|
484
|
+
# of this object. If an attribute still has its default value, it is omitted.
|
485
|
+
def to_yaml_properties
|
486
|
+
mark_version
|
487
|
+
@@attributes.map { |name, default| "@#{name}" }
|
488
|
+
end
|
489
|
+
|
490
|
+
# Returns a Ruby code representation of this specification, such that it can be
|
491
|
+
# eval'ed and reconstruct the same specification later. Attributes that still have
|
492
|
+
# their default values are omitted.
|
493
|
+
def to_ruby
|
494
|
+
mark_version
|
495
|
+
result = "Gem::Specification.new do |s|\n"
|
496
|
+
@@attributes.each do |name, default|
|
497
|
+
# TODO better implementation of next line (read_only_attribute? ... something like that)
|
498
|
+
next if name == :dependencies or name == :specification_version
|
499
|
+
current_value = self.send(name)
|
500
|
+
result << " s.#{name} = #{ruby_code(current_value)}\n" unless current_value == default
|
501
|
+
end
|
502
|
+
dependencies.each do |dep|
|
503
|
+
version_reqs_param = dep.requirements_list.inspect
|
504
|
+
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})\n"
|
505
|
+
end
|
506
|
+
result << "end\n"
|
507
|
+
end
|
508
|
+
|
509
|
+
# ------------------------- Validation and normalization methods.
|
510
|
+
|
511
|
+
##
|
512
|
+
# Checks that the specification contains all required fields, and
|
513
|
+
# does a very basic sanity check.
|
514
|
+
#
|
515
|
+
# Raises InvalidSpecificationException if the spec does not pass
|
516
|
+
# the checks..
|
517
|
+
def validate
|
518
|
+
normalize
|
519
|
+
if rubygems_version != RubyGemsVersion
|
520
|
+
raise InvalidSpecificationException.new(%[
|
521
|
+
Expected RubyGems Version #{RubyGemsVersion}, was #{rubygems_version}
|
522
|
+
].strip)
|
523
|
+
end
|
524
|
+
@@required_attributes.each do |symbol|
|
525
|
+
unless self.send(symbol)
|
526
|
+
raise InvalidSpecificationException.new("Missing value for attribute #{symbol}")
|
527
|
+
end
|
528
|
+
end
|
529
|
+
if require_paths.empty?
|
530
|
+
raise InvalidSpecificationException.new("Gem spec needs to have at least one require_path")
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
##
|
535
|
+
# Normalize the list of files so that:
|
536
|
+
# * All file lists have redundancies removed.
|
537
|
+
# * Files referenced in the extra_rdoc_files are included in the package file list.
|
538
|
+
#
|
539
|
+
# Also, the summary and description are converted to a normal format.
|
540
|
+
def normalize
|
541
|
+
if @extra_rdoc_files
|
542
|
+
@extra_rdoc_files.uniq!
|
543
|
+
@files ||= []
|
544
|
+
@files.concat(@extra_rdoc_files)
|
545
|
+
end
|
546
|
+
@files.uniq! if @files
|
547
|
+
end
|
548
|
+
|
549
|
+
# ------------------------- Dependency methods.
|
550
|
+
|
551
|
+
##
|
552
|
+
# return:: [Array] [[dependent_gem, dependency, [list_of_satisfiers]]]
|
553
|
+
#
|
554
|
+
def dependent_gems
|
555
|
+
out = []
|
556
|
+
Gem.source_index.each do |name,gem|
|
557
|
+
gem.dependencies.each do |dep|
|
558
|
+
if self.satisfies_requirement?(dep) then
|
559
|
+
sats = []
|
560
|
+
find_all_satisfiers(dep) do |sat|
|
561
|
+
sats << sat
|
562
|
+
end
|
563
|
+
out << [gem, dep, sats]
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
out
|
568
|
+
end
|
569
|
+
|
570
|
+
def to_s
|
571
|
+
"#<Gem::Specification name=#{@name} version=#{@version}>"
|
572
|
+
end
|
573
|
+
|
574
|
+
private
|
575
|
+
|
576
|
+
def find_all_satisfiers(dep)
|
577
|
+
Gem.source_index.each do |name,gem|
|
578
|
+
if(gem.satisfies_requirement?(dep)) then
|
579
|
+
yield gem
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
# Duplicate an object unless it's an immediate value.
|
585
|
+
def self.copy_of(obj)
|
586
|
+
case obj
|
587
|
+
when Numeric, Symbol, true, false, nil then obj
|
588
|
+
else obj.dup
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
# Duplicate an object unless it's an immediate value.
|
593
|
+
def copy_of(obj)
|
594
|
+
self.class.copy_of(obj)
|
595
|
+
end
|
596
|
+
|
597
|
+
# Return a string containing a Ruby code representation of the given object.
|
598
|
+
def ruby_code(obj)
|
599
|
+
case obj
|
600
|
+
when String then '%q{' + obj + '}'
|
601
|
+
when Array then obj.inspect
|
602
|
+
when Gem::Version then obj.to_s.inspect
|
603
|
+
when Date, Time then '%q{' + obj.strftime('%Y-%m-%d') + '}'
|
604
|
+
when Numeric then obj.inspect
|
605
|
+
when true, false, nil then obj.inspect
|
606
|
+
when Gem::Version::Requirement then "Gem::Version::Requirement.new(#{obj.to_s.inspect})"
|
607
|
+
else raise Exception, "ruby_code case not handled: #{obj.class}"
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
end # class Specification
|
612
|
+
end # module Gem
|
613
|
+
|