gem-dependent 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -2
- data/Gemfile.lock +0 -2
- data/Rakefile +0 -13
- data/Readme.md +6 -5
- data/VERSION +1 -1
- data/gem-dependent.gemspec +3 -10
- data/lib/rubygems/dependent.rb +2 -5
- data/lib/rubygems/dependent_parallel.rb +272 -0
- data/spec/dependent_spec.rb +1 -1
- metadata +6 -13
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -9,7 +9,6 @@ GEM
|
|
9
9
|
git (>= 1.2.5)
|
10
10
|
rubyforge (>= 2.0.0)
|
11
11
|
json_pure (1.4.6)
|
12
|
-
parallel (0.5.1)
|
13
12
|
rake (0.8.7)
|
14
13
|
rspec (2.0.1)
|
15
14
|
rspec-core (~> 2.0.1)
|
@@ -29,6 +28,5 @@ PLATFORMS
|
|
29
28
|
|
30
29
|
DEPENDENCIES
|
31
30
|
jeweler
|
32
|
-
parallel (>= 0.5.1)
|
33
31
|
rake
|
34
32
|
rspec (~> 2)
|
data/Rakefile
CHANGED
@@ -12,19 +12,6 @@ begin
|
|
12
12
|
gem.email = "grosser.michael@gmail.com"
|
13
13
|
gem.homepage = "http://github.com/grosser/#{gem.name}"
|
14
14
|
gem.authors = ["Michael Grosser"]
|
15
|
-
|
16
|
-
|
17
|
-
# if parallel was a dependency, every requirement of rubygems would
|
18
|
-
# load parallel, which causes overhead and problems
|
19
|
-
gem.post_install_message = <<-POST_INSTALL_MESSAGE
|
20
|
-
#{'*'*50}
|
21
|
-
|
22
|
-
Since parallel cannot be a dependency, please install by hand:
|
23
|
-
|
24
|
-
gem install parallel
|
25
|
-
|
26
|
-
#{'*'*50}
|
27
|
-
POST_INSTALL_MESSAGE
|
28
15
|
end
|
29
16
|
|
30
17
|
Jeweler::GemcutterTasks.new
|
data/Readme.md
CHANGED
@@ -5,6 +5,7 @@ Install
|
|
5
5
|
Usage
|
6
6
|
=====
|
7
7
|
The first run can take looooong, but after the caches are filled, its pretty fast.
|
8
|
+
|
8
9
|
gem dependent my_gem
|
9
10
|
|
10
11
|
--source URL Query this source (e.g. http://rubygems.org)
|
@@ -16,11 +17,11 @@ The first run can take looooong, but after the caches are filled, its pretty fas
|
|
16
17
|
Output
|
17
18
|
======
|
18
19
|
|
19
|
-
|
20
|
+
gem dependent my_gem --source http://rubygems.org
|
20
21
|
other_gem >= 1.2.1
|
21
22
|
even_more = 0.0.1
|
22
23
|
|
23
|
-
|
24
|
+
gem dependent XXX --source http://rubygems.org --no-progress | wc -l
|
24
25
|
|
25
26
|
# Fun-facts from 2010-11-03
|
26
27
|
bundler: 263
|
@@ -36,12 +37,12 @@ Output
|
|
36
37
|
|
37
38
|
TODO
|
38
39
|
=====
|
39
|
-
- include
|
40
|
+
- include nested dependencies (a > b > c --> a = [b,c])
|
40
41
|
- add tests for cli interface
|
41
42
|
- add `--type development` support
|
42
43
|
|
43
44
|
Author
|
44
45
|
======
|
45
|
-
[Michael Grosser](http://grosser.it)
|
46
|
-
|
46
|
+
[Michael Grosser](http://grosser.it)<br/>
|
47
|
+
michael@grosse.it<br/>
|
47
48
|
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
data/gem-dependent.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{gem-dependent}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Michael Grosser"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-08-21}
|
13
13
|
s.email = %q{grosser.michael@gmail.com}
|
14
14
|
s.files = [
|
15
15
|
"Gemfile",
|
@@ -20,19 +20,12 @@ Gem::Specification.new do |s|
|
|
20
20
|
"gem-dependent.gemspec",
|
21
21
|
"lib/rubygems/commands/dependent_command.rb",
|
22
22
|
"lib/rubygems/dependent.rb",
|
23
|
+
"lib/rubygems/dependent_parallel.rb",
|
23
24
|
"lib/rubygems_plugin.rb",
|
24
25
|
"spec/dependent_spec.rb",
|
25
26
|
"spec/fixtures/gemcutter_specs.yml"
|
26
27
|
]
|
27
28
|
s.homepage = %q{http://github.com/grosser/gem-dependent}
|
28
|
-
s.post_install_message = %q{**************************************************
|
29
|
-
|
30
|
-
Since parallel cannot be a dependency, please install by hand:
|
31
|
-
|
32
|
-
gem install parallel
|
33
|
-
|
34
|
-
**************************************************
|
35
|
-
}
|
36
29
|
s.rdoc_options = ["--charset=UTF-8"]
|
37
30
|
s.require_paths = ["lib"]
|
38
31
|
s.rubygems_version = %q{1.6.2}
|
data/lib/rubygems/dependent.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems/dependent_parallel'
|
2
2
|
require 'rubygems/spec_fetcher'
|
3
3
|
|
4
|
-
# older parallel versions can produce strange bugs
|
5
|
-
puts "update parallel gem" if Parallel::VERSION < '0.5.1'
|
6
|
-
|
7
4
|
module Gem
|
8
5
|
class Dependent
|
9
6
|
VERSION = File.read( File.join(File.dirname(__FILE__),'..','..','VERSION') ).strip
|
@@ -34,7 +31,7 @@ module Gem
|
|
34
31
|
|
35
32
|
def self.fetch_all_dependencies(specs_and_sources, options)
|
36
33
|
parallel = (options[:parallel] || 15)
|
37
|
-
Parallel.map(specs_and_sources, :in_processes => parallel) do |spec, source|
|
34
|
+
Gem::Dependent::Parallel.map(specs_and_sources, :in_processes => parallel) do |spec, source|
|
38
35
|
yield if block_given?
|
39
36
|
name = spec.first
|
40
37
|
dependencies = fetch_dependencies(spec, source)
|
@@ -0,0 +1,272 @@
|
|
1
|
+
# if parallel was a dependency, every requirement of rubygems would
|
2
|
+
# load parallel, which causes overhead and problems
|
3
|
+
# copied from https://github.com/grosser/parallel/blob/master/lib/parallel.rb
|
4
|
+
|
5
|
+
require 'thread' # to get Thread.exclusive
|
6
|
+
require 'base64'
|
7
|
+
require 'rbconfig'
|
8
|
+
|
9
|
+
module Gem;end
|
10
|
+
class Gem::Dependent;end
|
11
|
+
class Gem::Dependent::Parallel
|
12
|
+
VERSION = '0.5.8'
|
13
|
+
|
14
|
+
def self.in_threads(options={:count => 2})
|
15
|
+
count, options = extract_count_from_options(options)
|
16
|
+
|
17
|
+
out = []
|
18
|
+
threads = []
|
19
|
+
|
20
|
+
count.times do |i|
|
21
|
+
threads[i] = Thread.new do
|
22
|
+
out[i] = yield(i)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
wait_for_threads(threads)
|
27
|
+
|
28
|
+
out
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.in_processes(options = {}, &block)
|
32
|
+
count, options = extract_count_from_options(options)
|
33
|
+
count ||= processor_count
|
34
|
+
map(0...count, options.merge(:in_processes => count), &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.each(array, options={}, &block)
|
38
|
+
map(array, options.merge(:preserve_results => false), &block)
|
39
|
+
array
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.each_with_index(array, options={}, &block)
|
43
|
+
each(array, options.merge(:with_index => true), &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.map(array, options = {}, &block)
|
47
|
+
array = array.to_a # turn Range and other Enumerable-s into an Array
|
48
|
+
|
49
|
+
if options[:in_threads]
|
50
|
+
method = :in_threads
|
51
|
+
size = options[method]
|
52
|
+
else
|
53
|
+
method = :in_processes
|
54
|
+
size = options[method] || processor_count
|
55
|
+
end
|
56
|
+
size = [array.size, size].min
|
57
|
+
|
58
|
+
return work_direct(array, options, &block) if size == 0
|
59
|
+
|
60
|
+
if method == :in_threads
|
61
|
+
work_in_threads(array, options.merge(:count => size), &block)
|
62
|
+
else
|
63
|
+
work_in_processes(array, options.merge(:count => size), &block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.map_with_index(array, options={}, &block)
|
68
|
+
map(array, options.merge(:with_index => true), &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.processor_count
|
72
|
+
case RbConfig::CONFIG['host_os']
|
73
|
+
when /darwin9/
|
74
|
+
`hwprefs cpu_count`.to_i
|
75
|
+
when /darwin/
|
76
|
+
(hwprefs_available? ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
|
77
|
+
when /linux/
|
78
|
+
`grep -c processor /proc/cpuinfo`.to_i
|
79
|
+
when /freebsd/
|
80
|
+
`sysctl -n hw.ncpu`.to_i
|
81
|
+
when /mswin|mingw/
|
82
|
+
require 'win32ole'
|
83
|
+
wmi = WIN32OLE.connect("winmgmts://")
|
84
|
+
cpu = wmi.ExecQuery("select NumberOfLogicalProcessors from Win32_Processor")
|
85
|
+
cpu.to_enum.first.NumberOfLogicalProcessors
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def self.work_direct(array, options)
|
92
|
+
results = []
|
93
|
+
array.each_with_index do |e,i|
|
94
|
+
results << (options[:with_index] ? yield(e,i) : yield(e))
|
95
|
+
end
|
96
|
+
results
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.hwprefs_available?
|
100
|
+
`which hwprefs` != ''
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.work_in_threads(items, options, &block)
|
104
|
+
results = []
|
105
|
+
current = -1
|
106
|
+
exception = nil
|
107
|
+
|
108
|
+
in_threads(options[:count]) do
|
109
|
+
# as long as there are more items, work on one of them
|
110
|
+
loop do
|
111
|
+
break if exception
|
112
|
+
|
113
|
+
index = Thread.exclusive{ current+=1 }
|
114
|
+
break if index >= items.size
|
115
|
+
|
116
|
+
begin
|
117
|
+
results[index] = call_with_index(items, index, options, &block)
|
118
|
+
rescue Exception => e
|
119
|
+
exception = e
|
120
|
+
break
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
raise exception if exception
|
126
|
+
|
127
|
+
results
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.work_in_processes(items, options, &blk)
|
131
|
+
current_index = -1
|
132
|
+
results = []
|
133
|
+
pids = []
|
134
|
+
exception = nil
|
135
|
+
|
136
|
+
kill_on_ctrl_c(pids)
|
137
|
+
|
138
|
+
in_threads(options[:count]) do |i|
|
139
|
+
x = i
|
140
|
+
worker = worker(items, options, &blk)
|
141
|
+
pids[i] = worker[:pid]
|
142
|
+
|
143
|
+
begin
|
144
|
+
loop do
|
145
|
+
break if exception
|
146
|
+
index = Thread.exclusive{ current_index += 1 }
|
147
|
+
break if index >= items.size
|
148
|
+
|
149
|
+
write_to_pipe(worker[:write], index)
|
150
|
+
output = decode(worker[:read].gets.chomp)
|
151
|
+
|
152
|
+
if ExceptionWrapper === output
|
153
|
+
exception = output.exception
|
154
|
+
else
|
155
|
+
results[index] = output
|
156
|
+
end
|
157
|
+
end
|
158
|
+
ensure
|
159
|
+
worker[:read].close
|
160
|
+
worker[:write].close
|
161
|
+
|
162
|
+
# if it goes zombie, rather wait here to be able to debug
|
163
|
+
wait_for_process worker[:pid]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
raise exception if exception
|
168
|
+
|
169
|
+
results
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.worker(items, options, &block)
|
173
|
+
# use less memory on REE
|
174
|
+
GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
|
175
|
+
|
176
|
+
child_read, parent_write = IO.pipe
|
177
|
+
parent_read, child_write = IO.pipe
|
178
|
+
|
179
|
+
pid = Process.fork do
|
180
|
+
begin
|
181
|
+
parent_write.close
|
182
|
+
parent_read.close
|
183
|
+
|
184
|
+
process_incoming_jobs(child_read, child_write, items, options, &block)
|
185
|
+
ensure
|
186
|
+
child_read.close
|
187
|
+
child_write.close
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
child_read.close
|
192
|
+
child_write.close
|
193
|
+
|
194
|
+
{:read => parent_read, :write => parent_write, :pid => pid}
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.process_incoming_jobs(read, write, items, options, &block)
|
198
|
+
while input = read.gets and input != "\n"
|
199
|
+
index = decode(input.chomp)
|
200
|
+
begin
|
201
|
+
result = call_with_index(items, index, options, &block)
|
202
|
+
result = nil if options[:preserve_results] == false
|
203
|
+
rescue Exception => e
|
204
|
+
result = ExceptionWrapper.new(e)
|
205
|
+
end
|
206
|
+
write_to_pipe(write, result)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.write_to_pipe(pipe, item)
|
211
|
+
pipe.write(encode(item))
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.wait_for_threads(threads)
|
215
|
+
threads.compact.each do |t|
|
216
|
+
begin
|
217
|
+
t.join
|
218
|
+
rescue Interrupt
|
219
|
+
# thread died, do not stop other threads
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.wait_for_process(pid)
|
225
|
+
begin
|
226
|
+
Process.wait(pid)
|
227
|
+
rescue Interrupt
|
228
|
+
# process died
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def self.encode(obj)
|
233
|
+
Base64.encode64(Marshal.dump(obj)).split("\n").join + "\n"
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.decode(str)
|
237
|
+
Marshal.load(Base64.decode64(str))
|
238
|
+
end
|
239
|
+
|
240
|
+
# options is either a Integer or a Hash with :count
|
241
|
+
def self.extract_count_from_options(options)
|
242
|
+
if options.is_a?(Hash)
|
243
|
+
count = options[:count]
|
244
|
+
else
|
245
|
+
count = options
|
246
|
+
options = {}
|
247
|
+
end
|
248
|
+
[count, options]
|
249
|
+
end
|
250
|
+
|
251
|
+
# kill all these processes (children) if user presses Ctrl+c
|
252
|
+
def self.kill_on_ctrl_c(pids)
|
253
|
+
Signal.trap :SIGINT do
|
254
|
+
$stderr.puts 'Parallel execution interrupted, exiting ...'
|
255
|
+
pids.each { |pid| Process.kill(:KILL, pid) if pid }
|
256
|
+
exit 1 # Quit with 'failed' signal
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def self.call_with_index(array, index, options, &block)
|
261
|
+
args = [array[index]]
|
262
|
+
args << index if options[:with_index]
|
263
|
+
block.call(*args)
|
264
|
+
end
|
265
|
+
|
266
|
+
class ExceptionWrapper
|
267
|
+
attr_reader :exception
|
268
|
+
def initialize(exception)
|
269
|
+
@exception = exception
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
data/spec/dependent_spec.rb
CHANGED
@@ -53,7 +53,7 @@ describe Gem::Dependent do
|
|
53
53
|
|
54
54
|
it "obeys parallel option" do
|
55
55
|
stub_source
|
56
|
-
Parallel.should_receive(:map).with(anything, :in_processes => 3).and_return []
|
56
|
+
Gem::Dependent::Parallel.should_receive(:map).with(anything, :in_processes => 3).and_return []
|
57
57
|
Gem::Dependent.find('hoe', :parallel => 3)
|
58
58
|
end
|
59
59
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gem-dependent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 7
|
10
|
+
version: 0.1.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michael Grosser
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-21 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- gem-dependent.gemspec
|
37
37
|
- lib/rubygems/commands/dependent_command.rb
|
38
38
|
- lib/rubygems/dependent.rb
|
39
|
+
- lib/rubygems/dependent_parallel.rb
|
39
40
|
- lib/rubygems_plugin.rb
|
40
41
|
- spec/dependent_spec.rb
|
41
42
|
- spec/fixtures/gemcutter_specs.yml
|
@@ -43,15 +44,7 @@ has_rdoc: true
|
|
43
44
|
homepage: http://github.com/grosser/gem-dependent
|
44
45
|
licenses: []
|
45
46
|
|
46
|
-
post_install_message:
|
47
|
-
**************************************************
|
48
|
-
|
49
|
-
Since parallel cannot be a dependency, please install by hand:
|
50
|
-
|
51
|
-
gem install parallel
|
52
|
-
|
53
|
-
**************************************************
|
54
|
-
|
47
|
+
post_install_message:
|
55
48
|
rdoc_options:
|
56
49
|
- --charset=UTF-8
|
57
50
|
require_paths:
|