parallel_run 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = "tests/*_test.rb"
9
+ t.verbose = true
10
+ end
11
+
12
+ task :default => :test
data/lib/parallel_run.rb CHANGED
@@ -43,6 +43,11 @@ optparse = OptionParser.new do|opts|
43
43
  $options[:workers] = c
44
44
  end
45
45
 
46
+ $options[:retry] = 1
47
+ opts.on('--retry RETRY', Integer, "Number of retry for each command") do |c|
48
+ $options[:retry] = c
49
+ end
50
+
46
51
  opts.on('-h', '--help', 'Display this screen' ) do
47
52
  puts opts
48
53
  puts "Values can be used directly in command or prefix directly by using %v."
@@ -74,45 +79,68 @@ def replace s, value, k
74
79
  s = s.gsub(/%k/, k.to_s)
75
80
  s
76
81
  end
82
+
77
83
  module Enumerable
78
84
 
79
- def _peach_run(pool = nil, &b)
80
- pool ||= count
81
- pool = 1 unless pool >= 1
82
- div = (count.to_f/pool.to_f).ceil # should already be integer
83
- div = 1 unless div >= 1 # each thread better do something!
85
+ def in_groups(number, fill_with = nil)
86
+ # size / number gives minor group size;
87
+ # size % number gives how many objects need extra accomodation;
88
+ # each group hold either division or division + 1 items.
89
+ division = size / number
90
+ modulo = size % number
91
+
92
+ # create a new array avoiding dup
93
+ groups = []
94
+ start = 0
95
+
96
+ number.times do |index|
97
+ length = division + (modulo > 0 && modulo > index ? 1 : 0)
98
+ padding = fill_with != false &&
99
+ modulo > 0 && length == division ? 1 : 0
100
+ groups << slice(start, length).concat([fill_with] * padding)
101
+ start += length
102
+ end
103
+
104
+ if block_given?
105
+ groups.each{|g| yield(g) }
106
+ else
107
+ groups
108
+ end
109
+ end
110
+
111
+ def peach(workers = nil, &b)
112
+ workers ||= count
84
113
 
85
114
  threads = []
86
- each_slice(div).with_index do |slice, idx|
115
+ in_groups(workers, false).each do |slice|
87
116
  threads << Thread.new(slice) do |thread_slice|
88
- yield thread_slice, idx, div
117
+ thread_slice.each{|elt| yield elt}
89
118
  end
90
119
  end
91
120
  threads.each{|t| t.join }
92
121
  self
93
122
  end
94
123
 
95
- def peach(pool = nil, &b)
96
- _peach_run(pool) do |thread_slice, idx, div|
97
- thread_slice.each{|elt| yield elt}
98
- end
99
- end
100
-
101
124
  end
102
125
 
103
126
  result = {}
104
127
  ARGV.each_with_index.to_a.peach($options[:workers]) do |f, index|
128
+ try = $options[:retry]
105
129
  c = replace $options[:command], f, index
106
130
  prefix = replace $options[:prefix], f, index
107
- output("Lauching command for #{f} : #{c}", prefix) if $options[:verbose]
108
- full_cmd = "#{$options[:shell]} -c \"#{c.gsub(/"/, "\\\"")}\""
109
- status = POpen4::popen4(full_cmd, 'r') do |stdout, stderr, stdin, pid|
110
- [stdout, stderr].peach do |io|
111
- flow = io == stderr ? "err" : "out"
112
- while !io.eof?
113
- output io.readline, prefix, flow
131
+ while try > 0
132
+ output("Lauching command for #{f} : #{c}", prefix) if $options[:verbose]
133
+ full_cmd = "#{$options[:shell]} -c \"#{c.gsub(/"/, "\\\"")}\""
134
+ status = POpen4::popen4(full_cmd, 'r') do |stdout, stderr, stdin, pid|
135
+ [stdout, stderr].peach do |io|
136
+ flow = io == stderr ? "err" : "out"
137
+ while !io.eof?
138
+ output io.readline, prefix, flow
139
+ end
114
140
  end
115
141
  end
142
+ break if status.exitstatus == 0
143
+ try -= 1
116
144
  end
