corl 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +4 -0
  3. data/Gemfile +24 -0
  4. data/Gemfile.lock +123 -0
  5. data/LICENSE.txt +674 -0
  6. data/README.rdoc +27 -0
  7. data/Rakefile +78 -0
  8. data/VERSION +1 -0
  9. data/bin/corl +55 -0
  10. data/corl.gemspec +228 -0
  11. data/lib/corl/action/add.rb +69 -0
  12. data/lib/corl/action/bootstrap.rb +83 -0
  13. data/lib/corl/action/clone.rb +40 -0
  14. data/lib/corl/action/create.rb +55 -0
  15. data/lib/corl/action/exec.rb +41 -0
  16. data/lib/corl/action/extract.rb +49 -0
  17. data/lib/corl/action/image.rb +30 -0
  18. data/lib/corl/action/images.rb +55 -0
  19. data/lib/corl/action/lookup.rb +35 -0
  20. data/lib/corl/action/machines.rb +51 -0
  21. data/lib/corl/action/provision.rb +37 -0
  22. data/lib/corl/action/remove.rb +51 -0
  23. data/lib/corl/action/save.rb +53 -0
  24. data/lib/corl/action/seed.rb +115 -0
  25. data/lib/corl/action/spawn.rb +75 -0
  26. data/lib/corl/action/start.rb +37 -0
  27. data/lib/corl/action/stop.rb +30 -0
  28. data/lib/corl/action/update.rb +37 -0
  29. data/lib/corl/command/shell.rb +164 -0
  30. data/lib/corl/configuration/file.rb +386 -0
  31. data/lib/corl/event/puppet.rb +90 -0
  32. data/lib/corl/event/regex.rb +52 -0
  33. data/lib/corl/extension/puppetloader.rb +24 -0
  34. data/lib/corl/machine/fog.rb +310 -0
  35. data/lib/corl/machine/physical.rb +161 -0
  36. data/lib/corl/network/default.rb +26 -0
  37. data/lib/corl/node/aws.rb +90 -0
  38. data/lib/corl/node/fog.rb +198 -0
  39. data/lib/corl/node/google.rb +115 -0
  40. data/lib/corl/node/local.rb +26 -0
  41. data/lib/corl/node/rackspace.rb +89 -0
  42. data/lib/corl/project/git.rb +465 -0
  43. data/lib/corl/project/github.rb +108 -0
  44. data/lib/corl/provisioner/puppetnode/resource.rb +245 -0
  45. data/lib/corl/provisioner/puppetnode/resource_group.rb +205 -0
  46. data/lib/corl/provisioner/puppetnode.rb +407 -0
  47. data/lib/corl/template/environment.rb +73 -0
  48. data/lib/corl/template/json.rb +16 -0
  49. data/lib/corl/template/wrapper.rb +16 -0
  50. data/lib/corl/template/yaml.rb +16 -0
  51. data/lib/corl/translator/json.rb +27 -0
  52. data/lib/corl/translator/yaml.rb +27 -0
  53. data/lib/corl.rb +173 -0
  54. data/lib/corl_core/codes.rb +107 -0
  55. data/lib/corl_core/config/collection.rb +57 -0
  56. data/lib/corl_core/config/options.rb +70 -0
  57. data/lib/corl_core/config.rb +337 -0
  58. data/lib/corl_core/core.rb +59 -0
  59. data/lib/corl_core/corl.rb +254 -0
  60. data/lib/corl_core/errors.rb +84 -0
  61. data/lib/corl_core/facade.rb +126 -0
  62. data/lib/corl_core/gems.rb +72 -0
  63. data/lib/corl_core/manager.rb +425 -0
  64. data/lib/corl_core/mixin/action/commit.rb +58 -0
  65. data/lib/corl_core/mixin/action/keypair.rb +105 -0
  66. data/lib/corl_core/mixin/action/node.rb +129 -0
  67. data/lib/corl_core/mixin/action/project.rb +53 -0
  68. data/lib/corl_core/mixin/action/push.rb +52 -0
  69. data/lib/corl_core/mixin/config/collection.rb +53 -0
  70. data/lib/corl_core/mixin/config/ops.rb +53 -0
  71. data/lib/corl_core/mixin/config/options.rb +39 -0
  72. data/lib/corl_core/mixin/lookup.rb +196 -0
  73. data/lib/corl_core/mixin/macro/object_interface.rb +361 -0
  74. data/lib/corl_core/mixin/macro/plugin_interface.rb +380 -0
  75. data/lib/corl_core/mixin/settings.rb +46 -0
  76. data/lib/corl_core/mixin/sub_config.rb +148 -0
  77. data/lib/corl_core/mod/hash.rb +29 -0
  78. data/lib/corl_core/mod/hiera_backend.rb +63 -0
  79. data/lib/corl_core/plugin/action.rb +381 -0
  80. data/lib/corl_core/plugin/base.rb +374 -0
  81. data/lib/corl_core/plugin/command.rb +98 -0
  82. data/lib/corl_core/plugin/configuration.rb +177 -0
  83. data/lib/corl_core/plugin/event.rb +53 -0
  84. data/lib/corl_core/plugin/extension.rb +12 -0
  85. data/lib/corl_core/plugin/machine.rb +266 -0
  86. data/lib/corl_core/plugin/network.rb +359 -0
  87. data/lib/corl_core/plugin/node.rb +904 -0
  88. data/lib/corl_core/plugin/project.rb +927 -0
  89. data/lib/corl_core/plugin/provisioner.rb +51 -0
  90. data/lib/corl_core/plugin/template.rb +80 -0
  91. data/lib/corl_core/plugin/translator.rb +38 -0
  92. data/lib/corl_core/util/cli.rb +352 -0
  93. data/lib/corl_core/util/data.rb +404 -0
  94. data/lib/corl_core/util/disk.rb +114 -0
  95. data/lib/corl_core/util/git.rb +47 -0
  96. data/lib/corl_core/util/interface.rb +319 -0
  97. data/lib/corl_core/util/liquid.rb +17 -0
  98. data/lib/corl_core/util/package.rb +93 -0
  99. data/lib/corl_core/util/shell.rb +239 -0
  100. data/lib/corl_core/util/ssh.rb +286 -0
  101. data/lib/facter/corl_config_ready.rb +13 -0
  102. data/lib/facter/corl_exists.rb +15 -0
  103. data/lib/facter/corl_network.rb +17 -0
  104. data/lib/hiera/corl_logger.rb +18 -0
  105. data/lib/puppet/indirector/corl.rb +27 -0
  106. data/lib/puppet/indirector/data_binding/corl.rb +6 -0
  107. data/lib/puppet/parser/functions/config_initialized.rb +26 -0
  108. data/lib/puppet/parser/functions/corl_include.rb +44 -0
  109. data/lib/puppet/parser/functions/corl_resources.rb +58 -0
  110. data/lib/puppet/parser/functions/deep_merge.rb +21 -0
  111. data/lib/puppet/parser/functions/ensure.rb +29 -0
  112. data/lib/puppet/parser/functions/file_exists.rb +19 -0
  113. data/lib/puppet/parser/functions/global_array.rb +35 -0
  114. data/lib/puppet/parser/functions/global_hash.rb +35 -0
  115. data/lib/puppet/parser/functions/global_options.rb +23 -0
  116. data/lib/puppet/parser/functions/global_param.rb +43 -0
  117. data/lib/puppet/parser/functions/interpolate.rb +26 -0
  118. data/lib/puppet/parser/functions/is_false.rb +21 -0
  119. data/lib/puppet/parser/functions/is_true.rb +21 -0
  120. data/lib/puppet/parser/functions/module_array.rb +38 -0
  121. data/lib/puppet/parser/functions/module_hash.rb +38 -0
  122. data/lib/puppet/parser/functions/module_options.rb +23 -0
  123. data/lib/puppet/parser/functions/module_param.rb +48 -0
  124. data/lib/puppet/parser/functions/name.rb +21 -0
  125. data/lib/puppet/parser/functions/render.rb +33 -0
  126. data/lib/puppet/parser/functions/value.rb +21 -0
  127. data/locales/en.yml +232 -0
  128. data/spec/corl_core/interface_spec.rb +489 -0
  129. data/spec/corl_mock_input.rb +29 -0
  130. data/spec/corl_test_kernel.rb +22 -0
  131. data/spec/spec_helper.rb +15 -0
  132. metadata +406 -0
