pdo 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/bin/pdo CHANGED
@@ -3,17 +3,15 @@
3
3
  lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include? lib
5
5
 
6
- #require 'pdo/version'
7
-
8
6
  require 'ostruct'
9
7
  require 'pdo'
10
8
  require 'pdo/logging'
11
9
  require 'pdo/host'
12
- require 'pdo/pdoopts'
10
+ require 'pdo/opts'
13
11
  require 'pdo/task'
14
12
  require 'pp'
15
13
 
16
- include Logging
14
+ include PDO
17
15
 
18
16
  opts = OpenStruct.new
19
17
  # setting default values
@@ -26,7 +24,7 @@ opts.nohush = false
26
24
 
27
25
  begin
28
26
  # parse ARGV; defaults in opts is overwritten if needed
29
- opts = PdoOpts.parse(ARGV, opts)
27
+ opts = Opts.parse(ARGV, opts)
30
28
  logger.debug { opts }
31
29
  rescue => err
32
30
  logger.error { "#{err.class}: #{err.message}" }
@@ -34,7 +32,6 @@ rescue => err
34
32
  exit 1
35
33
  end
36
34
 
37
- include Host
38
35
  Host.load_file opts.host_definition_file
39
36
 
40
37
  excludes = []
@@ -82,7 +79,7 @@ if opts.groups then
82
79
  end
83
80
  end
84
81
  end
85
- pdo = PDO.new(tasks, opts.thread_num)
82
+ pdo = Worker.new(tasks, opts.thread_num)
86
83
  pdo.run
87
84
  else
88
85
  opts.groups.each do |key|
data/lib/pdo.rb CHANGED
@@ -2,88 +2,90 @@
2
2
 
3
3
  require 'pdo/logging'
4
4
 
5
- class PDO
6
- include Process
7
- include Logging
5
+ module PDO
6
+ class Worker
7
+ include Process
8
+ include Logging
8
9
 
9
- def initialize(tasks, thread_num)
10
- @tasks = tasks
11
- @thread_num = thread_num
12
- end
10
+ def initialize(tasks, thread_num)
11
+ @tasks = tasks
12
+ @thread_num = thread_num
13
+ end
13
14
 
14
- def run
15
- # run first spawns a set of threads, tells them to execute the task
16
- # queue. it then loop through the current Thread list (note
17
- # Thread.list returns all running and sleeping threads), and outputs
18
- # those new data.
19
- # for the spawned threads, they execute one task, then wait for their
20
- # data to be picked up by the main thread, then do the next task.
15
+ def run
16
+ # run first spawns a set of threads, tells them to execute the task
17
+ # queue. it then loop through the current Thread list (note
18
+ # Thread.list returns all running and sleeping threads), and outputs
19
+ # those new data.
20
+ # for the spawned threads, they execute one task, then wait for their
21
+ # data to be picked up by the main thread, then do the next task.
21
22
 
22
- return 1 if @tasks.size == 0
23
+ return 1 if @tasks.size == 0
23
24
 
24
- n = @thread_num < @tasks.size ? @thread_num : @tasks.size
25
- 1.upto(n) do
26
- Thread.new do
27
- while true do
28
- logger.info "#{Thread.current.object_id} started."
29
- begin
30
- execute(@tasks.next)
31
- # presumably new data is ready, thus i stop.
32
- # main thread will read :output and then wakes me up.
33
- Thread.stop
34
- rescue
35
- logger.info "No more task for #{Thread.current.object_id}."
36
- break
25
+ n = @thread_num < @tasks.size ? @thread_num : @tasks.size
26
+ 1.upto(n) do
27
+ Thread.new do
28
+ while true do
29
+ logger.info "#{Thread.current.object_id} started."
30
+ begin
31
+ execute(@tasks.next)
32
+ # presumably new data is ready, thus i stop.
33
+ # main thread will read :output and then wakes me up.
34
+ Thread.stop
35
+ rescue
36
+ logger.info "No more task for #{Thread.current.object_id}."
37
+ break
38
+ end
37
39
  end
38
40
  end
39
41
  end
40
- end
41
42
 
42
- loop do
43
- # break because the only left thread must be the main thread.
44
- break if Thread.list.size == 1
43
+ loop do
44
+ # break because the only left thread must be the main thread.
45
+ break if Thread.list.size == 1
45
46
 
46
- Thread.list.each do |t|
47
- next if t == Thread.main
48
- if t.key? :output and t.key? :new_data and t[:new_data] then
49
- logger.info "#{t.object_id} finished."
50
- puts "=== #{t[:target]} ==="
51
- t[:output].each {|x| puts x}
52
- # puts t[:output].join('').gsub("\n", ' | ').chomp(' | ')
53
- t[:new_data] = false
54
- # wakes up the thread
55
- t.run
47
+ Thread.list.each do |t|
48
+ next if t == Thread.main
49
+ if t.key? :output and t.key? :new_data and t[:new_data] then
50
+ logger.info "#{t.object_id} finished."
51
+ puts "=== #{t[:target]} ==="
52
+ t[:output].each {|x| puts x}
53
+ # puts t[:output].join('').gsub("\n", ' | ').chomp(' | ')
54
+ t[:new_data] = false
55
+ # wakes up the thread
56
+ t.run
57
+ end
56
58
  end
57
59
  end
58
60
  end
59
- end
60
61
 
61
- def execute(task)
62
- # execute forks a child process to run the task, then saves the
63
- # output from the child process into a thread local variable, marks
64
- # the :new_data tag.
62
+ def execute(task)
63
+ # execute forks a child process to run the task, then saves the
64
+ # output from the child process into a thread local variable, marks
65
+ # the :new_data tag.
65
66
 
66
- raise "no task" if task.nil?
67
+ raise "no task" if task.nil?
67
68
 
68
- target, cmd = task
69
+ target, cmd = task
69
70
 
70
- open("|-") do |child_io|
71
- if child_io
72
- # The waitpid statement below causes the program to hang when
73
- # running some commands, such as wget.
74
- # waitpid child_io.pid
75
- Thread.current[:output] = child_io.readlines
76
- Thread.current[:new_data] = true
77
- Thread.current[:target] = target
78
- else
79
- STDIN.close
80
- STDERR.reopen(STDOUT)
81
- exec(*cmd)
71
+ open("|-") do |child_io|
72
+ if child_io
73
+ # The waitpid statement below causes the program to hang when
74
+ # running some commands, such as wget.
75
+ # waitpid child_io.pid
76
+ Thread.current[:output] = child_io.readlines
77
+ Thread.current[:new_data] = true
78
+ Thread.current[:target] = target
79
+ else
80
+ STDIN.close
81
+ STDERR.reopen(STDOUT)
82
+ exec(*cmd)
83
+ end
82
84
  end
83
- end
84
85
 
85
- end
86
+ end
86
87
 
87
- end
88
+ end # class Worker
89
+ end # module PDO
88
90
 
89
91
  # vim: set et ts=2 sts=2 sw=2 si sta :
@@ -4,186 +4,188 @@ require 'pp'
4
4
  require 'yaml'
5
5
  require_relative 'logging'
6
6
 
7
- module Host
8
-
9
- include Logging
10
-
11
- @@recursive_level = 9
12
- def self.recursive_level=(level)
13
- @@recursive_level = level
14
- end
15
- def self.recursive_level
16
- @@recursive_level
17
- end
18
-
19
- def self.load_file(def_file=nil)
20
- if def_file then
21
- files = [ def_file ]
22
- else
23
- files = [ "/etc/pdo/pdo.yaml", "#{ENV['HOME']}/.pdo/pdo.yaml", ]
24
- end
25
-
26
- hosts = {}
27
- files.each do |f|
28
- begin
29
- hosts.update(YAML::load_file(f))
30
- rescue => ex
31
- logger.warn { "#{ex.class}: #{ex.message}" }
32
- logger.debug { ex.backtrace.join "\n" }
33
- end
34
- end
35
- return @@host_hash = hosts
7
+ module PDO
8
+ module Host
36
9
 
37
- end
10
+ include Logging
38
11
 
39
- def expand_group(group, level)
40
- # given a group, recursively expand it into a list of hosts.
41
- # if the group can't expand to a list of hosts, return that group.
42
- # if there are exception expanding the group, return an empty list.
43
-
44
- hosts = []
45
-
46
- level += 1
47
- if level > @@recursive_level then
48
- logger.warn "circle detected in the host definition file."
49
- return []
12
+ @@recursive_level = 9
13
+ def self.recursive_level=(level)
14
+ @@recursive_level = level
15
+ end
16
+ def self.recursive_level
17
+ @@recursive_level
50
18
  end
51
19
 
52
- # get the hash value
53
- keys = group.gsub(/^\//,'').split('/')
54
- list_of_hosts = @@host_hash
55
- keys.each do |k|
56
- begin
57
- if list_of_hosts.key? k then
58
- list_of_hosts = list_of_hosts[k]
59
- else
60
- # if any part of the group name is not a key in the
61
- # host hash, then return the group.
62
- return [ group ]
20
+ def self.load_file(def_file=nil)
21
+ if def_file then
22
+ files = [ def_file ]
23
+ else
24
+ files = [ "/etc/pdo/pdo.yaml", "#{ENV['HOME']}/.pdo/pdo.yaml", ]
25
+ end
26
+
27
+ hosts = {}
28
+ files.each do |f|
29
+ begin
30
+ hosts.update(YAML::load_file(f))
31
+ rescue => ex
32
+ logger.warn { "#{ex.class}: #{ex.message}" }
33
+ logger.debug { ex.backtrace.join "\n" }
63
34
  end
64
- rescue => ex
65
- logger.warn {
66
- "failed to get hash value for #{group.inspect}. "\
67
- 'possibly an error in the yaml file.'
68
- }
69
- logger.debug { ex.backtrace.join "\n" }
70
- return []
71
35
  end
36
+ return @@host_hash = hosts
37
+
72
38
  end
39
+
40
+ def expand_group(group, level)
41
+ # given a group, recursively expand it into a list of hosts.
42
+ # if the group can't expand to a list of hosts, return that group.
43
+ # if there are exception expanding the group, return an empty list.
73
44
 
74
- # return empty array if the group is empty.
75
- return [] if list_of_hosts.nil?
45
+ hosts = []
76
46
 
77
- if list_of_hosts.is_a? Hash then
78
- list_of_hosts.keys.each do |key|
79
- hosts += expand_group("#{group}/#{key}".squeeze('/'), level)
47
+ level += 1
48
+ if level > @@recursive_level then
49
+ logger.warn "circle detected in the host definition file."
50
+ return []
80
51
  end
81
- elsif list_of_hosts.is_a? Array then
82
- list_of_hosts.each do |h|
83
- if not h.is_a? String then
52
+
53
+ # get the hash value
54
+ keys = group.gsub(/^\//,'').split('/')
55
+ list_of_hosts = @@host_hash
56
+ keys.each do |k|
57
+ begin
58
+ if list_of_hosts.key? k then
59
+ list_of_hosts = list_of_hosts[k]
60
+ else
61
+ # if any part of the group name is not a key in the
62
+ # host hash, then return the group.
63
+ return [ group ]
64
+ end
65
+ rescue => ex
84
66
  logger.warn {
85
- "invalid host or group format: #{h.inspect}\n"\
67
+ "failed to get hash value for #{group.inspect}. "\
86
68
  'possibly an error in the yaml file.'
87
69
  }
88
- next
70
+ logger.debug { ex.backtrace.join "\n" }
71
+ return []
72
+ end
73
+ end
74
+
75
+ # return empty array if the group is empty.
76
+ return [] if list_of_hosts.nil?
77
+
78
+ if list_of_hosts.is_a? Hash then
79
+ list_of_hosts.keys.each do |key|
80
+ hosts += expand_group("#{group}/#{key}".squeeze('/'), level)
89
81
  end
90
- if h.include? "/" then
91
- hosts += expand_group(h, level)
92
- else
93
- hosts << h
82
+ elsif list_of_hosts.is_a? Array then
83
+ list_of_hosts.each do |h|
84
+ if not h.is_a? String then
85
+ logger.warn {
86
+ "invalid host or group format: #{h.inspect}\n"\
87
+ 'possibly an error in the yaml file.'
88
+ }
89
+ next
90
+ end
91
+ if h.include? "/" then
92
+ hosts += expand_group(h, level)
93
+ else
94
+ hosts << h
95
+ end
94
96
  end
97
+ else
98
+ logger.fatal "I don't know how to handle this. "\
99
+ 'possibly an error in the yaml file.'
100
+ exit 1
95
101
  end
96
- else
97
- logger.fatal "I don't know how to handle this. "\
98
- 'possibly an error in the yaml file.'
99
- exit 1
102
+ return hosts
103
+
104
+ end # expand_group
105
+ private :expand_group
106
+
107
+ def get_hosts(group, step)
108
+ hosts = []
109
+ hosts += expand_group(group, 0)
110
+ hosts.uniq!
111
+ hosts = stepping hosts, step
112
+ return hosts
113
+
100
114
  end
101
- return hosts
102
-
103
- end # expand_group
104
- private :expand_group
105
115
 
106
- def get_hosts(group, step)
107
- hosts = []
108
- hosts += expand_group(group, 0)
109
- hosts.uniq!
110
- hosts = stepping hosts, step
111
- return hosts
112
-
113
- end
116
+ def stepping(hosts, step)
117
+ unless hosts.is_a? Array or step.is_a? Array then
118
+ logger.warn "both hosts or step should be array."
119
+ return nil
120
+ end
121
+
122
+ start, stride = step[0].to_i, step[1].to_i
123
+ # if stride > 0, stepping forward
124
+ # if stride < 0, stepping backward
125
+ # if stride == 0, no stepping
126
+ # if start or stride makes no sense, no stepping either
127
+ index = case
128
+ when stride > 0 then
129
+ (start-1...hosts.size).step(stride).to_a
130
+ when stride < 0 then
131
+ (-start+1..0).step(-stride).to_a.map {|x| -x}
132
+ else []
133
+ end
134
+
135
+ unless index.empty? then
136
+ alist = []
137
+ index.each do |i|
138
+ alist << hosts[i]
139
+ end
140
+ hosts = alist
141
+ end
114
142
 
115
- def stepping(hosts, step)
116
- unless hosts.is_a? Array or step.is_a? Array then
117
- logger.warn "both hosts or step should be array."
118
- return nil
143
+ return hosts
119
144
  end
120
-
121
- start, stride = step[0].to_i, step[1].to_i
122
- # if stride > 0, stepping forward
123
- # if stride < 0, stepping backward
124
- # if stride == 0, no stepping
125
- # if start or stride makes no sense, no stepping either
126
- index = case
127
- when stride > 0 then
128
- (start-1...hosts.size).step(stride).to_a
129
- when stride < 0 then
130
- (-start+1..0).step(-stride).to_a.map {|x| -x}
131
- else []
132
- end
133
-
134
- unless index.empty? then
135
- alist = []
136
- index.each do |i|
137
- alist << hosts[i]
138
- end
139
- hosts = alist
145
+
146
+ def show_hosts
147
+ pp @@host_hash
140
148
  end
141
149
 
142
- return hosts
143
- end
144
-
145
- def show_hosts
146
- pp @@host_hash
147
- end
148
-
149
- def get_sub_groups(group)
150
-
151
- keys = group.gsub(/^\//, '').split('/')
152
- pointer = @@host_hash
153
- keys.each do |k|
154
- begin
155
- if pointer.key? k then
156
- pointer = pointer[k]
157
- else
158
- # if any part of the given group name is not a key in the
159
- # host hash, then return an empty array.
160
- return [ ]
150
+ def get_sub_groups(group)
151
+
152
+ keys = group.gsub(/^\//, '').split('/')
153
+ pointer = @@host_hash
154
+ keys.each do |k|
155
+ begin
156
+ if pointer.key? k then
157
+ pointer = pointer[k]
158
+ else
159
+ # if any part of the given group name is not a key in the
160
+ # host hash, then return an empty array.
161
+ return [ ]
162
+ end
163
+ rescue => ex
164
+ logger.warn {
165
+ "failed to get hash value for #{group.inspect}. "\
166
+ 'maybe a wrong key is specifid?'
167
+ }
168
+ logger.debug { ex.backtrace.join "\n" }
169
+ return []
161
170
  end
162
- rescue => ex
163
- logger.warn {
164
- "failed to get hash value for #{group.inspect}. "\
165
- 'maybe a wrong key is specifid?'
166
- }
167
- logger.debug { ex.backtrace.join "\n" }
168
- return []
169
171
  end
170
- end
171
172
 
172
- # return empty array if the group is empty.
173
- return [] if pointer.nil?
174
-
175
- if pointer.is_a? Hash then
176
- return pointer.keys
177
- elsif pointer.is_a? Array then
178
- return pointer
179
- else
180
- logger.fatal "I don't know how to handle this. "\
181
- 'possibly an error in the yaml file.'
182
- exit 1
173
+ # return empty array if the group is empty.
174
+ return [] if pointer.nil?
175
+
176
+ if pointer.is_a? Hash then
177
+ return pointer.keys
178
+ elsif pointer.is_a? Array then
179
+ return pointer
180
+ else
181
+ logger.fatal "I don't know how to handle this. "\
182
+ 'possibly an error in the yaml file.'
183
+ exit 1
184
+ end
185
+
183
186
  end
184
-
185
- end
186
187
 
187
- end # module Host
188
+ end # module Host
189
+ end # module PDO
188
190
 
189
191
  # vim: set et ts=2 sts=2 sw=2 si sta :
@@ -4,28 +4,30 @@ require 'log4r'
4
4
  require 'log4r/yamlconfigurator'
5
5
  require 'log4r/outputter/datefileoutputter'
6
6
 
7
- module Logging
7
+ module PDO
8
+ module Logging
8
9
 
9
- include Log4r
10
- # set the default log directory
11
- Log4r::YamlConfigurator['LOGDIR'] =
12
- File.expand_path("#{File.dirname(__FILE__)}/../../log")
10
+ include Log4r
11
+ # set the default log directory
12
+ Log4r::YamlConfigurator['LOGDIR'] =
13
+ File.expand_path("#{File.dirname(__FILE__)}/../../log")
13
14
 
14
- def logger
15
+ def logger
15
16
 
16
- return @logger if @logger
17
+ return @logger if @logger
17
18
 
18
- conf_dir = File.expand_path("#{File.dirname(__FILE__)}/../../conf")
19
+ conf_dir = File.expand_path("#{File.dirname(__FILE__)}/../../conf")
19
20
 
20
- [conf_dir, '/etc/pdo', "#{ENV['HOME']}/.pdo"].each { |dir|
21
- conf = "#{dir}/log4r.yaml"
22
- Log4r::YamlConfigurator.load_yaml_file conf if File.exists? conf
23
- }
21
+ [conf_dir, '/etc/pdo', "#{ENV['HOME']}/.pdo"].each { |dir|
22
+ conf = "#{dir}/log4r.yaml"
23
+ Log4r::YamlConfigurator.load_yaml_file conf if File.exists? conf
24
+ }
24
25
 
25
- @logger = Logger[self.class.to_s] || Logger['pdo']
26
+ @logger = Logger[self.class.to_s] || Logger['pdo']
26
27
 
27
- end
28
+ end
28
29
 
29
- end # module Logging
30
+ end # module Logging
31
+ end # module PDO
30
32
 
31
33
  # vim: set et ts=2 sts=2 sw=2 si sta :
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ module PDO
6
+ class Opts
7
+ def self.parse(args, opts)
8
+ op = OptionParser.new
9
+ op.set_summary_width 15
10
+
11
+ op.banner = "pdo [opts]"
12
+ op.separator ""
13
+ op.separator "Specific options:"
14
+
15
+ op.on('-c CMD', 'the command to be executed',
16
+ "if CMD equals to '-', then read command from stdin") do |cmd|
17
+ if cmd == '-' then
18
+ opts.cmd = $stdin.read
19
+ else
20
+ opts.cmd = cmd
21
+ end
22
+ end
23
+
24
+ op.on('--count', 'count the number of hosts') do |count|
25
+ opts.count = true
26
+ end
27
+
28
+ op.on('--enum', 'enumerate the hosts') do |enum|
29
+ opts.enum = true
30
+ end
31
+
32
+ op.on('-f <name>',
33
+ 'name of the alternative host definition file') do |fn|
34
+ opts.host_definition_file = fn
35
+ end
36
+
37
+ op.on('-g <name1,name2,...>', Array,
38
+ 'comma separated group or host names') do |groups|
39
+ opts.groups = groups
40
+ end
41
+
42
+ op.on('-l', 'run the command CMD locally') do
43
+ opts.local = true
44
+ end
45
+
46
+ op.on('--step <m,n>', Array,
47
+ 'stepping the hosts, m and n must be integers;',
48
+ 'if n > 0, stepping forward; if n < 0 stepping',
49
+ 'backward') do |step|
50
+ opts.step = [step[0].to_i, step[1].to_i]
51
+ end
52
+
53
+ op.on('--sshopts <key1=val1,key2=val2,...>', Array,
54
+ 'ssh options as described in "man ssh_config"') do |sshopts|
55
+ opts.sshopts = {} unless opts.sshopts
56
+ sshopts.each do |opt|
57
+ key, val = opt.split '='
58
+ opts.sshopts[:"#{key}"] = val if key and val
59
+ end
60
+ end
61
+
62
+ op.on('-t INTEGER', Integer, 'number of threads') do |thread_num|
63
+ if thread_num < 0 then
64
+ raise ArgumentError,
65
+ "thread number must be greater or equal to zero"
66
+ end
67
+ opts.thread_num = thread_num
68
+ end
69
+
70
+ op.on('-x <name1,name2,...>', Array,
71
+ 'comma separated group or host names, which should be',
72
+ 'excluded from the final list') do |e_groups|
73
+ opts.e_groups = e_groups
74
+ end
75
+
76
+ op.on('-y', 'do not confirm, execute immediately') do
77
+ opts.confirm_before_execute = false
78
+ end
79
+
80
+ op.separator ""
81
+ op.separator "Common options:"
82
+
83
+ op.on_tail('-h', '--help', 'this help') do
84
+ puts op.help
85
+ exit 0
86
+ end
87
+
88
+ op.parse!(args)
89
+ return opts
90
+
91
+ end # self.parse()
92
+ end # class Opts
93
+ end # module PDO
94
+
95
+ # vim: set et ts=2 sts=2 sw=2 si sta :
@@ -2,102 +2,104 @@
2
2
 
3
3
  require_relative 'logging'
4
4
 
5
- class SSHCmd
6
- include Logging
5
+ module PDO
6
+ class SSHCmd
7
+ include Logging
7
8
 
8
- def initialize(local, sshopts)
9
+ def initialize(local, sshopts)
9
10
 
10
- @defaults = {
11
- :user => 'root',
12
- :port => '22',
13
- :ssh => '/usr/bin/ssh',
14
- :sshopts => {
15
- :ConnectTimeout => '60',
16
- :StrictHostKeyChecking => 'no',
17
- },
18
- }
19
- @local = local
20
- @sshopts = @defaults[:sshopts]
21
- @sshopts = @defaults[:sshopts].update sshopts if sshopts
22
- logger.debug { @sshopts.inspect }
23
- end
24
-
25
- def form(host, cmd)
26
- if host.match(/^(?:(\w+)@)?(\w+(?:\.\w+)*)(?::(\d+))?$/) then
27
- user, host, port = $1, $2, $3
11
+ @defaults = {
12
+ :user => 'root',
13
+ :port => '22',
14
+ :ssh => '/usr/bin/ssh',
15
+ :sshopts => {
16
+ :ConnectTimeout => '60',
17
+ :StrictHostKeyChecking => 'no',
18
+ },
19
+ }
20
+ @local = local
21
+ @sshopts = @defaults[:sshopts]
22
+ @sshopts = @defaults[:sshopts].update sshopts if sshopts
23
+ logger.debug { @sshopts.inspect }
28
24
  end
25
+
26
+ def form(host, cmd)
27
+ if host.match(/^(?:(\w+)@)?(\w+(?:\.\w+)*)(?::(\d+))?$/) then
28
+ user, host, port = $1, $2, $3
29
+ end
29
30
 
30
- cmd = cmd.dup # without dup, all tasks refer to the same
31
- cmd.strip!
32
- cmd.gsub! '_USER_', user ? user : @defaults[:user]
33
- cmd.gsub! '_HOST_', host
34
- cmd.gsub! '_PORT_', port ? port : @defaults[:port]
35
- # when opts.cmd == '-', the command is read from stdin.
36
- # in this case multiple lines can be entered. here I'm doing some
37
- # simple substitution for "\n".
38
- cmd.gsub! "\n", '; '
31
+ cmd = cmd.dup # without dup, all tasks refer to the same
32
+ cmd.strip!
33
+ cmd.gsub! '_USER_', user ? user : @defaults[:user]
34
+ cmd.gsub! '_HOST_', host
35
+ cmd.gsub! '_PORT_', port ? port : @defaults[:port]
36
+ # when opts.cmd == '-', the command is read from stdin.
37
+ # in this case multiple lines can be entered. here I'm doing some
38
+ # simple substitution for "\n".
39
+ cmd.gsub! "\n", '; '
39
40
 
40
- # escape "`$ characters in cmd, unless they're already escaped.
41
- if RUBY_VERSION.to_f < 1.9 then
42
- # v1.8 dose not support negative look-behind assertion, thus
43
- # doing it in 2 steps.
44
- if cmd.match /["`$]/ then
45
- if not cmd.match /['\\]["`$]/ then
46
- cmd.gsub! /(["`$])/, '\\\\\1'
41
+ # escape "`$ characters in cmd, unless they're already escaped.
42
+ if RUBY_VERSION.to_f < 1.9 then
43
+ # v1.8 dose not support negative look-behind assertion, thus
44
+ # doing it in 2 steps.
45
+ if cmd.match /["`$]/ then
46
+ if not cmd.match /['\\]["`$]/ then
47
+ cmd.gsub! /(["`$])/, '\\\\\1'
48
+ end
47
49
  end
50
+ else
51
+ cmd.gsub! /(?<!['\\])(["`$])/, '\\\\\1'
48
52
  end
49
- else
50
- cmd.gsub! /(?<!['\\])(["`$])/, '\\\\\1'
51
- end
52
53
 
53
- if @local then
54
- return cmd
55
- else
56
- ssh = @defaults[:ssh]
57
- ssh = [ ssh, '-l', "#{user}"].join ' ' if user
58
- ssh = [ ssh, '-p', "#{port}"].join ' ' if port
59
- @sshopts.each do |k, v|
60
- ssh = [ssh, '-o', "#{k}=#{v}"].join ' '
54
+ if @local then
55
+ return cmd
56
+ else
57
+ ssh = @defaults[:ssh]
58
+ ssh = [ ssh, '-l', "#{user}"].join ' ' if user
59
+ ssh = [ ssh, '-p', "#{port}"].join ' ' if port
60
+ @sshopts.each do |k, v|
61
+ ssh = [ssh, '-o', "#{k}=#{v}"].join ' '
62
+ end
63
+ ssh = [ ssh, "#{host}", "\"#{cmd}\""].join ' '
64
+ return ssh
61
65
  end
62
- ssh = [ ssh, "#{host}", "\"#{cmd}\""].join ' '
63
- return ssh
64
66
  end
65
67
  end
66
- end
67
68
 
68
- class Task
69
- include Logging
69
+ class Task
70
+ include Logging
70
71
 
71
- def initialize
72
- @task_q = Queue.new
73
- end
72
+ def initialize
73
+ @task_q = Queue.new
74
+ end
74
75
 
75
- def add(task)
76
- @task_q << task
77
- end
76
+ def add(task)
77
+ @task_q << task
78
+ end
78
79
 
79
- def next
80
- begin
81
- @task_q.deq(non_block=true)
82
- rescue ThreadError
83
- nil
80
+ def next
81
+ begin
82
+ @task_q.deq(non_block=true)
83
+ rescue ThreadError
84
+ nil
85
+ end
84
86
  end
85
- end
86
87
 
87
- def size
88
- @task_q.length
89
- end
88
+ def size
89
+ @task_q.length
90
+ end
90
91
 
91
- def print_all
92
- tmp_q = Queue.new
93
- while not @task_q.empty? do
94
- task = @task_q.deq
95
- printf "%s\n", task
96
- tmp_q << task
92
+ def print_all
93
+ tmp_q = Queue.new
94
+ while not @task_q.empty? do
95
+ task = @task_q.deq
96
+ printf "%s\n", task
97
+ tmp_q << task
98
+ end
99
+ @task_q = tmp_q
97
100
  end
98
- @task_q = tmp_q
99
- end
100
101
 
101
- end
102
+ end # class SSHCmd
103
+ end # module PDO
102
104
 
103
105
  # vim: set et ts=2 sts=2 sw=2 si sta :
@@ -1,3 +1,3 @@
1
- module Pdo
2
- VERSION = "0.0.3"
1
+ module PDO
2
+ VERSION = "0.0.5"
3
3
  end
@@ -6,7 +6,7 @@ require 'pdo/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = 'pdo'
8
8
  gem.license = 'MIT'
9
- gem.version = Pdo::VERSION
9
+ gem.version = PDO::VERSION
10
10
  gem.authors = ['bqbn']
11
11
  gem.email = ['bqbn@openken.com']
12
12
  gem.description = 'pdo is a wrapper for running commands on or '\
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.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-05-20 00:00:00.000000000 Z
12
+ date: 2013-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: log4r
@@ -47,7 +47,7 @@ files:
47
47
  - lib/pdo.rb
48
48
  - lib/pdo/host.rb
49
49
  - lib/pdo/logging.rb
50
- - lib/pdo/pdoopts.rb
50
+ - lib/pdo/opts.rb
51
51
  - lib/pdo/task.rb
52
52
  - lib/pdo/version.rb
53
53
  - log/.gitignore
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'optparse'
4
-
5
- class PdoOpts
6
- def self.parse(args, opts)
7
- op = OptionParser.new
8
- op.set_summary_width 15
9
-
10
- op.banner = "pdo [opts]"
11
- op.separator ""
12
- op.separator "Specific options:"
13
-
14
- op.on('-c CMD', 'the command to be executed',
15
- "if CMD equals to '-', then read command from stdin") do |cmd|
16
- if cmd == '-' then
17
- opts.cmd = $stdin.read
18
- else
19
- opts.cmd = cmd
20
- end
21
- end
22
-
23
- op.on('--count', 'count the number of hosts') do |count|
24
- opts.count = true
25
- end
26
-
27
- op.on('--enum', 'enumerate the hosts') do |enum|
28
- opts.enum = true
29
- end
30
-
31
- op.on('-f <name>',
32
- 'name of the alternative host definition file') do |fn|
33
- opts.host_definition_file = fn
34
- end
35
-
36
- op.on('-g <name1,name2,...>', Array,
37
- 'comma separated group or host names') do |groups|
38
- opts.groups = groups
39
- end
40
-
41
- op.on('-l', 'run the command CMD locally') do
42
- opts.local = true
43
- end
44
-
45
- op.on('--step <m,n>', Array,
46
- 'stepping the hosts, m and n must be integers;',
47
- 'if n > 0, stepping forward; if n < 0 stepping',
48
- 'backward') do |step|
49
- opts.step = [step[0].to_i, step[1].to_i]
50
- end
51
-
52
- op.on('--sshopts <key1=val1,key2=val2,...>', Array,
53
- 'ssh options as described in "man ssh_config"') do |sshopts|
54
- opts.sshopts = {} unless opts.sshopts
55
- sshopts.each do |opt|
56
- key, val = opt.split '='
57
- opts.sshopts[:"#{key}"] = val if key and val
58
- end
59
- end
60
-
61
- op.on('-t INTEGER', Integer, 'number of threads') do |thread_num|
62
- if thread_num < 0 then
63
- raise ArgumentError,
64
- "thread number must be greater or equal to zero"
65
- end
66
- opts.thread_num = thread_num
67
- end
68
-
69
- op.on('-x <name1,name2,...>', Array,
70
- 'comma separated group or host names, which should be',
71
- 'excluded from the final list') do |e_groups|
72
- opts.e_groups = e_groups
73
- end
74
-
75
- op.on('-y', 'do not confirm, execute immediately') do
76
- opts.confirm_before_execute = false
77
- end
78
-
79
- op.separator ""
80
- op.separator "Common options:"
81
-
82
- op.on_tail('-h', '--help', 'this help') do
83
- puts op.help
84
- exit 0
85
- end
86
-
87
- op.parse!(args)
88
- return opts
89
-
90
- end # self.parse()
91
-
92
- end
93
-
94
- # vim: set et ts=2 sts=2 sw=2 si sta :