rubygems-update 2.1.11 → 2.2.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.autotest +37 -12
  5. data/History.txt +99 -2
  6. data/MIT.txt +1 -0
  7. data/Manifest.txt +59 -19
  8. data/Rakefile +4 -6
  9. data/lib/gauntlet_rubygems.rb +1 -1
  10. data/lib/rubygems.rb +102 -80
  11. data/lib/rubygems/available_set.rb +2 -2
  12. data/lib/rubygems/basic_specification.rb +97 -8
  13. data/lib/rubygems/commands/install_command.rb +58 -15
  14. data/lib/rubygems/commands/list_command.rb +1 -7
  15. data/lib/rubygems/commands/outdated_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +14 -1
  17. data/lib/rubygems/commands/push_command.rb +9 -4
  18. data/lib/rubygems/commands/query_command.rb +33 -17
  19. data/lib/rubygems/commands/search_command.rb +0 -6
  20. data/lib/rubygems/commands/specification_command.rb +1 -1
  21. data/lib/rubygems/commands/unpack_command.rb +1 -1
  22. data/lib/rubygems/commands/update_command.rb +4 -1
  23. data/lib/rubygems/commands/which_command.rb +5 -8
  24. data/lib/rubygems/compatibility.rb +3 -0
  25. data/lib/rubygems/core_ext/kernel_gem.rb +6 -0
  26. data/lib/rubygems/defaults.rb +19 -0
  27. data/lib/rubygems/dependency_installer.rb +28 -9
  28. data/lib/rubygems/doctor.rb +17 -11
  29. data/lib/rubygems/errors.rb +16 -3
  30. data/lib/rubygems/exceptions.rb +52 -5
  31. data/lib/rubygems/ext.rb +1 -2
  32. data/lib/rubygems/ext/build_error.rb +6 -0
  33. data/lib/rubygems/ext/builder.rb +50 -17
  34. data/lib/rubygems/ext/cmake_builder.rb +1 -1
  35. data/lib/rubygems/ext/configure_builder.rb +1 -3
  36. data/lib/rubygems/ext/ext_conf_builder.rb +9 -3
  37. data/lib/rubygems/ext/rake_builder.rb +2 -5
  38. data/lib/rubygems/gemcutter_utilities.rb +8 -1
  39. data/lib/rubygems/installer.rb +14 -4
  40. data/lib/rubygems/installer_test_case.rb +0 -5
  41. data/lib/rubygems/package.rb +11 -2
  42. data/lib/rubygems/psych_additions.rb +1 -1
  43. data/lib/rubygems/rdoc.rb +1 -1
  44. data/lib/rubygems/remote_fetcher.rb +3 -3
  45. data/lib/rubygems/request.rb +16 -8
  46. data/lib/rubygems/request_set.rb +133 -42
  47. data/lib/rubygems/request_set/gem_dependency_api.rb +493 -11
  48. data/lib/rubygems/request_set/lockfile.rb +579 -0
  49. data/lib/rubygems/requirement.rb +58 -30
  50. data/lib/rubygems/resolver.rb +471 -0
  51. data/lib/rubygems/resolver/activation_request.rb +165 -0
  52. data/lib/rubygems/resolver/api_set.rb +110 -0
  53. data/lib/rubygems/resolver/api_specification.rb +79 -0
  54. data/lib/rubygems/resolver/best_set.rb +31 -0
  55. data/lib/rubygems/resolver/composed_set.rb +39 -0
  56. data/lib/rubygems/resolver/conflict.rb +122 -0
  57. data/lib/rubygems/{dependency_resolver → resolver}/current_set.rb +1 -4
  58. data/lib/rubygems/{dependency_resolver → resolver}/dependency_request.rb +37 -7
  59. data/lib/rubygems/resolver/git_set.rb +119 -0
  60. data/lib/rubygems/resolver/git_specification.rb +35 -0
  61. data/lib/rubygems/resolver/index_set.rb +74 -0
  62. data/lib/rubygems/resolver/index_specification.rb +69 -0
  63. data/lib/rubygems/resolver/installed_specification.rb +40 -0
  64. data/lib/rubygems/{dependency_resolver → resolver}/installer_set.rb +18 -17
  65. data/lib/rubygems/resolver/local_specification.rb +16 -0
  66. data/lib/rubygems/resolver/lock_set.rb +78 -0
  67. data/lib/rubygems/resolver/lock_specification.rb +58 -0
  68. data/lib/rubygems/resolver/requirement_list.rb +81 -0
  69. data/lib/rubygems/resolver/set.rb +27 -0
  70. data/lib/rubygems/resolver/spec_specification.rb +58 -0
  71. data/lib/rubygems/resolver/specification.rb +89 -0
  72. data/lib/rubygems/resolver/stats.rb +44 -0
  73. data/lib/rubygems/resolver/vendor_set.rb +83 -0
  74. data/lib/rubygems/resolver/vendor_specification.rb +24 -0
  75. data/lib/rubygems/security/trust_dir.rb +16 -2
  76. data/lib/rubygems/source.rb +71 -18
  77. data/lib/rubygems/source/git.rb +218 -0
  78. data/lib/rubygems/source/installed.rb +8 -1
  79. data/lib/rubygems/source/local.rb +14 -8
  80. data/lib/rubygems/source/lock.rb +48 -0
  81. data/lib/rubygems/source/specific_file.rb +14 -3
  82. data/lib/rubygems/source/vendor.rb +27 -0
  83. data/lib/rubygems/source_list.rb +74 -12
  84. data/lib/rubygems/spec_fetcher.rb +36 -4
  85. data/lib/rubygems/specification.rb +214 -65
  86. data/lib/rubygems/stub_specification.rb +57 -1
  87. data/lib/rubygems/syck_hack.rb +3 -3
  88. data/lib/rubygems/test_case.rb +226 -59
  89. data/lib/rubygems/test_utilities.rb +198 -0
  90. data/lib/rubygems/uninstaller.rb +22 -10
  91. data/lib/rubygems/uri_formatter.rb +20 -0
  92. data/lib/rubygems/user_interaction.rb +193 -71
  93. data/lib/rubygems/util.rb +121 -0
  94. data/lib/rubygems/util/list.rb +4 -0
  95. data/lib/rubygems/util/stringio.rb +34 -0
  96. data/lib/rubygems/validator.rb +6 -2
  97. data/lib/rubygems/version.rb +4 -8
  98. data/test/rubygems/test_bundled_ca.rb +1 -1
  99. data/test/rubygems/test_gem.rb +137 -29
  100. data/test/rubygems/test_gem_available_set.rb +19 -0
  101. data/test/rubygems/test_gem_commands_build_command.rb +1 -1
  102. data/test/rubygems/test_gem_commands_cert_command.rb +2 -2
  103. data/test/rubygems/test_gem_commands_cleanup_command.rb +13 -13
  104. data/test/rubygems/test_gem_commands_dependency_command.rb +24 -34
  105. data/test/rubygems/test_gem_commands_fetch_command.rb +43 -48
  106. data/test/rubygems/test_gem_commands_install_command.rb +244 -279
  107. data/test/rubygems/test_gem_commands_list_command.rb +3 -3
  108. data/test/rubygems/test_gem_commands_outdated_command.rb +7 -12
  109. data/test/rubygems/test_gem_commands_pristine_command.rb +73 -27
  110. data/test/rubygems/test_gem_commands_push_command.rb +76 -8
  111. data/test/rubygems/test_gem_commands_query_command.rb +239 -49
  112. data/test/rubygems/test_gem_commands_sources_command.rb +10 -43
  113. data/test/rubygems/test_gem_commands_specification_command.rb +24 -47
  114. data/test/rubygems/test_gem_commands_stale_command.rb +2 -2
  115. data/test/rubygems/test_gem_commands_uninstall_command.rb +3 -3
  116. data/test/rubygems/test_gem_commands_unpack_command.rb +16 -30
  117. data/test/rubygems/test_gem_commands_update_command.rb +149 -134
  118. data/test/rubygems/test_gem_commands_which_command.rb +4 -2
  119. data/test/rubygems/test_gem_dependency_installer.rb +68 -0
  120. data/test/rubygems/test_gem_dependency_list.rb +17 -17
  121. data/test/rubygems/test_gem_dependency_resolution_error.rb +28 -0
  122. data/test/rubygems/test_gem_doctor.rb +1 -1
  123. data/test/rubygems/test_gem_ext_builder.rb +178 -8
  124. data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -7
  125. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -10
  126. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +18 -21
  127. data/test/rubygems/test_gem_ext_rake_builder.rb +1 -3
  128. data/test/rubygems/test_gem_impossible_dependencies_error.rb +10 -6
  129. data/test/rubygems/test_gem_indexer.rb +6 -6
  130. data/test/rubygems/test_gem_installer.rb +29 -10
  131. data/test/rubygems/test_gem_local_remote_options.rb +1 -1
  132. data/test/rubygems/test_gem_package.rb +18 -0
  133. data/test/rubygems/test_gem_rdoc.rb +1 -1
  134. data/test/rubygems/test_gem_remote_fetcher.rb +1 -1
  135. data/test/rubygems/test_gem_request.rb +37 -10
  136. data/test/rubygems/test_gem_request_set.rb +271 -9
  137. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +684 -0
  138. data/test/rubygems/test_gem_request_set_lockfile.rb +849 -0
  139. data/test/rubygems/test_gem_requirement.rb +21 -0
  140. data/test/rubygems/{test_gem_dependency_resolver.rb → test_gem_resolver.rb} +231 -70
  141. data/test/rubygems/test_gem_resolver_activation_request.rb +63 -0
  142. data/test/rubygems/test_gem_resolver_api_set.rb +167 -0
  143. data/test/rubygems/test_gem_resolver_api_specification.rb +104 -0
  144. data/test/rubygems/test_gem_resolver_best_set.rb +30 -0
  145. data/test/rubygems/test_gem_resolver_conflict.rb +75 -0
  146. data/test/rubygems/test_gem_resolver_dependency_request.rb +20 -0
  147. data/test/rubygems/test_gem_resolver_git_set.rb +148 -0
  148. data/test/rubygems/test_gem_resolver_git_specification.rb +100 -0
  149. data/test/rubygems/test_gem_resolver_index_set.rb +28 -0
  150. data/test/rubygems/test_gem_resolver_index_specification.rb +89 -0
  151. data/test/rubygems/test_gem_resolver_installed_specification.rb +49 -0
  152. data/test/rubygems/test_gem_resolver_installer_set.rb +22 -0
  153. data/test/rubygems/test_gem_resolver_local_specification.rb +45 -0
  154. data/test/rubygems/test_gem_resolver_lock_set.rb +57 -0
  155. data/test/rubygems/test_gem_resolver_lock_specification.rb +87 -0
  156. data/test/rubygems/test_gem_resolver_requirement_list.rb +20 -0
  157. data/test/rubygems/test_gem_resolver_specification.rb +32 -0
  158. data/test/rubygems/test_gem_resolver_vendor_set.rb +67 -0
  159. data/test/rubygems/test_gem_resolver_vendor_specification.rb +83 -0
  160. data/test/rubygems/test_gem_server.rb +4 -4
  161. data/test/rubygems/test_gem_source.rb +54 -64
  162. data/test/rubygems/test_gem_source_git.rb +231 -0
  163. data/test/rubygems/test_gem_source_list.rb +24 -0
  164. data/test/rubygems/test_gem_source_local.rb +1 -1
  165. data/test/rubygems/test_gem_source_lock.rb +114 -0
  166. data/test/rubygems/test_gem_source_vendor.rb +27 -0
  167. data/test/rubygems/test_gem_spec_fetcher.rb +116 -61
  168. data/test/rubygems/test_gem_specification.rb +526 -94
  169. data/test/rubygems/test_gem_stub_specification.rb +123 -10
  170. data/test/rubygems/test_gem_uninstaller.rb +28 -2
  171. data/test/rubygems/test_gem_util.rb +31 -0
  172. data/test/rubygems/test_gem_validator.rb +9 -0
  173. data/util/update_bundled_ca_certificates.rb +8 -1
  174. metadata +89 -29
  175. metadata.gz.sig +2 -4
  176. data/lib/rubygems/dependency_resolver.rb +0 -254
  177. data/lib/rubygems/dependency_resolver/activation_request.rb +0 -109
  178. data/lib/rubygems/dependency_resolver/api_set.rb +0 -65
  179. data/lib/rubygems/dependency_resolver/api_specification.rb +0 -39
  180. data/lib/rubygems/dependency_resolver/composed_set.rb +0 -18
  181. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +0 -85
  182. data/lib/rubygems/dependency_resolver/index_set.rb +0 -64
  183. data/lib/rubygems/dependency_resolver/index_specification.rb +0 -60
  184. data/lib/rubygems/dependency_resolver/installed_specification.rb +0 -52
  185. data/test/rubygems/test_gem_dependency_resolver_api_specification.rb +0 -33
  186. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +0 -36
  187. data/test/rubygems/test_gem_dependency_resolver_index_set.rb +0 -53
  188. data/test/rubygems/test_gem_dependency_resolver_index_specification.rb +0 -73
  189. data/test/rubygems/test_gem_dependency_resolver_installed_specification.rb +0 -19
  190. data/test/rubygems/test_gem_dependency_resolver_installer_set.rb +0 -28
@@ -1,6 +1,10 @@
1
+ ##
2
+ # Represents an installed gem. This is used for dependency resolution.
3
+
1
4
  class Gem::Source::Installed < Gem::Source
2
5
 
3
- def initialize
6
+ def initialize # :nodoc:
7
+ @uri = nil
4
8
  end
5
9
 
6
10
  ##
@@ -8,6 +12,9 @@ class Gem::Source::Installed < Gem::Source
8
12
 
9
13
  def <=> other
10
14
  case other
15
+ when Gem::Source::Lock,
16
+ Gem::Source::Vendor then
17
+ -1
11
18
  when Gem::Source::Installed then
12
19
  0
13
20
  when Gem::Source then
@@ -1,5 +1,10 @@
1
+ ##
2
+ # The local source finds gems in the current directory for fulfilling
3
+ # dependencies.
4
+
1
5
  class Gem::Source::Local < Gem::Source
2
- def initialize
6
+
7
+ def initialize # :nodoc:
3
8
  @specs = nil
4
9
  @api_uri = nil
5
10
  @uri = nil
@@ -10,7 +15,8 @@ class Gem::Source::Local < Gem::Source
10
15
 
11
16
  def <=> other
12
17
  case other
13
- when Gem::Source::Installed then
18
+ when Gem::Source::Installed,
19
+ Gem::Source::Lock then
14
20
  -1
15
21
  when Gem::Source::Local then
16
22
  0
@@ -26,7 +32,7 @@ class Gem::Source::Local < Gem::Source
26
32
  "#<%s specs: %p>" % [self.class, keys]
27
33
  end
28
34
 
29
- def load_specs(type)
35
+ def load_specs type # :nodoc:
30
36
  names = []
31
37
 
32
38
  @specs = {}
@@ -68,8 +74,8 @@ class Gem::Source::Local < Gem::Source
68
74
  names
69
75
  end
70
76
 
71
- def find_gem(gem_name, version=Gem::Requirement.default,
72
- prerelease=false)
77
+ def find_gem gem_name, version = Gem::Requirement.default, # :nodoc:
78
+ prerelease = false
73
79
  load_specs :complete
74
80
 
75
81
  found = []
@@ -88,10 +94,10 @@ class Gem::Source::Local < Gem::Source
88
94
  end
89
95
  end
90
96
 
91
- found.sort_by { |s| s.version }.last
97
+ found.max_by { |s| s.version }
92
98
  end
93
99
 
94
- def fetch_spec(name)
100
+ def fetch_spec name # :nodoc:
95
101
  load_specs :complete
96
102
 
97
103
  if data = @specs[name]
@@ -101,7 +107,7 @@ class Gem::Source::Local < Gem::Source
101
107
  end
102
108
  end
103
109
 
104
- def download(spec, cache_dir=nil)
110
+ def download spec, cache_dir = nil # :nodoc:
105
111
  load_specs :complete
106
112
 
107
113
  @specs.each do |name, data|
@@ -0,0 +1,48 @@
1
+ ##
2
+ # A Lock source wraps an installed gem's source and sorts before other sources
3
+ # during dependency resolution. This allows RubyGems to prefer gems from
4
+ # dependency lock files.
5
+
6
+ class Gem::Source::Lock < Gem::Source
7
+
8
+ ##
9
+ # The wrapped Gem::Source
10
+
11
+ attr_reader :wrapped
12
+
13
+ ##
14
+ # Creates a new Lock source that wraps +source+ and moves it earlier in the
15
+ # sort list.
16
+
17
+ def initialize source
18
+ @wrapped = source
19
+ end
20
+
21
+ def <=> other # :nodoc:
22
+ case other
23
+ when Gem::Source::Lock then
24
+ @wrapped <=> other.wrapped
25
+ when Gem::Source then
26
+ 1
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ def == other # :nodoc:
33
+ 0 == (self <=> other)
34
+ end
35
+
36
+ ##
37
+ # Delegates to the wrapped source's fetch_spec method.
38
+
39
+ def fetch_spec name_tuple
40
+ @wrapped.fetch_spec name_tuple
41
+ end
42
+
43
+ def uri # :nodoc:
44
+ @wrapped.uri
45
+ end
46
+
47
+ end
48
+
@@ -1,4 +1,12 @@
1
+ ##
2
+ # A source representing a single .gem file. This is used for installation of
3
+ # local gems.
4
+
1
5
  class Gem::Source::SpecificFile < Gem::Source
6
+
7
+ ##
8
+ # Creates a new SpecificFile for the gem in +file+
9
+
2
10
  def initialize(file)
3
11
  @uri = nil
4
12
  @path = ::File.expand_path(file)
@@ -8,19 +16,22 @@ class Gem::Source::SpecificFile < Gem::Source
8
16
  @name = @spec.name_tuple
9
17
  end
10
18
 
19
+ ##
20
+ # The Gem::Specification extracted from this .gem.
21
+
11
22
  attr_reader :spec
12
23
 
13
- def load_specs(*a)
24
+ def load_specs *a # :nodoc:
14
25
  [@name]
15
26
  end
16
27
 
17
- def fetch_spec(name)
28
+ def fetch_spec name # :nodoc:
18
29
  return @spec if name == @name
19
30
  raise Gem::Exception, "Unable to find '#{name}'"
20
31
  @spec
21
32
  end
22
33
 
23
- def download(spec, dir=nil)
34
+ def download spec, dir = nil # :nodoc:
24
35
  return @path if spec == @spec
25
36
  raise Gem::Exception, "Unable to download '#{spec.full_name}'"
26
37
  end
@@ -0,0 +1,27 @@
1
+ ##
2
+ # This represents a vendored source that is similar to an installed gem.
3
+
4
+ class Gem::Source::Vendor < Gem::Source::Installed
5
+
6
+ ##
7
+ # Creates a new Vendor source for a gem that was unpacked at +path+.
8
+
9
+ def initialize path
10
+ @uri = path
11
+ end
12
+
13
+ def <=> other
14
+ case other
15
+ when Gem::Source::Lock then
16
+ -1
17
+ when Gem::Source::Vendor then
18
+ 0
19
+ when Gem::Source then
20
+ 1
21
+ else
22
+ nil
23
+ end
24
+ end
25
+
26
+ end
27
+
@@ -1,28 +1,53 @@
1
1
  require 'rubygems/source'
2
2
 
3
+ ##
4
+ # The SourceList represents the sources rubygems has been configured to use.
5
+ # A source may be created from an array of sources:
6
+ #
7
+ # Gem::SourceList.from %w[https://rubygems.example https://internal.example]
8
+ #
9
+ # Or by adding them:
10
+ #
11
+ # sources = Gem::SourceList.new
12
+ # sources.add 'https://rubygems.example'
13
+ #
14
+ # The most common way to get a SourceList is Gem.sources.
15
+
3
16
  class Gem::SourceList
