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 CHANGED
@@ -4,5 +4,4 @@ group :dev do
4
4
  gem 'rake'
5
5
  gem 'rspec', '~>2'
6
6
  gem 'jeweler'
7
- gem 'parallel', '>= 0.5.1'
8
- end
7
+ end
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
- $ gem dependent my_gem --source http://rubygems.org
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
- $ gem dependent XXX --source http://rubygems.org --no-progress | wc -l
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 reverse dependencies (a > b > c --> a = [b,c])
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
- grosser.michael@gmail.com
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.6
1
+ 0.1.7
@@ -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.6"
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-05-09}
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}
@@ -1,9 +1,6 @@
1
- require 'parallel'
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
@@ -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: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 6
10
- version: 0.1.6
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-05-09 00:00:00 +02:00
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: