rubygems-update 0.8.6 → 0.8.8

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.

Files changed (42) hide show
  1. data/ChangeLog +134 -0
  2. data/Rakefile +41 -17
  3. data/bin/gemwhich +61 -0
  4. data/examples/application/an-app.gemspec +1 -0
  5. data/lib/gemconfigure.rb +18 -0
  6. data/lib/rubygems.rb +65 -47
  7. data/lib/rubygems/cmd_manager.rb +3 -1
  8. data/lib/rubygems/command.rb +4 -0
  9. data/lib/rubygems/config_file.rb +2 -6
  10. data/lib/rubygems/custom_require.rb +2 -2
  11. data/lib/rubygems/dependency_list.rb +131 -0
  12. data/lib/rubygems/deployment.rb +265 -0
  13. data/lib/rubygems/doc_manager.rb +1 -0
  14. data/lib/rubygems/gem_commands.rb +216 -15
  15. data/lib/rubygems/installer.rb +111 -286
  16. data/lib/rubygems/remote_installer.rb +16 -6
  17. data/lib/rubygems/rubygems_version.rb +1 -1
  18. data/lib/rubygems/source_index.rb +11 -5
  19. data/lib/rubygems/specification.rb +5 -0
  20. data/lib/rubygems/version.rb +146 -129
  21. data/test/test_configfile.rb +1 -1
  22. data/test/test_dependency_list.rb +163 -0
  23. data/test/test_deployment.rb +93 -0
  24. data/test/test_remote_fetcher.rb +38 -36
  25. metadata +23 -47
  26. data/test/data/a-0.0.1.gem +0 -0
  27. data/test/data/a-0.0.2.gem +0 -0
  28. data/test/data/b-0.0.2.gem +0 -0
  29. data/test/data/c-1.2.gem +0 -0
  30. data/test/data/gemhome/cache/a-0.0.1.gem +0 -0
  31. data/test/data/gemhome/cache/a-0.0.2.gem +0 -0
  32. data/test/data/gemhome/cache/b-0.0.2.gem +0 -0
  33. data/test/data/gemhome/cache/c-1.2.gem +0 -0
  34. data/test/data/gemhome/gems/a-0.0.1/lib/code.rb +0 -1
  35. data/test/data/gemhome/gems/a-0.0.2/lib/code.rb +0 -1
  36. data/test/data/gemhome/gems/b-0.0.2/lib/code.rb +0 -1
  37. data/test/data/gemhome/gems/c-1.2/lib/code.rb +0 -1
  38. data/test/data/gemhome/specifications/a-0.0.1.gemspec +0 -8
  39. data/test/data/gemhome/specifications/a-0.0.2.gemspec +0 -8
  40. data/test/data/gemhome/specifications/b-0.0.2.gemspec +0 -8
  41. data/test/data/gemhome/specifications/c-1.2.gemspec +0 -8
  42. data/test/data/one/one-0.0.1.gem +0 -0
@@ -37,10 +37,12 @@ module Gem
37
37
  register_command UninstallCommand.new
38
38
  register_command CheckCommand.new
39
39
  register_command BuildCommand.new
40
+ register_command DependencyCommand.new
40
41
  register_command QueryCommand.new
41
42
  register_command ListCommand.new
42
43
  register_command SearchCommand.new
43
44
  register_command UpdateCommand.new
45
+ register_command CleanupCommand.new
44
46
  register_command RDocCommand.new
45
47
  register_command EnvironmentCommand.new
46
48
  register_command SpecificationCommand.new
@@ -111,7 +113,7 @@ module Gem
111
113
  # - if it's specified multiple times, the first one wins
112
114
  # - there is a default config file location HOME/.gemrc
113
115
  def load_config_file_options(args)
114
- config_file = File.join(ENV['HOME'], ".gemrc")
116
+ config_file = Gem.config_file
115
117
  if args.index("--config-file")
116
118
  config_file = args[args.index("--config-file")+1]
117
119
  end
@@ -78,6 +78,10 @@ module Gem
78
78
 
79
79
  private
80
80
 
81
+ def command_manager
82
+ Gem::CommandManager.instance
83
+ end
84
+
81
85
  def handle_options(args)
82
86
  args = add_extra_args(args)
83
87
  @options = @defaults.clone
@@ -13,13 +13,13 @@ module Gem
13
13
  rescue ArgumentError
14
14
  warn "Failed to load #{config_file_name}"
15
15
  rescue Errno::ENOENT
16
- warn "Config file #{config_file_name} does not exist"
16
+ # Ignore missing config file error.
17
17
  end
18
18
  @hash ||= {}
19
19
  end
20
20
 
21
21
  def config_file_name
22
- @config_file_name || default_config_file_name
22
+ @config_file_name || Gem.config_file
23
23
  end
24
24
 
25
25
  def [](key)
@@ -51,10 +51,6 @@ module Gem
51
51
  end
52
52
  end
53
53
  end
54
-
55
- def default_config_file_name
56
- File.join(ENV['HOME'], '.gemrc')
57
- end
58
54
  end
59
55
 
60
56
  end
@@ -93,8 +93,8 @@ module Gem
93
93
  # Return a list of all installed gemspecs, sorted by alphabetical order and in reverse
94
94
  # version order.
95
95
  def init_gemspecs
96
- Gem.source_index.map { |_, spec| spec }.sort_by { |spec|
97
- [spec.name, spec.version.to_ints.map { |n| -n } ]
96
+ Gem.source_index.map { |_, spec| spec }.sort { |a,b|
97
+ (a.name <=> b.name).nonzero? || (b.version <=> a.version)
98
98
  }
99
99
  end
100
100
 
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Gem
4
+ class DependencyList
5
+ def self.from_source_index(src_index)
6
+ deps = DependencyList.new
7
+ src_index.each do |full_name, spec|
8
+ deps.add(spec)
9
+ end
10
+ deps
11
+ end
12
+
13
+ def initialize
14
+ @specs = []
15
+ end
16
+
17
+ # Are all the dependencies in the list satisfied?
18
+ def ok?
19
+ @specs.all? { |spec|
20
+ spec.dependencies.all? { |dep|
21
+ @specs.find { |s| s.satisfies_requirement?(dep) }
22
+ }
23
+ }
24
+ end
25
+
26
+ # Add a gemspec to the dependency list.
27
+ def add(gemspec)
28
+ @specs << gemspec
29
+ end
30
+
31
+ def find_name(full_name)
32
+ @specs.find { |spec| spec.full_name == full_name }
33
+ end
34
+
35
+ def remove_by_name(full_name)
36
+ @specs.delete_if { |spec| spec.full_name == full_name }
37
+ end
38
+
39
+ # Is is ok to remove a gem from the dependency list?
40
+ #
41
+ # If removing the gemspec creates breaks a currently ok dependency,
42
+ # then it is NOT ok to remove the gem.
43
+ def ok_to_remove?(full_name)
44
+ gem_to_remove = find_name(full_name)
45
+ siblings = @specs.find_all { |s|
46
+ s.name == gem_to_remove.name &&
47
+ s.full_name != gem_to_remove.full_name
48
+ }
49
+ deps = []
50
+ @specs.each do |spec|
51
+ spec.dependencies.each do |dep|
52
+ deps << dep if gem_to_remove.satisfies_requirement?(dep)
53
+ end
54
+ end
55
+ deps.all? { |dep|
56
+ siblings.any? { |s|
57
+ s.satisfies_requirement?(dep)
58
+ }
59
+ }
60
+ end
61
+
62
+ # Return a list of the specifications in the dependency list,
63
+ # sorted in order so that no spec in the list depends on a gem
64
+ # earlier in the list.
65
+ #
66
+ # This is useful when removing gems from a set of installed gems.
67
+ # By removing them in the returned order, you don't get into as
68
+ # many dependency issues.
69
+ #
70
+ # If there are circular dependencies (yuck!), then gems will be
71
+ # returned in order until only the circular dependents and anything
72
+ # they reference are left. Then arbitrary gemspecs will be returned
73
+ # until the circular dependency is broken, after which gems will be
74
+ # returned in dependency order again.
75
+ def dependency_order
76
+ result = []
77
+ disabled = {}
78
+ predecessors = build_predecessors
79
+ while disabled.size < @specs.size
80
+ candidate = @specs.find { |spec|
81
+ ! disabled[spec.full_name] &&
82
+ active_count(predecessors[spec.full_name], disabled) == 0
83
+ }
84
+ if candidate
85
+ disabled[candidate.full_name] = true
86
+ result << candidate
87
+ elsif candidate = @specs.find { |spec| ! disabled[spec.full_name] }
88
+ # This case handles circular dependencies. Just choose a
89
+ # candidate and move on.
90
+ disabled[candidate.full_name] = true
91
+ result << candidate
92
+ else
93
+ # We should never get here, but just in case we will terminate
94
+ # the loop.
95
+ break
96
+ end
97
+ end
98
+ result
99
+ end
100
+
101
+ private
102
+
103
+ # Count the number of gemspecs in the list +specs+ that are still
104
+ # active (e.g. not listed in the ignore hash).
105
+ def active_count(specs, ignored)
106
+ result = 0
107
+ specs.each do |spec|
108
+ result += 1 unless ignored[spec.full_name]
109
+ end
110
+ result
111
+ end
112
+
113
+ # Return a hash of predecessors. E.g. results[spec.full_name] is a
114
+ # list of gemspecs that have a dependency satisfied by spec.
115
+ def build_predecessors
116
+ result = Hash.new { |h,k| h[k] = [] }
117
+ @specs.each do |spec|
118
+ @specs.each do |other|
119
+ next if spec.full_name == other.full_name
120
+ other.dependencies.each do |dep|
121
+ if spec.satisfies_requirement?(dep)
122
+ result[spec.full_name] << other
123
+ end
124
+ end
125
+ end
126
+ end
127
+ result
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,265 @@
1
+ # The following is borrowed from setup.rb
2
+
3
+ def File.binread(fname)
4
+ open(fname, 'rb') {|f|
5
+ return f.read
6
+ }
7
+ end
8
+
9
+ # for corrupted windows stat(2)
10
+ def File.dir?(path)
11
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
12
+ end
13
+
14
+
15
+ module Gem
16
+
17
+ module Deployment
18
+
19
+ # The following is borrowed from setup.rb
20
+ module FileOperations
21
+
22
+ def mkdir_p(dirname, prefix = nil)
23
+ dirname = prefix + File.expand_path(dirname) if prefix
24
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
25
+ return if no_harm?
26
+
27
+ # does not check '/'... it's too abnormal case
28
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
29
+ if /\A[a-z]:\z/i =~ dirs[0]
30
+ disk = dirs.shift
31
+ dirs[0] = disk + dirs[0]
32
+ end
33
+ dirs.each_index do |idx|
34
+ path = dirs[0..idx].join('')
35
+ Dir.mkdir path unless File.dir?(path)
36
+ end
37
+ end
38
+
39
+ def rm_f(fname)
40
+ $stderr.puts "rm -f #{fname}" if verbose?
41
+ return if no_harm?
42
+
43
+ if File.exist?(fname) or File.symlink?(fname)
44
+ File.chmod 0777, fname
45
+ File.unlink fname
46
+ end
47
+ end
48
+
49
+ def rm_rf(dn)
50
+ $stderr.puts "rm -rf #{dn}" if verbose?
51
+ return if no_harm?
52
+
53
+ Dir.chdir dn
54
+ Dir.foreach('.') do |fn|
55
+ next if fn == '.'
56
+ next if fn == '..'
57
+ if File.dir?(fn)
58
+ verbose_off {
59
+ rm_rf fn
60
+ }
61
+ else
62
+ verbose_off {
63
+ rm_f fn
64
+ }
65
+ end
66
+ end
67
+ Dir.chdir '..'
68
+ Dir.rmdir dn
69
+ end
70
+
71
+ def no_harm?
72
+ false
73
+ end
74
+
75
+ def verbose?
76
+ false
77
+ end
78
+
79
+ def verbose_off(&block)
80
+ block.call
81
+ end
82
+
83
+ end
84
+
85
+ class Manager
86
+
87
+ DEPLOYMENTS_DIR = "."
88
+ DEPLOYMENTS_DB = "deployments.yaml"
89
+
90
+ attr_reader :deployments
91
+
92
+ def initialize(dir = DEPLOYMENTS_DIR, db = DEPLOYMENTS_DB)
93
+ require 'yaml'
94
+ require 'digest/sha1'
95
+ @db_file = File.expand_path(File.join(dir, db))
96
+ if File.exist?(@db_file)
97
+ @deployments = YAML.load(File.binread(@db_file))
98
+ @deployments.each {|deployment| deployment.manager = self}
99
+ else
100
+ @deployments = []
101
+ end
102
+ end
103
+
104
+ def new_deployment(target_dir = nil)
105
+ unless target_dir
106
+ require 'rbconfig'
107
+ target_dir = Config::CONFIG['sitelibdir']
108
+ end
109
+ target_dir = File.expand_path(target_dir)
110
+ deployment = self[target_dir]
111
+ unless deployment
112
+ deployment = ActiveDeployment.new(target_dir)
113
+ deployment.manager = self
114
+ @deployments << deployment
115
+ end
116
+ deployment
117
+ end
118
+
119
+ def persist
120
+ File.open(@db_file, "wb") {|f| f.puts @deployments.to_yaml}
121
+ end
122
+
123
+ def [](target_dir)
124
+ target_dir = File.expand_path(target_dir)
125
+ @deployments.each {|deployment| return deployment if deployment.target_directory == target_dir}
126
+ nil
127
+ end
128
+ end
129
+
130
+ class ActiveDeployment
131
+ attr_reader :target_directory, :deployed_gems
132
+ attr_accessor :manager
133
+
134
+ def initialize(target_directory)
135
+ @target_directory = target_directory
136
+ @deployed_gems = []
137
+ end
138
+
139
+ def to_yaml_properties
140
+ ['@target_directory', '@deployed_gems']
141
+ end
142
+
143
+ def prepare
144
+ @deployed_gems.each {|gem| gem.prepare}
145
+ end
146
+
147
+ def deploy
148
+ @deployed_gems.each {|gem| gem.deploy}
149
+ if fully_deployed?
150
+ @manager.persist
151
+ else
152
+ raise "ERROR: Did not fully deploy"
153
+ end
154
+ end
155
+
156
+ def fully_deployed?
157
+ @deployed_gems.each {|gem| return false unless gem.deployed?}
158
+ return true
159
+ end
160
+
161
+ def add_all_gems
162
+ Gem.source_index.each do |name, spec|
163
+ @deployed_gems << DeployedGem.new(spec, @target_directory)
164
+ end
165
+ self
166
+ end
167
+
168
+ def add_gem(gem_to_add)
169
+ @deployed_gems.each {|dg| return if gem_to_add.full_name == dg.gem_name}
170
+ @deployed_gems << DeployedGem.new(gem_to_add, @target_directory)
171
+ return self if gem_to_add.dependencies.size == 0
172
+ # must fulfill dependencies
173
+ sats = {}
174
+ Gem.source_index.each do |name, gem|
175
+ gem_to_add.dependencies.each do |dependency|
176
+ (sats[dependency] ||= []) << gem if gem.satisfies_requirement?(dependency)
177
+ end
178
+ end
179
+ sats.each_value {|list| add_gem list.sort.last}
180
+ self
181
+ end
182
+ end
183
+
184
+ class DeployedGem
185
+ attr_reader :specification, :gem_name, :gem_path, :deployed_files
186
+
187
+ def initialize(spec, target_directory)
188
+ @gem_name = spec.full_name
189
+ @gem_path = spec.full_gem_path
190
+ @lib_paths = spec.require_paths
191
+ @target_directory = target_directory
192
+ @deployed_files = []
193
+ end
194
+
195
+ def to_yaml_properties
196
+ ['@gem_name', '@gem_path', '@lib_paths', '@target_directory', '@deployed_files']
197
+ end
198
+
199
+ def prepare
200
+ paths = @lib_paths.collect {|lib_path| File.expand_path(File.join(gem_path, lib_path))}
201
+ paths.each do |path|
202
+ Dir.glob("#{path}/**/*").each do |file|
203
+ unless File.directory?(file)
204
+ @deployed_files << DeployedFile.new(file, File.join(@target_directory, file[(path.size+1)..-1]))
205
+ end
206
+ end
207
+ end
208
+ @deployed_files.each {|df| df.prepare}
209
+ end
210
+
211
+ def deploy
212
+ @deployed_files.each {|file| file.deploy}
213
+ end
214
+
215
+ def deployed?
216
+ @deployed_files.each {|file| return false unless file.deployed?}
217
+ return true
218
+ end
219
+ end
220
+
221
+ class DeployedFile
222
+
223
+ include FileOperations
224
+
225
+ attr_reader :source_path, :destination_path, :checksum
226
+
227
+ def initialize(source_path, destination_path)
228
+ @source_path = source_path
229
+ @destination_path = destination_path
230
+ end
231
+
232
+ def to_yaml_properties
233
+ ['@source_path', '@destination_path', '@checksum']
234
+ end
235
+
236
+ def prepare
237
+ @checksum ||= Digest::SHA1.new(File.binread(@source_path)).hexdigest
238
+ end
239
+
240
+ def deploy
241
+ return if deployed?
242
+ File.open(@source_path, "rb") do |source|
243
+ mkdir_p(File.dirname(@destination_path))
244
+ File.open(@destination_path, "wb") do |destination|
245
+ destination.write(source.read)
246
+ end
247
+ end
248
+ end
249
+
250
+ def deployed?
251
+ return false unless File.exist?(@destination_path)
252
+ return false if File.size(@source_path) != File.size(@destination_path)
253
+ new_checksum = nil
254
+ begin
255
+ new_checksum = Digest::SHA1.new(File.binread(@destination_path)).hexdigest
256
+ rescue
257
+ puts $!
258
+ puts $!.backtrace.join("\n")
259
+ end
260
+ new_checksum == @checksum
261
+ end
262
+ end
263
+
264
+ end
265
+ end