@@ -0,0 +1,319 @@
1
+
2
+ module CORL
3
+ module Util
4
+ class Interface
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Properties
8
+
9
+ @@log_level = nil
10
+ @@loggers = {}
11
+
12
+ def self.log_level
13
+ @@log_level
14
+ end
15
+
16
+ def self.log_level=level
17
+ @@log_level = set_log_level(level)
18
+ end
19
+
20
+ #---
21
+
22
+ def self.loggers
23
+ @@loggers
24
+ end
25
+
26
+ def self.add_log_levels(*levels)
27
+ levels = levels.flatten.collect do |level|
28
+ level.to_s.upcase
29
+ end
30
+ Log4r::Configurator.custom_levels(*levels)
31
+ end
32
+
33
+ def self.add_logger(name, logger)
34
+ logger.outputters = Log4r::StdoutOutputter.new('console')
35
+
36
+ level = log_level.nil? ? 'off' : log_level
37
+ set_log_level(level, logger)
38
+
39
+ @@loggers[name] = logger
40
+ end
41
+
42
+ def self.set_log_level(level, logger = nil)
43
+ level_sym = level.to_s.downcase.to_sym
44
+ level_id = level.to_s.upcase
45
+
46
+ if logger.nil?
47
+ loggers.each do |name, registered_logger|
48
+ @@loggers[name].level = Log4r.const_get(level_id)
49
+ end
50
+ else
51
+ if logger.levels.include?(level_id)
52
+ logger.level = Log4r.const_get(level_id)
53
+ end
54
+ end
55
+ level_sym
56
+ end
57
+
58
+ #---
59
+
60
+ # Initialize log levels
61
+
62
+ add_log_levels :debug, :info, :warn, :error, :hook
63
+
64
+ if ENV['CORL_LOG']
65
+ Interface.log_level = ENV['CORL_LOG']
66
+ end
67
+
68
+ #---
69
+
70
+ @@ui_lock = Mutex.new
71
+
72
+ #---
73
+
74
+ COLORS = {
75
+ :clear => "\e[0m",
76
+ :red => "\e[31m",
77
+ :green => "\e[32m",
78
+ :yellow => "\e[33m"
79
+ }
80
+
81
+ COLOR_MAP = {
82
+ :warn => COLORS[:yellow],
83
+ :error => COLORS[:red],
84
+ :success => COLORS[:green]
85
+ }
86
+
87
+ #-----------------------------------------------------------------------------
88
+ # Constructor
89
+
90
+ def initialize(options = {})
91
+ if options.is_a?(String)
92
+ options = { :resource => options, :logger => options }
93
+ end
94
+ config = Config.ensure(options)
95
+
96
+ @resource = config.get(:resource, '')
97
+
98
+ if config.get(:logger, false)
99
+ self.logger = config[:logger]
100
+ else
101
+ self.logger = Log4r::Logger.new(@resource)
102
+ end
103
+
104
+ @color = config.get(:color, true)
105
+ @printer = config.get(:printer, :puts)
106
+
107
+ @input = config.get(:input, $stdin)
108
+ @output = config.get(:output, $stdout)
109
+ @error = config.get(:error, $stderr)
110
+
111
+ @delegate = config.get(:ui_delegate, nil)
112
+ end
113
+
114
+ #---
115
+
116
+ def inspect
117
+ "#<#{self.class}: #{@resource}>"
118
+ end
119
+
120
+ #-----------------------------------------------------------------------------
121
+ # Accessors / Modifiers
122
+
123
+ attr_reader :logger
124
+ attr_accessor :resource, :color, :input, :output, :error, :delegate
125
+
126
+ #---
127
+
128
+ def logger=logger
129
+ if logger.is_a?(String)
130
+ @logger = Log4r::Logger.new(logger)
131
+ else
132
+ @logger = logger
133
+ end
134
+ self.class.add_logger(@resource, @logger)
135
+ end
136
+
137
+ #-----------------------------------------------------------------------------
138
+ # UI functionality
139
+
140
+ def say(type, message, options = {})
141
+ return @delegate.say(type, message, options) if check_delegate('say')
142
+
143
+ defaults = { :new_line => true, :prefix => true }
144
+ options = defaults.merge(options)
145
+ printer = options[:new_line] ? :puts : :print
146
+ channel = type == :error || options[:channel] == :error ? @error : @output
147
+
148
+ options[:sync] = true unless options.has_key?(:sync)
149
+
150
+ render = lambda do
151
+ safe_puts(format_message(type, message, options),
152
+ :channel => channel, :printer => printer)
153
+ end
154
+
155
+ if options[:sync]
156
+ @@ui_lock.synchronize do
157
+ render.call
158
+ end
159
+ else
160
+ render.call
161
+ end
162
+ end
163
+
164
+ #---
165
+
166
+ def ask(message, options = {})
167
+ return @delegate.ask(message, options) if check_delegate('ask')
168
+
169
+ options[:new_line] = false if ! options.has_key?(:new_line)
170
+ options[:prefix] = false if ! options.has_key?(:prefix)
171
+ options[:echo] = true if ! options.has_key?(:echo)
172
+
173
+ options[:sync] = true unless options.has_key?(:sync)
174
+
175
+ user_input = nil
176
+
177
+ collect = lambda do
178
+ say(:info, message, Config.ensure(options).import({ :sync => false }).export)
179
+
180
+ if options[:echo]
181
+ user_input = @input.gets.chomp
182
+ else
183
+ require 'io/console'
184
+ user_input = @input.noecho(&:gets).chomp
185
+ end
186
+ safe_puts("\n")
187
+ user_input
188
+ end
189
+
190
+ if options[:sync]
191
+ @@ui_lock.synchronize do
192
+ return collect.call
193
+ end
194
+ else
195
+ return collect.call
196
+ end
197
+ end
198
+
199
+ #---
200
+
201
+ def password(type, options = {})
202
+ return @delegate.password(type, options) if check_delegate('password')
203
+
204
+ options[:sync] = true unless options.has_key?(:sync)
205
+
206
+ collect = lambda do
207
+ try_again = true
208
+ password = nil
209
+
210
+ while try_again
211
+ # Get and check a password from the keyboard
212
+ password = ask("Enter #{type} password: ", { :echo => false, :sync => false })
213
+ confirmation_password = ask("Confirm #{type} password: ", { :echo => false, :sync => false })
214
+
215
+ if password != confirmation_password
216
+ choice = ask('Passwords do not match! Try again? (Y|N): ', { :sync => false })
217
+ try_again = choice.upcase == "Y"
218
+ password = nil unless try_again
219
+ else
220
+ try_again = false
221
+ end
222
+ end
223
+ password
224
+ end
225
+
226
+ if options[:sync]
227
+ @@ui_lock.synchronize do
228
+ return collect.call
229
+ end
230
+ else
231
+ return collect.call
232
+ end
233
+ end
234
+
235
+ #-----------------------------------------------------------------------------
236
+
237
+ def info(message, *args)
238
+ @logger.info("info: #{message}")
239
+
240
+ return @delegate.info(message, *args) if check_delegate('info')
241
+ say(:info, message, *args)
242
+ end
243
+
244
+ #---
245
+
246
+ def warn(message, *args)
247
+ @logger.info("warn: #{message}")
248
+
249
+ return @delegate.warn(message, *args) if check_delegate('warn')
250
+ say(:warn, message, *args)
251
+ end
252
+
253
+ #---
254
+
255
+ def error(message, *args)
256
+ @logger.info("error: #{message}")
257
+
258
+ return @delegate.error(message, *args) if check_delegate('error')
259
+ say(:error, message, *args)
260
+ end
261
+
262
+ #---
263
+
264
+ def success(message, *args)
265
+ @logger.info("success: #{message}")
266
+
267
+ return @delegate.success(message, *args) if check_delegate('success')
268
+ say(:success, message, *args)
269
+ end
270
+
271
+ #-----------------------------------------------------------------------------
272
+ # Utilities
273
+
274
+ def format_message(type, message, options = {})
275
+ return @delegate.format_message(type, message, options) if check_delegate('format_message')
276
+ return '' if message.to_s.strip.empty?
277
+
278
+ if @resource && ! @resource.empty? && options[:prefix]
279
+ prefix = "[#{@resource}]"
280
+ end
281
+ message = "#{prefix} #{message}".lstrip.gsub(/\n+$/, '')
282
+
283
+ if @color
284
+ if options.has_key?(:color)
285
+ color = COLORS[options[:color]]
286
+ message = "#{color}#{message}#{COLORS[:clear]}"
287
+ else
288
+ message = "#{COLOR_MAP[type]}#{message}#{COLORS[:clear]}" if COLOR_MAP[type]
289
+ end
290
+ end
291
+ return message
292
+ end
293
+
294
+ #---
295
+
296
+ def safe_puts(message = nil, options = {})
297
+ return @delegate.safe_puts(message, options) if check_delegate('safe_puts')
298
+
299
+ message ||= ""
300
+ options = {
301
+ :channel => @output,
302
+ :printer => @printer,
303
+ }.merge(options)
304
+
305
+ begin
306
+ options[:channel].send(options[:printer], message)
307
+ rescue Errno::EPIPE
308
+ return
309
+ end
310
+ end
311
+
312
+ #-----------------------------------------------------------------------------
313
+
314
+ def check_delegate(method)
315
+ return ( @delegate && @delegate.respond_to?(method.to_s) )
316
+ end
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module CORL
3
+ module Util
4
+ class Liquid
5
+
6
+ def initialize(&code)
7
+ @code = code
8
+ end
9
+
10
+ #---
11
+
12
+ def method_missing(method, *args, &block)
13
+ @code.call(method, args, block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,93 @@
1
+
2
+ module CORL
3
+ module Util
4
+ class Package
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Constructor / Destructor
8
+
9
+ def initialize(options = {})
10
+ if options.is_a?(String)
11
+ @data = Config.new
12
+ decode(options)
13
+ else
14
+ @data = Config.ensure(options)
15
+ end
16
+ end
17
+
18
+ #-----------------------------------------------------------------------------
19
+ # Property accessors / modifiers
20
+
21
+ attr_reader :data
22
+
23
+ #-----------------------------------------------------------------------------
24
+ # Operations
25
+
26
+ def encode
27
+ Base64.encode64(Data.to_json(data.export, false))
28
+ end
29
+
30
+ def decode(encoded_string)
31
+ data.import(Data.symbol_map(Data.parse_json(Base64.decode64(encoded_string))))
32
+ end
33
+
34
+ #---
35
+
36
+ def add_file(file, target_path = nil, perm = 0600)
37
+ target_path = file if target_path.nil?
38
+ file = File.expand_path(file)
39
+
40
+ if File.exists?(file)
41
+ content = Disk.read(file)
42
+ data.set([ :files, target_path ], { :perm => perm, :content => content }) if content
43
+ end
44
+ self
45
+ end
46
+
47
+ #---
48
+
49
+ def add_files(base_path, file_glob, target_path = nil, perm = 0600)
50
+ target_path = base_path if target_path.nil?
51
+ curr_dir = Dir.pwd
52
+
53
+ Dir.chdir(File.expand_path(base_path))
54
+ Dir.glob(file_glob.gsub(/^[\/\\]+/, '')) do |file|
55
+ content = Disk.read(file)
56
+
57
+ if content
58
+ data.set([ :dir, target_path, file ], { :perm => perm, :content => content })
59
+ end
60
+ end
61
+ Dir.chdir(curr_dir)
62
+ self
63
+ end
64
+
65
+ #---
66
+
67
+ def extract(base_path)
68
+ success = true
69
+
70
+ data.get_hash(:files).each do |target_path, info|
71
+ file = File.join(base_path.to_s, target_path.to_s)
72
+ perm = info[:perm]
73
+ content = info[:content]
74
+
75
+ FileUtils.mkdir_p(File.dirname(file))
76
+ success = false unless Disk.write(file, content) && File.chmod(perm, file)
77
+ end
78
+
79
+ data.get_hash(:dir).each do |target_path, files|
80
+ files.each do |file, info|
81
+ file = File.join(base_path.to_s, target_path.to_s, file.to_s)
82
+ perm = info[:perm]
83
+ content = info[:content]
84
+
85
+ FileUtils.mkdir_p(File.dirname(file))
86
+ success = false unless Disk.write(file, content) && File.chmod(perm, file)
87
+ end
88
+ end
89
+ success
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,239 @@
1
+
2
+ module CORL
3
+ module Util
4
+ class Shell < Core
5
+
6
+ include Celluloid
7
+
8
+ #-----------------------------------------------------------------------------
9
+
10
+ @@supervisors = {}
11
+
12
+ #-----------------------------------------------------------------------------
13
+ # Execution result interface
14
+
15
+ class Result
16
+ attr_accessor :status
17
+ attr_reader :command
18
+
19
+ def initialize(command)
20
+ @command = command
21
+ @output = ''
22
+ @errors = ''
23
+ @status = CORL.code.success
24
+ end
25
+
26
+ #---
27
+
28
+ def output
29
+ @output.strip
30
+ end
31
+
32
+ def errors
33
+ @errors.strip
34
+ end
35
+
36
+ #---
37
+
38
+ def append_output(output_str)
39
+ @output << output_str
40
+ end
41
+
42
+ def append_errors(error_str)
43
+ @errors << error_str
44
+ end
45
+ end
46
+
47
+ #-----------------------------------------------------------------------------
48
+ # Shell interface
49
+
50
+ def self.connection(name = :core)
51
+ name = name.to_sym
52
+ init_shell(name) unless @@supervisors.has_key?(name)
53
+ @@supervisors[name]
54
+ end
55
+
56
+ def self.init_shell(name)
57
+ name = name.to_sym
58
+
59
+ Shell.supervise_as name
60
+ @@supervisors[name] = Celluloid::Actor[name]
61
+ end
62
+
63
+ #---
64
+
65
+ execute_block_on_receiver :exec
66
+
67
+ def exec(command, options = {}, &code)
68
+ config = Config.ensure(options)
69
+
70
+ min = config.get(:min, 1).to_i
71
+ tries = config.get(:tries, min).to_i
72
+ tries = ( min > tries ? min : tries )
73
+
74
+ info_prefix = config.get(:info_prefix, '')
75
+ info_suffix = config.get(:info_suffix, '')
76
+ error_prefix = config.get(:error_prefix, '')
77
+ error_suffix = config.get(:error_suffix, '')
78
+
79
+ ui = config.get(:ui, CORL.ui)
80
+
81
+ conditions = CORL.events(config.get(:exit, {}), true)
82
+
83
+ $stdout.sync = true
84
+ $stderr.sync = true
85
+
86
+ system_result = Result.new(command)
87
+
88
+ for i in tries.downto(1)
89
+ logger.info(">> running: #{command}")
90
+
91
+ begin
92
+ t1, output_new, output_orig, output_reader = pipe_exec_stream($stdout, conditions, {
93
+ :prefix => info_prefix,
94
+ :suffix => info_suffix,
95
+ }, 'output') do |data|
96
+ system_result.append_output(data)
97
+ block_given? ? code.call(:output, command, data) : true
98
+ end
99
+
100
+ t2, error_new, error_orig, error_reader = pipe_exec_stream($stderr, conditions, {
101
+ :prefix => error_prefix,
102
+ :suffix => error_suffix,
103
+ }, 'error') do |data|
104
+ system_result.append_errors(data)
105
+ block_given? ? code.call(:error, command, data) : true
106
+ end
107
+
108
+ system_success = system(command)
109
+ system_result.status = $?.exitstatus
110
+
111
+ ensure
112
+ output_success = close_exec_pipe(t1, $stdout, output_orig, output_new, 'output')
113
+ error_success = close_exec_pipe(t2, $stderr, error_orig, error_new, 'error')
114
+ end
115
+
116
+ success = ( system_success && output_success && error_success )
117
+
118
+ min -= 1
119
+ break if success && min <= 0 && conditions.empty?
120
+ end
121
+ system_result
122
+ end
123
+
124
+ #---
125
+
126
+ def pipe_exec_stream(output, conditions, options, label, &code)
127
+ original = output.dup
128
+ read, write = IO.pipe
129
+
130
+ match_prefix = ( options[:match_prefix] ? options[:match_prefix] : 'EXIT' )
131
+
132
+ thread = process_stream(read, original, options, label) do |data|
133
+ check_conditions(data, conditions, match_prefix) do
134
+ block_given? ? code.call(data) : true
135
+ end
136
+ end
137
+
138
+ thread.abort_on_exception = false
139
+
140
+ output.reopen(write)
141
+ return thread, write, original, read
142
+ end
143
+ protected :pipe_exec_stream
144
+
145
+ #---
146
+
147
+ def close_exec_pipe(thread, output, original, write, label)
148
+ output.reopen(original)
149
+
150
+ write.close
151
+ success = thread.value
152
+
153
+ original.close
154
+ return success
155
+ end
156
+ protected :close_exec_pipe
157
+
158
+ #---
159
+
160
+ def check_conditions(data, conditions, match_prefix = '', &code)
161
+ prefix = ''
162
+
163
+ unless ! conditions || conditions.empty?
164
+ conditions.each do |key, event|
165
+ if event.check(data)
166
+ prefix = match_prefix
167
+ conditions.delete(key)
168
+ end
169
+ end
170
+ end
171
+
172
+ result = true
173
+ if block_given?
174
+ result = code.call
175
+
176
+ unless prefix.empty?
177
+ case result
178
+ when Hash
179
+ result[:prefix] = prefix
180
+ else
181
+ result = { :success => result, :prefix => prefix }
182
+ end
183
+ end
184
+ end
185
+ return result
186
+ end
187
+ protected :check_conditions
188
+
189
+ #---
190
+
191
+ def process_stream(input, output, options, label, &code)
192
+ return Thread.new do
193
+ success = true
194
+ default_prefix = ( options[:prefix] ? options[:prefix] : '' )
195
+ default_suffix = ( options[:suffix] ? options[:suffix] : '' )
196
+
197
+ begin
198
+ while ( data = input.readpartial(1024) )
199
+ message = data.strip
200
+ newline = ( data[-1,1].match(/\n/) ? true : false )
201
+
202
+ unless message.empty?
203
+ lines = message.split(/\n/)
204
+ lines.each_with_index do |line, index|
205
+ prefix = default_prefix
206
+ suffix = default_suffix
207
+
208
+ unless line.empty?
209
+ if block_given?
210
+ result = code.call(line)
211
+
212
+ if result && result.is_a?(Hash)
213
+ prefix = result[:prefix]
214
+ suffix = result[:suffix]
215
+ result = result[:success]
216
+ end
217
+ success = result if success
218
+ end
219
+
220
+ prefix = ( prefix && ! prefix.empty? ? "#{prefix}: " : '' )
221
+ suffix = ( suffix && ! suffix.empty? ? suffix : '' )
222
+ eol = ( index < lines.length - 1 || newline ? "\n" : ' ' )
223
+
224
+ output.write(prefix.lstrip + line + suffix.rstrip + eol)
225
+ end
226
+ end
227
+ end
228
+ end
229
+ rescue EOFError
230
+ end
231
+
232
+ input.close()
233
+ success
234
+ end
235
+ end
236
+ protected :process_stream
237
+ end
238
+ end
239
+ end