17
+
18
+ include Enumerable
19
+
20
+ ##
21
+ # Creates a new SourceList
22
+
4
23
  def initialize
5
24
  @sources = []
6
25
  end
7
26
 
27
+ ##
28
+ # The sources in this list
29
+
8
30
  attr_reader :sources
9
31
 
32
+ ##
33
+ # Creates a new SourceList from an array of sources.
34
+
10
35
  def self.from(ary)
11
36
  list = new
12
37
 
13
- if ary
14
- ary.each do |x|
15
- list << x
16
- end
17
- end
38
+ list.replace ary
18
39
 
19
40
  return list
20
41
  end
21
42
 
22
- def initialize_copy(other)
43
+ def initialize_copy(other) # :nodoc:
23
44
  @sources = @sources.dup
24
45
  end
25
46
 
47
+ ##
48
+ # Appends +obj+ to the source list which may be a Gem::Source, URI or URI
49
+ # String.
50
+
26
51
  def <<(obj)
27
52
  src = case obj
28
53
  when URI
@@ -37,8 +62,12 @@ class Gem::SourceList
37
62
  src
38
63
  end
39
64
 
65
+ ##
66
+ # Replaces this SourceList with the sources in +other+ See #<< for
67
+ # acceptable items in +other+.
68
+
40
69
  def replace(other)
41
- @sources.clear
70
+ clear
42
71
 
43
72
  other.each do |x|
44
73
  self << x
@@ -47,28 +76,58 @@ class Gem::SourceList
47
76
  self
48
77
  end
49
78
 
79
+ ##
80
+ # Removes all sources from the SourceList.
81
+
82
+ def clear
83
+ @sources.clear
84
+ end
85
+
86
+ ##
87
+ # Yields each source URI in the list.
88
+
50
89
  def each
51
90
  @sources.each { |s| yield s.uri.to_s }
52
91
  end
53
92
 
93
+ ##
94
+ # Yields each source in the list.
95
+
54
96
  def each_source(&b)
55
97
  @sources.each(&b)
56
98
  end
57
99
 
58
- def ==(other)
100
+ ##
101
+ # Returns true if there are no sources in this SourceList.
102
+
103
+ def empty?
104
+ @sources.empty?
105
+ end
106
+
107
+ def == other # :nodoc:
59
108
  to_a == other
60
109
  end
61
110
 
111
+ ##
112
+ # Returns an Array of source URI Strings.
113
+
62
114
  def to_a
63
115
  @sources.map { |x| x.uri.to_s }
64
116
  end
65
117
 
66
118
  alias_method :to_ary, :to_a
67
119
 
120
+ ##
121
+ # Returns the first source in the list.
122
+
68
123
  def first
69
124
  @sources.first
70
125
  end
71
126
 
127
+ ##
128
+ # Returns true if this source list includes +other+ which may be a
129
+ # Gem::Source or a source URI.
130
+
72
131
  def include?(other)
73
132
  if other.kind_of? Gem::Source
74
133
  @sources.include? other
@@ -77,11 +136,14 @@ class Gem::SourceList
77
136
  end
78
137
  end
79
138
 
80
- def delete(uri)
81
- if uri.kind_of? Gem::Source
82
- @sources.delete uri
139
+ ##
140
+ # Deletes +source+ from the source list which may be a Gem::Source or a URI.
141
+
142
+ def delete source
143
+ if source.kind_of? Gem::Source
144
+ @sources.delete source
83
145
  else
84
- @sources.delete_if { |x| x.uri.to_s == uri.to_s }
146
+ @sources.delete_if { |x| x.uri.to_s == source.to_s }
85
147
  end
86
148
  end
87
149
  end
@@ -17,6 +17,11 @@ class Gem::SpecFetcher
17
17
 
18
18
  attr_reader :latest_specs # :nodoc:
19
19
 
20
+ ##
21
+ # Sources for this SpecFetcher
22
+
23
+ attr_reader :sources # :nodoc:
24
+
20
25
  ##
21
26
  # Cache of all released specs
22
27
 
@@ -29,6 +34,10 @@ class Gem::SpecFetcher
29
34
 
30
35
  @fetcher = nil
31
36
 
37
+ ##
38
+ # Default fetcher instance. Use this instead of ::new to reduce object
39
+ # allocation.
40
+
32
41
  def self.fetcher
33
42
  @fetcher ||= new
34
43
  end
@@ -37,7 +46,16 @@ class Gem::SpecFetcher
37
46
  @fetcher = fetcher
38
47
  end
39
48
 
40
- def initialize
49
+ ##
50
+ # Creates a new SpecFetcher. Ordinarily you want to use the default fetcher
51
+ # from Gem::SpecFetcher::fetcher which uses the Gem.sources.
52
+ #
53
+ # If you need to retrieve specifications from a different +source+, you can
54
+ # send it as an argument.
55
+
56
+ def initialize sources = nil
57
+ @sources = sources || Gem.sources
58
+
41
59
  @update_cache =
42
60
  begin
43
61
  File.stat(Gem.user_home).uid == Process.uid
@@ -70,7 +88,11 @@ class Gem::SpecFetcher
70
88
  rejected_specs = {}
71
89
 
72
90
  if dependency.prerelease?
73
- type = :complete
91
+ if dependency.specific?
92
+ type = :complete
93
+ else
94
+ type = :abs_latest
95
+ end
74
96
  elsif dependency.latest_version?
75
97
  type = :latest
76
98
  else
@@ -197,7 +219,7 @@ class Gem::SpecFetcher
197
219
  errors = []
198
220
  list = {}
199
221
 
200
- Gem.sources.each_source do |source|
222
+ @sources.each_source do |source|
201
223
  begin
202
224
  names = case type
203
225
  when :latest
@@ -209,6 +231,12 @@ class Gem::SpecFetcher
209
231
  tuples_for(source, :prerelease, true) +
210
232
  tuples_for(source, :released)
211
233
 
234
+ names.sort
235
+ when :abs_latest
236
+ names =
237
+ tuples_for(source, :prerelease, true) +
238
+ tuples_for(source, :latest)
239
+
212
240
  names.sort
213
241
  when :prerelease
214
242
  tuples_for(source, :prerelease)
@@ -225,7 +253,11 @@ class Gem::SpecFetcher
225
253
  [list, errors]
226
254
  end
227
255
 
228
- def tuples_for(source, type, gracefully_ignore=false)
256
+ ##
257
+ # Retrieves NameTuples from +source+ of the given +type+ (:prerelease,
258
+ # etc.). If +gracefully_ignore+ is true, errors are ignored.
259
+
260
+ def tuples_for(source, type, gracefully_ignore=false) # :nodoc:
229
261
  cache = @caches[type]
230
262
 
231
263
  tuples =
@@ -12,6 +12,7 @@ require 'rubygems/platform'
12
12
  require 'rubygems/deprecate'