117
145
  result[f] = {
118
146
  :command => c,
data/parallel_run.gemspec CHANGED
@@ -4,7 +4,7 @@ $:.push File.expand_path("../lib", __FILE__)
4
4
  Gem::Specification.new do |s|
5
5
 
6
6
  s.name = "parallel_run"
7
- s.version = "0.4"
7
+ s.version = "0.5"
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Bertrand Paquet"]
10
10
  s.email = ["bertrand.paquet@gmail.com"]
data/tests/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require 'tempfile'
3
+
4
+ def parallel_run command_line, script
5
+ f = Tempfile.new 'script'
6
+ f.write script
7
+ f.close
8
+ File.chmod(0700, f.path)
9
+ command_line = command_line.gsub(/%s/, f.path)
10
+ exec = File.join(File.dirname(__FILE__), '..', 'bin', 'parallel_run')
11
+ path = File.join(File.dirname(__FILE__), '..', 'lib')
12
+ result = %x{RUBYLIB=#{path} #{exec} #{command_line}}
13
+ code = $?.exitstatus
14
+ return code, result
15
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), 'helper.rb')
2
+
3
+ class RetrySimple < Test::Unit::TestCase
4
+
5
+ def test_no_retry
6
+ %x{rm -f /tmp/toto}
7
+ code, result = parallel_run "--command \"%s %k\" 1 2 3 4", <<-EOF
8
+ #!/bin/sh
9
+
10
+ sleep $1
11
+ test -f /tmp/toto
12
+ result=$?
13
+ touch /tmp/toto
14
+ exit $result
15
+ EOF
16
+ assert_equal 1, code
17
+ %x{rm -f /tmp/toto}
18
+ end
19
+
20
+ def test_retry
21
+ %x{rm -f /tmp/toto}
22
+ code, result = parallel_run "--retry 2 --command \"%s %k\" 1 2 3 4", <<-EOF
23
+ #!/bin/sh
24
+
25
+ sleep $1
26
+ test -f /tmp/toto
27
+ result=$?
28
+ touch /tmp/toto
29
+ exit $result
30
+ EOF
31
+ assert_equal 0, code
32
+ %x{rm -f /tmp/toto}
33
+ end
34
+
35
+ end
@@ -0,0 +1,107 @@
1
+ require File.join(File.dirname(__FILE__), 'helper.rb')
2
+
3
+ class TestSimple < Test::Unit::TestCase
4
+
5
+ def test_index
6
+ code, result = parallel_run "--command \"%s %k\" val0/5 val1/6 val2/7 val3/8 val4/9", <<-EOF
7
+ #!/bin/sh
8
+ echo $1
9
+ EOF
10
+ assert_equal 0, code
11
+ [0, 1, 2, 3, 4].each do |x|
12
+ assert result.match(/#{x}$/), "Not found #{x}"
13
+ end
14
+ end
15
+
16
+ def test_value
17
+ code, result = parallel_run "--command \"%s %v\" val0/5 val1/6 val2/7 val3/8 val4/9", <<-EOF
18
+ #!/bin/sh
19
+ echo $1
20
+ EOF
21
+ assert_equal 0, code
22
+ [0, 1, 2, 3, 4].each do |x|
23
+ assert result.match(/val#{x}\/#{x + 5}$/), "Not found #{x}"
24
+ end
25
+ end
26
+
27
+ def test_dirname
28
+ code, result = parallel_run "--command \"%s %d\" val0/5 val1/6 val2/7 val3/8 val4/9", <<-EOF
29
+ #!/bin/sh
30
+ echo $1
31
+ EOF
32
+ assert_equal 0, code
33
+ [0, 1, 2, 3, 4].each do |x|
34
+ assert result.match(/val#{x}$/), "Not found #{x}"
35
+ end
36
+ end
37
+
38
+ def test_basename
39
+ code, result = parallel_run "--command \"%s %b\" val0/5 val1/6 val2/7 val3/8 val4/9", <<-EOF
40
+ #!/bin/sh
41
+ echo $1
42
+ EOF
43
+ assert_equal 0, code
44
+ [0, 1, 2, 3, 4].each do |x|
45
+ assert result.match(/#{x + 5}$/), "Not found #{x}"
46
+ end
47
+ end
48
+
49
+ def test_shell
50
+ code, result = parallel_run "--command \"%s\" 1", <<-EOF
51
+ echo $BASH
52
+ EOF
53
+ assert_equal 0, code
54
+ assert result.match(/#{ENV['SHELL']}/)
55
+ end
56
+
57
+ def test_shell_sh
58
+ code, result = parallel_run "--shell /bin/sh --command \"%s\" 1", <<-EOF
59
+ echo $BASH
60
+ EOF
61
+ assert_equal 0, code
62
+ assert result.match(/\/bin\/sh/)
63
+ end
64
+
65
+ def test_parallel
66
+ code, result = parallel_run "--command \"%s %k\" 1 2 3 4 5", <<-EOF
67
+ #!/bin/sh
68
+ echo Start $1
69
+ sleep 0.5
70
+ echo Stop $1
71
+ sleep 0.5
72
+ EOF
73
+ assert_equal 0, code
74
+ start = 0
75
+ stop = 0
76
+ result.split(/\n/).each do |x|
77
+ start += 1 if x.match(/Start/)
78
+ stop += 1 if x.match(/Stop/)
79
+ assert_equal 5, start if stop == 1
80
+ end
81
+ assert_equal 5, start
82
+ assert_equal 5, stop
83
+ end
84
+
85
+ def test_one_fail
86
+ code, result = parallel_run "--command \"%s %k\" val1 val2 val3 val4 val5", <<-EOF
87
+ if [ "$1" = 2 ]; then
88
+ exit 2
89
+ fi
90
+ EOF
91
+ assert_equal 1, code
92
+ assert result.match(/Command failed : val3/)
93
+ assert ! result.match(/Command failed : val2/)
94
+ end
95
+
96
+ def test_all_fail
97
+ code, result = parallel_run "--command \"%s %k\" val1 val2 val3 val4 val5", <<-EOF
98
+ exit 2
99
+ EOF
100
+ assert_equal 1, code
101
+ [1, 2, 3, 4, 5].each do |x|
102
+ assert result.match(/Command failed : val#{x}/)
103
+ end
104
+ end
105
+
106
+ end
107
+
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), 'helper.rb')
2
+
3
+ class WorkerSimple < Test::Unit::TestCase
4
+
5
+ def test_worker_two
6
+ code, result = parallel_run "--workers 2 --command \"%s %k\" 1 2 3 4", <<-EOF
7
+ #!/bin/sh
8
+ echo Start $1
9
+ sleep 0.5
10
+ echo Stop $1
11
+ sleep 0.5
12
+ EOF
13
+ assert_equal 0, code
14
+ start = 0
15
+ stop = 0
16
+ result.split(/\n/).each do |x|
17
+ start += 1 if x.match(/Start/)
18
+ if x.match(/Stop/)
19
+ stop += 1
20
+ assert_equal 2, start if stop == 2
21
+ end
22
+ end
23
+ assert_equal 4, start
24
+ assert_equal 4, stop
25
+ end
26
+
27
+ def test_worker_three
28
+ code, result = parallel_run "--workers 3 --command \"%s %k\" 1 2 3 4", <<-EOF
29
+ #!/bin/sh
30
+ echo Start $1
31
+ sleep 0.5
32
+ echo Stop $1
33
+ sleep 0.5
34
+ EOF
35
+ assert_equal 0, code
36
+ start = 0
37
+ stop = 0
38
+ result.split(/\n/).each do |x|
39
+ start += 1 if x.match(/Start/)
40
+ if x.match(/Stop/)
41
+ stop += 1
42
+ assert_equal 3, start if stop == 3
43
+ end
44
+ end
45
+ assert_equal 4, start
46
+ assert_equal 4, stop
47
+ end
48
+
49
+ def test_worker_one
50
+ code, result = parallel_run "--workers 1 --command \"%s %k\" 1 2 3 4", <<-EOF
51
+ #!/bin/sh
52
+ echo Start $1
53
+ sleep 0.5
54
+ echo Stop $1
55
+ sleep 0.5
56
+ EOF
57
+ assert_equal 0, code
58
+ start = 0
59
+ stop = 0
60
+ result.split(/\n/).each do |x|
61
+ start += 1 if x.match(/Start/)
62
+ if x.match(/Stop/)
63
+ stop += 1
64
+ assert_equal stop, start
65
+ end
66
+ end
67
+ assert_equal 4, start
68
+ assert_equal 4, stop
69
+ end
70
+
71
+ def test_worker_impair_one
72
+ code, result = parallel_run "--workers 1 --command \"%s %k\" 1 2 3 4 5 6 7 8 9", <<-EOF
73
+ #!/bin/sh
74
+ echo Start $1
75
+ sleep 0.5
76
+ echo Stop $1
77
+ sleep 0.5
78
+ EOF
79
+ assert_equal 0, code
80
+ start = 0
81
+ stop = 0
82
+ result.split(/\n/).each do |x|
83
+ start += 1 if x.match(/Start/)
84
+ if x.match(/Stop/)
85
+ stop += 1
86
+ assert_equal stop, start
87
+ end
88
+ end
89
+ assert_equal 9, start
90
+ assert_equal 9, stop
91
+ end
92
+
93
+ def test_worker_impair_two
94
+ code, result = parallel_run "--workers 2 --command \"%s %k\" 1 2 3 4 5 6 7 8 9", <<-EOF
95
+ #!/bin/sh
96
+ echo Start $1
97
+ sleep 0.5
98
+ echo Stop $1
99
+ sleep 0.5
100
+ EOF
101
+ assert_equal 0, code
102
+ start = 0
103
+ stop = 0
104
+ result.split(/\n/).each do |x|
105
+ start += 1 if x.match(/Start/)
106
+ if x.match(/Stop/)
107
+ stop += 1
108
+ assert_equal stop, start if stop % 2 == 0
109
+ end
110
+ end
111
+ assert_equal 9, start
112
+ assert_equal 9, stop
113
+ end
114
+
115
+ def test_worker_impair_three
116
+ code, result = parallel_run "--workers 3 --command \"%s %k\" 1 2 3 4 5 6 7 8 9", <<-EOF
117
+ #!/bin/sh
118
+ echo Start $1
119
+ sleep 0.5
120
+ echo Stop $1
121
+ sleep 0.5
122
+ EOF
123
+ assert_equal 0, code
124
+ start = 0
125
+ stop = 0
126
+ result.split(/\n/).each do |x|
127
+ start += 1 if x.match(/Start/)
128
+ if x.match(/Stop/)
129
+ stop += 1
130
+ assert_equal stop, start if stop % 3 == 0
131
+ end
132
+ end
133
+ assert_equal 9, start
134
+ assert_equal 9, stop
135
+ end
136
+
137
+ def test_worker_impair_for
138
+ code, result = parallel_run "--workers 4 --command \"%s %k\" 1 2 3 4 5 6 7 8 9", <<-EOF
139
+ #!/bin/sh
140
+ echo Start $1
141
+ sleep 0.5
142
+ echo Stop $1
143
+ sleep 0.5
144
+ EOF
145
+ assert_equal 0, code
146
+ start = 0
147
+ stop = 0
148
+ result.split(/\n/).each do |x|
149
+ start += 1 if x.match(/Start/)
150
+ if x.match(/Stop/)
151
+ stop += 1
152
+ assert_equal stop, start if stop == 4
153
+ end
154
+ end
155
+ assert_equal 9, start
156
+ assert_equal 9, stop
157
+ end
158
+
159
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_run
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-06 00:00:00.000000000 Z
12
+ date: 2013-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: popen4
@@ -44,6 +44,10 @@ files:
44
44
  - bin/parallel_run
45
45
  - lib/parallel_run.rb
46
46
  - parallel_run.gemspec
47
+ - tests/helper.rb
48
+ - tests/retry_test.rb
49
+ - tests/simple_test.rb
50
+ - tests/worker_test.rb
47
51
  homepage: http://github.com/bpaquet/parallel_run
48
52
  licenses: []
49
53
  post_install_message: