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.
- data/ChangeLog +134 -0
- data/Rakefile +41 -17
- data/bin/gemwhich +61 -0
- data/examples/application/an-app.gemspec +1 -0
- data/lib/gemconfigure.rb +18 -0
- data/lib/rubygems.rb +65 -47
- data/lib/rubygems/cmd_manager.rb +3 -1
- data/lib/rubygems/command.rb +4 -0
- data/lib/rubygems/config_file.rb +2 -6
- data/lib/rubygems/custom_require.rb +2 -2
- data/lib/rubygems/dependency_list.rb +131 -0
- data/lib/rubygems/deployment.rb +265 -0
- data/lib/rubygems/doc_manager.rb +1 -0
- data/lib/rubygems/gem_commands.rb +216 -15
- data/lib/rubygems/installer.rb +111 -286
- data/lib/rubygems/remote_installer.rb +16 -6
- data/lib/rubygems/rubygems_version.rb +1 -1
- data/lib/rubygems/source_index.rb +11 -5
- data/lib/rubygems/specification.rb +5 -0
- data/lib/rubygems/version.rb +146 -129
- data/test/test_configfile.rb +1 -1
- data/test/test_dependency_list.rb +163 -0
- data/test/test_deployment.rb +93 -0
- data/test/test_remote_fetcher.rb +38 -36
- metadata +23 -47
- data/test/data/a-0.0.1.gem +0 -0
- data/test/data/a-0.0.2.gem +0 -0
- data/test/data/b-0.0.2.gem +0 -0
- data/test/data/c-1.2.gem +0 -0
- data/test/data/gemhome/cache/a-0.0.1.gem +0 -0
- data/test/data/gemhome/cache/a-0.0.2.gem +0 -0
- data/test/data/gemhome/cache/b-0.0.2.gem +0 -0
- data/test/data/gemhome/cache/c-1.2.gem +0 -0
- data/test/data/gemhome/gems/a-0.0.1/lib/code.rb +0 -1
- data/test/data/gemhome/gems/a-0.0.2/lib/code.rb +0 -1
- data/test/data/gemhome/gems/b-0.0.2/lib/code.rb +0 -1
- data/test/data/gemhome/gems/c-1.2/lib/code.rb +0 -1
- data/test/data/gemhome/specifications/a-0.0.1.gemspec +0 -8
- data/test/data/gemhome/specifications/a-0.0.2.gemspec +0 -8
- data/test/data/gemhome/specifications/b-0.0.2.gemspec +0 -8
- data/test/data/gemhome/specifications/c-1.2.gemspec +0 -8
- data/test/data/one/one-0.0.1.gem +0 -0
data/lib/rubygems/cmd_manager.rb
CHANGED
@@ -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 =
|
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
|
data/lib/rubygems/command.rb
CHANGED
data/lib/rubygems/config_file.rb
CHANGED
@@ -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
|
-
|
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 ||
|
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 }.
|
97
|
-
|
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
|