13
13
  require 'rubygems/basic_specification'
14
14
  require 'rubygems/stub_specification'
15
+ require 'rubygems/util/stringio'
15
16
 
16
17
  # :stopdoc:
17
18
  # date.rb can't be loaded for `make install` due to miniruby
@@ -26,6 +27,7 @@ class Date; end
26
27
  # Gem::Specification.new do |s|
27
28
  # s.name = 'example'
28
29
  # s.version = '0.1.0'
30
+ # s.licenses = ['MIT']
29
31
  # s.summary = "This is an example!"
30
32
  # s.description = "Much longer explanation of the example!"
31
33
  # s.authors = ["Ruby Coder"]
@@ -71,13 +73,13 @@ class Gem::Specification < Gem::BasicSpecification
71
73
  #
72
74
  # NOTE RubyGems < 1.2 cannot load specification versions > 2.
73
75
 
74
- CURRENT_SPECIFICATION_VERSION = 4
76
+ CURRENT_SPECIFICATION_VERSION = 4 # :nodoc:
75
77
 
76
78
  ##
77
79
  # An informal list of changes to the specification. The highest-valued
78
80
  # key should be equal to the CURRENT_SPECIFICATION_VERSION.
79
81
 
80
- SPECIFICATION_VERSION_HISTORY = {
82
+ SPECIFICATION_VERSION_HISTORY = { # :nodoc:
81
83
  -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
82
84
  1 => [
83
85
  'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
@@ -95,12 +97,18 @@ class Gem::Specification < Gem::BasicSpecification
95
97
  ]
96
98
  }
97
99
 
98
- MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17, 4 => 18 }
100
+ MARSHAL_FIELDS = { # :nodoc:
101
+ -1 => 16,
102
+ 1 => 16,
103
+ 2 => 16,
104
+ 3 => 17,
105
+ 4 => 18,
106
+ }
99
107
 
100
108
  today = Time.now.utc
101
- TODAY = Time.utc(today.year, today.month, today.day)
109
+ TODAY = Time.utc(today.year, today.month, today.day) # :nodoc:
102
110
 
103
- LOAD_CACHE = {}
111
+ LOAD_CACHE = {} # :nodoc:
104
112
 
105
113
  private_constant :LOAD_CACHE if defined? private_constant
106
114
 
@@ -153,7 +161,7 @@ class Gem::Specification < Gem::BasicSpecification
153
161
  :version => nil,
154
162
  }
155
163
 
156
- Dupable = { }
164
+ Dupable = { } # :nodoc:
157
165
 
158
166
  @@default_value.each do |k,v|
159
167
  case v
@@ -199,6 +207,8 @@ class Gem::Specification < Gem::BasicSpecification
199
207
  # Paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
200
208
  # activated.
201
209
  #
210
+ # See also #require_paths
211
+ #
202
212
  # If you have an extension you do not need to add <code>"ext"</code> to the
203
213
  # require path, the extension build process will copy the extension files
204
214
  # into "lib" for you.
@@ -210,7 +220,7 @@ class Gem::Specification < Gem::BasicSpecification
210
220
  # # If all library files are in the root directory...
211
221
  # spec.require_path = '.'
212
222
 
213
- attr_accessor :require_paths
223
+ attr_writer :require_paths
214
224
 
215
225
  ##
216
226
  # The version of RubyGems used to create this gem.
@@ -317,7 +327,7 @@ class Gem::Specification < Gem::BasicSpecification
317
327
  add_bindir(@executables),
318
328
  @extra_rdoc_files,
319
329
  @extensions,
320
- ].flatten.uniq.compact
330
+ ].flatten.sort.uniq.compact
321
331
  end
322
332
 
323
333
  ######################################################################
@@ -504,6 +514,24 @@ class Gem::Specification < Gem::BasicSpecification
504
514
  end
505
515
 
506
516
  ##
517
+ # The version of RubyGems that installed this gem. Returns
518
+ # <code>Gem::Version.new(0)</code> for gems installed by versions earlier
519
+ # than RubyGems 2.2.0.
520
+
521
+ def installed_by_version # :nodoc:
522
+ @installed_by_version ||= Gem::Version.new(0)
523
+ end
524
+
525
+ ##
526
+ # Sets the version of RubyGems that installed this gem. See also
527
+ # #installed_by_version.
528
+
529
+ def installed_by_version= version # :nodoc:
530
+ @installed_by_version = Gem::Version.new version
531
+ end
532
+
533
+ ##
534
+ # :category: Recommended gemspec attributes
507
535
  # The license for this gem.
508
536
  #
509
537
  # The license must be a short name, no more than 64 characters.
@@ -512,7 +540,12 @@ class Gem::Specification < Gem::BasicSpecification
512
540
  # text of the license should be inside of the gem when you build it.
513
541
  #
514
542
  # See http://opensource.org/licenses/alphabetical for a list of licenses and
515
- # their abbreviations (or short names).
543
+ # their abbreviations (or short names). GitHub also provides a
544
+ # license picker at http://choosealicense.com/
545
+ #
546
+ # According to copyright law, not having an OSI-approved open source license
547
+ # means you have no rights to use the code for any purpose-- in other words,
548
+ # "all rights reserved".
516
549
  #
517
550
  # You can set multiple licenses with #licenses=
518
551
  #
@@ -524,6 +557,7 @@ class Gem::Specification < Gem::BasicSpecification
524
557
  end
525
558
 
526
559
  ##
560
+ # :category: Recommended gemspec attributes
527
561
  # The license(s) for the library.
528
562
  #
529
563
  # Each license must be a short name, no more than 64 characters.
@@ -671,8 +705,7 @@ class Gem::Specification < Gem::BasicSpecification
671
705
  LOAD_CACHE.clear
672
706
  end
673
707
 
674
- # :nodoc:
675
- def self.each_gemspec(dirs)
708
+ def self.each_gemspec(dirs) # :nodoc:
676
709
  dirs.each do |dir|
677
710
  Dir[File.join(dir, "*.gemspec")].each do |path|
678
711
  yield path.untaint
@@ -680,16 +713,14 @@ class Gem::Specification < Gem::BasicSpecification
680
713
  end
681
714
  end
682
715
 
683
- # :nodoc:
684
- def self.each_stub(dirs)
716
+ def self.each_stub(dirs) # :nodoc:
685
717
  each_gemspec(dirs) do |path|
686
718
  stub = Gem::StubSpecification.new(path)
687
719
  yield stub if stub.valid?
688
720
  end
689
721
  end
690
722
 
691
- # :nodoc:
692
- def self.each_spec(dirs)
723
+ def self.each_spec(dirs) # :nodoc:
693
724
  each_gemspec(dirs) do |path|
694
725
  spec = self.load path
695
726
  yield spec if spec
@@ -834,12 +865,8 @@ class Gem::Specification < Gem::BasicSpecification
834
865
  # this resets the list of known specs.
835
866
 
836
867
  def self.dirs= dirs
837
- # TODO: find extra calls to dir=
838
- # warn "NOTE: dirs= called from #{caller.first} for #{dirs.inspect}"
839
-
840
868
  self.reset
841
869
 
842
- # ugh
843
870
  @@dirs = Array(dirs).map { |dir| File.join dir, "specifications" }
844
871
  end
845
872
 
@@ -1004,7 +1031,7 @@ class Gem::Specification < Gem::BasicSpecification
1004
1031
  spec = eval code, binding, file
1005
1032
 
1006
1033
  if Gem::Specification === spec
1007
- spec.loaded_from = file.to_s
1034
+ spec.loaded_from = File.expand_path file.to_s
1008
1035
  LOAD_CACHE[file] = spec
1009
1036
  return spec
1010
1037
  end
@@ -1248,7 +1275,7 @@ class Gem::Specification < Gem::BasicSpecification
1248
1275
 
1249
1276
  ##
1250
1277
  # Activate all unambiguously resolved runtime dependencies of this
1251
- # spec. Add any ambigous dependencies to the unresolved list to be
1278
+ # spec. Add any ambiguous dependencies to the unresolved list to be
1252
1279
  # resolved later, as needed.
1253
1280
 
1254
1281
  def activate_dependencies
@@ -1324,9 +1351,7 @@ class Gem::Specification < Gem::BasicSpecification
1324
1351
  def add_self_to_load_path
1325
1352
  return if default_gem?
1326
1353
 
1327
- paths = require_paths.map do |path|
1328
- File.join full_gem_path, path
1329
- end
1354
+ paths = full_require_paths
1330
1355
 
1331
1356
  # gem directories must come after -I and ENV['RUBYLIB']
1332
1357
  insert_index = Gem.load_path_insert_index
@@ -1377,13 +1402,44 @@ class Gem::Specification < Gem::BasicSpecification
1377
1402
  # Returns the build_args used to install the gem
1378
1403
 
1379
1404
  def build_args
1380
- if File.exists? build_info_file
1405
+ if File.exist? build_info_file
1381
1406
  File.readlines(build_info_file).map { |x| x.strip }
1382
1407
  else
1383
1408
  []
1384
1409
  end
1385
1410
  end
1386
1411
 
1412
+ ##
1413
+ # Builds extensions for this platform if the gem has extensions listed and
1414
+ # the gem.build_complete file is missing.
1415
+
1416
+ def build_extensions # :nodoc:
1417
+ return if default_gem?
1418
+ return if extensions.empty?
1419
+ return if installed_by_version < Gem::Version.new('2.2.0.preview.2')
1420
+ return if File.exist? gem_build_complete_path
1421
+ return if !File.writable?(base_dir) &&
1422
+ !File.exist?(File.join(base_dir, 'extensions'))
1423
+
1424
+ begin
1425
+ # We need to require things in $LOAD_PATH without looking for the
1426
+ # extension we are about to build.
1427
+ unresolved_deps = Gem::Specification.unresolved_deps.dup
1428
+ Gem::Specification.unresolved_deps.clear
1429
+
1430
+ require 'rubygems/config_file'
1431
+ require 'rubygems/ext'
1432
+ require 'rubygems/user_interaction'
1433
+
1434
+ Gem::DefaultUserInteraction.use_ui Gem::SilentUI.new do
1435
+ builder = Gem::Ext::Builder.new self
1436
+ builder.build_extensions
1437
+ end
1438
+ ensure
1439
+ Gem::Specification.unresolved_deps.replace unresolved_deps
1440
+ end
1441
+ end
1442
+
1387
1443
  ##
1388
1444
  # Returns the full path to the build info directory
1389
1445
 
@@ -1438,10 +1494,11 @@ class Gem::Specification < Gem::BasicSpecification
1438
1494
  @date ||= TODAY
1439
1495
  end
1440
1496
 
1441
- DateTimeFormat = /\A
1442
- (\d{4})-(\d{2})-(\d{2})
1443
- (\s+ \d{2}:\d{2}:\d{2}\.\d+ \s* (Z | [-+]\d\d:\d\d) )?
1444
- \Z/x
1497
+ DateTimeFormat = # :nodoc:
1498
+ /\A
1499
+ (\d{4})-(\d{2})-(\d{2})
1500
+ (\s+ \d{2}:\d{2}:\d{2}\.\d+ \s* (Z | [-+]\d\d:\d\d) )?
1501
+ \Z/x
1445
1502
 
1446
1503
  ##
1447
1504
  # The date this gem was created
@@ -1514,7 +1571,6 @@ class Gem::Specification < Gem::BasicSpecification
1514
1571
  # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
1515
1572
 
1516
1573
  def dependent_gems
1517
- # REFACTOR: out = []; each; out; ? Really? No #collect love?
1518
1574
  out = []
1519
1575
  Gem::Specification.each do |spec|
1520
1576
  spec.dependencies.each do |dep|
@@ -1553,7 +1609,7 @@ class Gem::Specification < Gem::BasicSpecification
1553
1609
 
1554
1610
  ##
1555
1611
  # Returns the full path to this spec's documentation directory. If +type+
1556
- # is given it will be appended to the end. For examlpe:
1612
+ # is given it will be appended to the end. For example:
1557
1613
  #
1558
1614
  # spec.doc_dir # => "/path/to/gem_repo/doc/a-1"
1559
1615
  #
@@ -1674,8 +1730,7 @@ class Gem::Specification < Gem::BasicSpecification
1674
1730
  spec
1675
1731
  end
1676
1732
 
1677
- # :nodoc:
1678
- def find_full_gem_path
1733
+ def find_full_gem_path # :nodoc:
1679
1734
  super || File.expand_path(File.join(gems_dir, original_name))
1680
1735
  end
1681
1736
  private :find_full_gem_path
@@ -1685,11 +1740,18 @@ class Gem::Specification < Gem::BasicSpecification
1685
1740
  end
1686
1741
 
1687
1742
  ##
1688
- # Returns the full path to this spec's gem directory.
1689
- # eg: /usr/local/lib/ruby/1.8/gems/mygem-1.0
1743
+ # The path to the gem.build_complete file within the extension install
1744
+ # directory.
1690
1745
 
1691
- def gem_dir
1692
- @gem_dir ||= File.expand_path File.join(gems_dir, full_name)
1746
+ def gem_build_complete_path # :nodoc:
1747
+ File.join extension_dir, 'gem.build_complete'
1748
+ end
1749
+
1750
+ ##
1751
+ # Work around bundler removing my methods
1752
+
1753
+ def gem_dir # :nodoc:
1754
+ super
1693
1755
  end
1694
1756
 
1695
1757
  ##
@@ -1742,6 +1804,7 @@ class Gem::Specification < Gem::BasicSpecification
1742
1804
  @activated = false
1743
1805
  self.loaded_from = nil
1744
1806
  @original_platform = nil
1807
+ @installed_by_version = nil
1745
1808
 
1746
1809
  @@nil_attributes.each do |key|
1747
1810
  instance_variable_set "@#{key}", nil
@@ -1797,7 +1860,7 @@ class Gem::Specification < Gem::BasicSpecification
1797
1860
 
1798
1861
  private :invalidate_memoized_attributes
1799
1862
 
1800
- def inspect
1863
+ def inspect # :nodoc:
1801
1864
  if $DEBUG
1802
1865
  super
1803
1866
  else
@@ -1853,7 +1916,6 @@ class Gem::Specification < Gem::BasicSpecification
1853
1916
  @cache_dir = nil
1854
1917
  @cache_file = nil
1855
1918
  @doc_dir = nil
1856
- @gem_dir = nil
1857
1919
  @ri_dir = nil
1858
1920
  @spec_dir = nil
1859
1921
  @spec_file = nil
@@ -1945,8 +2007,12 @@ class Gem::Specification < Gem::BasicSpecification
1945
2007
  q.group 2, 'Gem::Specification.new do |s|', 'end' do
1946
2008
  q.breakable
1947
2009
 
1948
- # REFACTOR: each_attr - use in to_yaml as well
1949
- @@attributes.each do |attr_name|
2010
+ attributes = @@attributes - [:name, :version]
2011
+ attributes.unshift :installed_by_version
2012
+ attributes.unshift :version
2013
+ attributes.unshift :name
2014
+
2015
+ attributes.each do |attr_name|
1950
2016
  current_value = self.send attr_name
1951
2017
  if current_value != default_value(attr_name) or
1952
2018
  self.class.required_attribute? attr_name then
@@ -2107,10 +2173,10 @@ class Gem::Specification < Gem::BasicSpecification
2107
2173
  end
2108
2174
 
2109
2175
  ##
2110
- # Used by Gem::DependencyResolver to order Gem::Specification objects
2176
+ # Used by Gem::Resolver to order Gem::Specification objects
2111
2177
 
2112
2178
  def source # :nodoc:
2113
- self
2179
+ Gem::Source::Installed.new
2114
2180
  end
2115
2181
 
2116
2182
  ##
@@ -2183,16 +2249,14 @@ class Gem::Specification < Gem::BasicSpecification
2183
2249
  # Returns a Ruby code representation of this specification, such that it can
2184
2250
  # be eval'ed and reconstruct the same specification later. Attributes that
2185
2251
  # still have their default values are omitted.
2186
- #
2187
- # REFACTOR: This, plus stuff like #ruby_code and #pretty_print, should
2188
- # probably be extracted out into some sort of separate class. SRP, do you
2189
- # speak it!??!
2190
2252
 
2191
2253
  def to_ruby
2192
2254
  mark_version
2193
2255
  result = []
2194
2256
  result << "# -*- encoding: utf-8 -*-"
2195
- result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{require_paths.join("\0")}"
2257
+ result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{@require_paths.join("\0")}"
2258
+ result << "#{Gem::StubSpecification::PREFIX}#{extensions.join "\0"}" unless
2259
+ extensions.empty?
2196
2260
  result << nil
2197
2261
  result << "Gem::Specification.new do |s|"
2198
2262
 
@@ -2207,11 +2271,13 @@ class Gem::Specification < Gem::BasicSpecification
2207
2271
  if metadata and !metadata.empty?
2208
2272
  result << " s.metadata = #{ruby_code metadata} if s.respond_to? :metadata="
2209
2273
  end
2274
+ result << " s.require_paths = #{ruby_code @require_paths}"
2210
2275
 
2211
2276
  handled = [
2212
2277
  :dependencies,
2213
2278
  :name,
2214
2279
  :platform,
2280
+ :require_paths,
2215
2281
  :required_rubygems_version,
2216
2282
  :specification_version,
2217
2283
  :version,
@@ -2229,6 +2295,11 @@ class Gem::Specification < Gem::BasicSpecification
2229
2295
  end
2230
2296
  end
2231
2297
 
2298
+ if @installed_by_version then
2299
+ result << nil
2300
+ result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version"
2301
+ end
2302
+
2232
2303
  unless dependencies.empty? then
2233
2304
  result << nil
2234
2305
  result << " if s.respond_to? :specification_version then"
@@ -2300,7 +2371,7 @@ class Gem::Specification < Gem::BasicSpecification
2300
2371
  builder << self
2301
2372
  ast = builder.tree
2302
2373
 
2303
- io = StringIO.new
2374
+ io = Gem::StringSink.new
2304
2375
  io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
2305
2376
 
2306
2377
  Psych::Visitors::Emitter.new(io).accept(ast)
@@ -2338,6 +2409,7 @@ class Gem::Specification < Gem::BasicSpecification
2338
2409
  # checks..
2339
2410
 
2340
2411
  def validate packaging = true
2412
+ @warnings = 0
2341
2413
  require 'rubygems/user_interaction'
2342
2414
  extend Gem::UserInteraction
2343
2415
  normalize
@@ -2368,7 +2440,7 @@ class Gem::Specification < Gem::BasicSpecification
2368
2440
  "invalid value for attribute name: \"#{name.inspect}\""
2369
2441
  end
2370
2442
 
2371
- if require_paths.empty? then
2443
+ if @require_paths.empty? then
2372
2444
  raise Gem::InvalidSpecificationException,
2373
2445
  'specification must have at least one require_path'
2374
2446
  end
@@ -2386,6 +2458,11 @@ class Gem::Specification < Gem::BasicSpecification
2386
2458
  "[\"#{non_files.join "\", \""}\"] are not files"
2387
2459
  end
2388
2460
 
2461
+ if files.include? file_name then
2462
+ raise Gem::InvalidSpecificationException,
2463
+ "#{full_name} contains itself (#{file_name}), check your files list"
2464
+ end
2465
+
2389
2466
  unless specification_version.is_a?(Fixnum)
2390
2467
  raise Gem::InvalidSpecificationException,
2391
2468
  'specification_version must be a Fixnum (did you mean version?)'
@@ -2413,7 +2490,6 @@ class Gem::Specification < Gem::BasicSpecification
2413
2490
  end
2414
2491
  end
2415
2492
 
2416
- # FIX: uhhhh single element array.each?
2417
2493
  [:authors].each do |field|
2418
2494
  val = self.send field
2419
2495
  raise Gem::InvalidSpecificationException, "#{field} may not be empty" if
@@ -2456,16 +2532,15 @@ class Gem::Specification < Gem::BasicSpecification
2456
2532
  end
2457
2533
  }
2458
2534
 
2459
- alert_warning <<-warning if licenses.empty?
2460
- licenses is empty. Use a license abbreviation from:
2461
- http://opensource.org/licenses/alphabetical
2535
+ warning <<-warning if licenses.empty?
2536
+ licenses is empty, but is recommended. Use a license abbreviation from:
2537
+ http://opensource.org/licenses/alphabetical
2462
2538
  warning
2463
2539
 
2464
2540
  validate_permissions
2465
2541
 
2466
2542
  # reject lazy developers:
2467
2543
 
2468
- # FIX: Doesn't this just evaluate to "FIXME" or "TODO"?
2469
2544
  lazy = '"FIxxxXME" or "TOxxxDO"'.gsub(/xxx/, '')
2470
2545
 
2471
2546
  unless authors.grep(/FI XME|TO DO/x).empty? then
@@ -2494,33 +2569,98 @@ licenses is empty. Use a license abbreviation from:
2494
2569
 
2495
2570
  %w[author description email homepage summary].each do |attribute|
2496
2571
  value = self.send attribute
2497
- alert_warning "no #{attribute} specified" if value.nil? or value.empty?
2572
+ warning "no #{attribute} specified" if value.nil? or value.empty?
2498
2573
  end
2499
2574
 
2500
2575
  if description == summary then
2501
- alert_warning 'description and summary are identical'
2576
+ warning 'description and summary are identical'
2502
2577
  end
2503
2578
 
2504
2579
  # TODO: raise at some given date
2505
- alert_warning "deprecated autorequire specified" if autorequire
2580
+ warning "deprecated autorequire specified" if autorequire
2506
2581
 
2507
2582
  executables.each do |executable|
2508
2583
  executable_path = File.join(bindir, executable)
2509
2584
  shebang = File.read(executable_path, 2) == '#!'
2510
2585
 
2511
- alert_warning "#{executable_path} is missing #! line" unless shebang
2586
+ warning "#{executable_path} is missing #! line" unless shebang
2512
2587
  end
2513
2588
 
2589
+ validate_dependencies
2590
+
2591
+ true
2592
+ ensure
2593
+ if $! or @warnings > 0 then
2594
+ alert_warning "See http://guides.rubygems.org/specification-reference/ for help"
2595
+ end
2596
+ end
2597
+
2598
+ ##
2599
+ # Checks that dependencies use requirements as we recommend. Warnings are
2600
+ # issued when dependencies are open-ended or overly strict for semantic
2601
+ # versioning.
2602
+
2603
+ def validate_dependencies # :nodoc:
2604
+ seen = {}
2605
+
2514
2606
  dependencies.each do |dep|
2607
+ if prev = seen[dep.name] then
2608
+ raise Gem::InvalidSpecificationException, <<-MESSAGE
2609
+ duplicate dependency on #{dep}, (#{prev.requirement}) use:
2610
+ add_runtime_dependency '#{dep.name}', '#{dep.requirement}', '#{prev.requirement}'
2611
+ MESSAGE
2612
+ end
2613
+
2614
+ seen[dep.name] = dep
2615
+
2515
2616
  prerelease_dep = dep.requirements_list.any? do |req|
2516
2617
  Gem::Requirement.new(req).prerelease?
2517
2618
  end
2518
2619
 
2519
- alert_warning "prerelease dependency on #{dep} is not recommended" if
2620
+ warning "prerelease dependency on #{dep} is not recommended" if
2520
2621
  prerelease_dep
2521
- end
2522
2622
 
2523
- true
2623
+ overly_strict = dep.requirement.requirements.length == 1 &&
2624
+ dep.requirement.requirements.any? do |op, version|
2625
+ op == '~>' and
2626
+ not version.prerelease? and
2627
+ version.segments.length > 2
2628
+ end
2629
+
2630
+ if overly_strict then
2631
+ _, dep_version = dep.requirement.requirements.first
2632
+
2633
+ base = dep_version.segments.first 2
2634
+
2635
+ warning <<-WARNING
2636
+ pessimistic dependency on #{dep} may be overly strict
2637
+ if #{dep.name} is semantically versioned, use:
2638
+ add_#{dep.type}_dependency '#{dep.name}', '~> #{base.join '.'}', '>= #{dep_version}'
2639
+ WARNING
2640
+ end
2641
+
2642
+ open_ended = dep.requirement.requirements.all? do |op, version|
2643
+ not version.prerelease? and (op == '>' or op == '>=')
2644
+ end
2645
+
2646
+ if open_ended then
2647
+ op, dep_version = dep.requirement.requirements.first
2648
+
2649
+ base = dep_version.segments.first 2
2650
+
2651
+ bugfix = if op == '>' then
2652
+ ", '> #{dep_version}'"
2653
+ elsif op == '>=' and base != dep_version.segments then
2654
+ ", '>= #{dep_version}'"
2655
+ end
2656
+
2657
+ warning <<-WARNING
2658
+ open-ended dependency on #{dep} is not recommended
2659
+ if #{dep.name} is semantically versioned, use:
2660
+ add_#{dep.type}_dependency '#{dep.name}', '~> #{base.join '.'}'#{bugfix}
2661
+ WARNING
2662
+ end
2663
+ end
2524
2664
  end
2525
2665
 
2526
2666
  ##
@@ -2531,13 +2671,13 @@ licenses is empty. Use a license abbreviation from:
2531
2671
 
2532
2672
  files.each do |file|
2533
2673
  next if File.stat(file).mode & 0444 == 0444
2534
- alert_warning "#{file} is not world-readable"
2674
+ warning "#{file} is not world-readable"
2535
2675
  end
2536
2676
 
2537
2677
  executables.each do |name|
2538
2678
  exec = File.join @bindir, name
2539
2679
  next if File.stat(exec).executable?
2540
- alert_warning "#{exec} is not executable"
2680
+ warning "#{exec} is not executable"
2541
2681
  end
2542
2682
  end
2543
2683
 
@@ -2554,7 +2694,10 @@ licenses is empty. Use a license abbreviation from:
2554
2694
  return @version
2555
2695
  end
2556
2696
 
2557
- # FIX: have this handle the platform/new_platform/original_platform bullshit
2697
+ def stubbed?
2698
+ false
2699
+ end
2700
+
2558
2701
  def yaml_initialize(tag, vals) # :nodoc:
2559
2702
  vals.each do |ivar, val|
2560
2703
  case ivar
@@ -2592,6 +2735,12 @@ licenses is empty. Use a license abbreviation from:
2592
2735
  @installed_by_version ||= nil
2593
2736
  end
2594
2737
 
2738
+ def warning statement # :nodoc:
2739
+ @warnings += 1
2740
+
2741
+ alert_warning statement
2742
+ end
2743
+
2595
2744
  extend Gem::Deprecate
2596
2745
 
2597
2746
  # TODO: