scout-gear 8.0.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +48 -9
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +16 -4
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/rbbt-scout.rb +2 -1
  9. data/lib/scout/cmd.rb +32 -29
  10. data/lib/scout/concurrent_stream.rb +36 -19
  11. data/lib/scout/exceptions.rb +10 -0
  12. data/lib/scout/indiferent_hash.rb +17 -0
  13. data/lib/scout/log/color.rb +11 -11
  14. data/lib/scout/log/progress/report.rb +8 -5
  15. data/lib/scout/log/progress/util.rb +3 -0
  16. data/lib/scout/log/trap.rb +3 -3
  17. data/lib/scout/log.rb +67 -36
  18. data/lib/scout/meta_extension.rb +34 -0
  19. data/lib/scout/misc/digest.rb +11 -2
  20. data/lib/scout/misc/filesystem.rb +2 -3
  21. data/lib/scout/misc/format.rb +12 -7
  22. data/lib/scout/misc/monitor.rb +11 -0
  23. data/lib/scout/misc/system.rb +48 -0
  24. data/lib/scout/named_array.rb +8 -0
  25. data/lib/scout/offsite/ssh.rb +174 -0
  26. data/lib/scout/offsite/step.rb +100 -0
  27. data/lib/scout/offsite/sync.rb +55 -0
  28. data/lib/scout/offsite.rb +3 -0
  29. data/lib/scout/open/lock.rb +5 -24
  30. data/lib/scout/open/remote.rb +12 -1
  31. data/lib/scout/open/stream.rb +109 -122
  32. data/lib/scout/open/util.rb +9 -0
  33. data/lib/scout/open.rb +12 -11
  34. data/lib/scout/path/find.rb +15 -10
  35. data/lib/scout/path/util.rb +5 -0
  36. data/lib/scout/path.rb +1 -1
  37. data/lib/scout/persist/serialize.rb +4 -4
  38. data/lib/scout/persist.rb +1 -1
  39. data/lib/scout/resource/open.rb +8 -0
  40. data/lib/scout/resource/path.rb +16 -9
  41. data/lib/scout/resource/software.rb +4 -2
  42. data/lib/scout/resource/util.rb +10 -4
  43. data/lib/scout/resource.rb +2 -0
  44. data/lib/scout/tsv/dumper.rb +5 -1
  45. data/lib/scout/tsv/index.rb +28 -86
  46. data/lib/scout/tsv/open.rb +35 -14
  47. data/lib/scout/tsv/parser.rb +22 -5
  48. data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
  49. data/lib/scout/tsv/stream.rb +204 -0
  50. data/lib/scout/tsv/transformer.rb +11 -0
  51. data/lib/scout/tsv.rb +9 -2
  52. data/lib/scout/work_queue/worker.rb +2 -2
  53. data/lib/scout/work_queue.rb +37 -12
  54. data/lib/scout/workflow/definition.rb +2 -1
  55. data/lib/scout/workflow/deployment/orchestrator.rb +254 -0
  56. data/lib/scout/workflow/deployment.rb +1 -0
  57. data/lib/scout/workflow/step/dependencies.rb +46 -14
  58. data/lib/scout/workflow/step/file.rb +5 -0
  59. data/lib/scout/workflow/step/info.rb +13 -3
  60. data/lib/scout/workflow/step/inputs.rb +5 -0
  61. data/lib/scout/workflow/step/load.rb +1 -1
  62. data/lib/scout/workflow/step/provenance.rb +1 -0
  63. data/lib/scout/workflow/step/status.rb +27 -9
  64. data/lib/scout/workflow/step.rb +82 -30
  65. data/lib/scout/workflow/task/dependencies.rb +116 -0
  66. data/lib/scout/workflow/task/inputs.rb +36 -17
  67. data/lib/scout/workflow/task.rb +12 -109
  68. data/lib/scout/workflow/usage.rb +57 -41
  69. data/lib/scout/workflow.rb +19 -13
  70. data/lib/scout-gear.rb +2 -0
  71. data/lib/scout.rb +6 -0
  72. data/scout-gear.gemspec +38 -7
  73. data/scout_commands/doc +37 -0
  74. data/scout_commands/find +1 -0
  75. data/scout_commands/offsite +30 -0
  76. data/scout_commands/resource/produce +66 -0
  77. data/scout_commands/template +52 -0
  78. data/scout_commands/update +29 -0
  79. data/scout_commands/workflow/info +15 -3
  80. data/scout_commands/workflow/install +105 -0
  81. data/scout_commands/workflow/task +46 -6
  82. data/share/software/install_helpers +2 -2
  83. data/share/templates/command +25 -0
  84. data/share/templates/workflow.rb +14 -0
  85. data/test/scout/offsite/test_ssh.rb +15 -0
  86. data/test/scout/offsite/test_step.rb +32 -0
  87. data/test/scout/offsite/test_sync.rb +36 -0
  88. data/test/scout/offsite/test_task.rb +0 -0
  89. data/test/scout/resource/test_path.rb +6 -0
  90. data/test/scout/test_named_array.rb +6 -0
  91. data/test/scout/test_persist.rb +3 -2
  92. data/test/scout/test_tsv.rb +17 -0
  93. data/test/scout/test_work_queue.rb +64 -42
  94. data/test/scout/tsv/persist/test_adapter.rb +1 -1
  95. data/test/scout/tsv/test_index.rb +14 -0
  96. data/test/scout/tsv/test_parser.rb +35 -0
  97. data/test/scout/tsv/test_stream.rb +200 -0
  98. data/test/scout/tsv/test_transformer.rb +12 -0
  99. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  100. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  101. data/test/scout/workflow/step/test_info.rb +17 -0
  102. data/test/scout/workflow/step/test_status.rb +0 -1
  103. data/test/scout/workflow/task/test_dependencies.rb +357 -0
  104. data/test/scout/workflow/task/test_inputs.rb +52 -0
  105. data/test/scout/workflow/test_definition.rb +18 -0
  106. data/test/scout/workflow/test_documentation.rb +24 -0
  107. data/test/scout/workflow/test_step.rb +109 -0
  108. data/test/scout/workflow/test_task.rb +0 -287
  109. data/test/test_scout.rb +9 -0
  110. metadata +89 -5
  111. data/scout_commands/workflow/task_old +0 -706
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48f6bb392f3391e2816e701887bfd98617b1a68bc533c8b6de3307f25c84906d
4
- data.tar.gz: 476858f63deaa7fa9fc531c7872bdaefa1d6b3ed32cdacbe41f53d1d170fcc87
3
+ metadata.gz: 98b3f84350f2f451b717f004bfc97cd7767f7e0fed58e1a2d0cd023bc700185f
4
+ data.tar.gz: '00847ad4d92b1cab22305ea867dc12c870b22e192e79536917f82aa90cc82989'
5
5
  SHA512:
6
- metadata.gz: c61501c8cc79b57b64cb8613efc8b00fb84908bf0d55b008c6a6a39b99ea6bffa53630a8e134c07a49cb7bc4145ec181df057b6ba1eebfd2d722b2aa2d2e63d0
7
- data.tar.gz: 100356a04cd34eba627239668747023ee5be4455ebbee715df39dbe04e9c8dfcac7007ce310e4622cf0c7e16ee9159e6fc2d4eefcaa486c24519c7f99185facf
6
+ metadata.gz: 4af5e13873fa13dea33161e9200aa725bb4329899e9242ae6504ffae2ab82e7eb01b82a53edc2a4331ede06d0f12bb07f86f579cb29ecbf0d36e791bf6d53f3e
7
+ data.tar.gz: fc773eb933e5c851aa1d642e872df02d282fbcb29ee1b8e1bf150ffebf9bd4ce8c3670d43a284ff2c8197477a8cf6f71dfcd49b265ad938c723292ec57579998
data/.vimproject CHANGED
@@ -8,11 +8,18 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
8
8
  alias
9
9
  find
10
10
  glob
11
+ doc
12
+ update
13
+ template
14
+ offsite
11
15
  workflow=workflow{
12
16
  task
13
17
  list
14
18
  info
15
- task_old
19
+ install
20
+ }
21
+ resource=resource{
22
+ produce
16
23
  }
17
24
  }
18
25
  lib=lib {
@@ -99,24 +106,30 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
99
106
  workflow.rb
100
107
  workflow=workflow{
101
108
  definition.rb
109
+ documentation.rb
110
+ usage.rb
111
+ util.rb
102
112
  step.rb
103
113
  step=step{
104
- info.rb
105
- status.rb
106
- load.rb
107
- file.rb
108
114
  config.rb
109
115
  dependencies.rb
110
- provenance.rb
116
+ file.rb
117
+ info.rb
118
+ load.rb
111
119
  progress.rb
120
+ provenance.rb
121
+ status.rb
122
+ inputs.rb
112
123
  }
113
124
  task.rb
114
125
  task=task{
126
+ dependencies.rb
115
127
  inputs.rb
116
128
  }
117
- documentation.rb
118
- usage.rb
119
- util.rb
129
+ deployment.rb
130
+ deployment=deployment{
131
+ orchestrator.rb
132
+ }
120
133
  }
121
134
  semaphore.rb
122
135
  work_queue.rb
@@ -141,6 +154,8 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
141
154
  persist=persist{
142
155
  adapter.rb
143
156
  serialize.rb
157
+ sdbm.rb
158
+ tkrzw.rb
144
159
  tokyocabinet.rb
145
160
  fix_width_table.rb
146
161
  }
@@ -149,8 +164,18 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
149
164
  attach.rb
150
165
  change_id.rb
151
166
  path.rb
167
+ stream.rb
152
168
  open.rb
153
169
  }
170
+ offsite.rb
171
+ offsite=offsite{
172
+ ssh.rb
173
+ sync.rb
174
+ step.rb
175
+ }
176
+ hpc=hpc{
177
+ slurm.rb
178
+ }
154
179
  }
155
180
  }
156
181
  test=test {
@@ -181,7 +206,18 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
181
206
  test_task.rb
182
207
  test_usage.rb
183
208
  test_util.rb
209
+ step=step{
210
+ test_dependencies.rb
211
+ test_info.rb
212
+ test_load.rb
213
+ test_provenance.rb
214
+ test_status.rb
215
+ }
216
+ task=task{
217
+ test_dependencies.rb
218
+ test_inputs.rb
184
219
  }
220
+ }
185
221
  indiferent_hash=indiferent_hash{
186
222
  test_case_insensitive.rb
187
223
  test_options.rb
@@ -192,6 +228,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
192
228
  software=software{
193
229
  install_helpers
194
230
  }
231
+ templates=templates{
232
+ workflow.rb
233
+ }
195
234
  }
196
235
 
197
236
 
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ Juwelier::Tasks.new do |gem|
12
12
  gem.homepage = "http://github.com/mikisvaz/scout-gear"
13
13
  gem.license = "MIT"
14
14
  gem.summary = %Q{basic gear for scouts}
15
- gem.description = %Q{Temporary files, logs, etc.}
15
+ gem.description = %Q{Temporary files, logs, path, resources, persistence, workflows, TSV, etc.}
16
16
  gem.email = "mikisvaz@gmail.com"
17
17
  gem.authors = ["Miguel Vazquez"]
18
18
 
@@ -21,6 +21,11 @@ Juwelier::Tasks.new do |gem|
21
21
  # gem.add_runtime_dependency 'jabber4r', '> 0.1'
22
22
  # gem.add_development_dependency 'rspec', '> 1.2.3'
23
23
  gem.add_runtime_dependency 'term-ansicolor'
24
+ gem.add_runtime_dependency 'net-ssh'
25
+ gem.add_runtime_dependency 'matrix'
26
+ gem.add_runtime_dependency 'sys-proctable'
27
+ gem.add_runtime_dependency 'RubyInline'
28
+ #gem.add_runtime_dependency 'tokyocabinet'
24
29
 
25
30
  gem.add_development_dependency "rdoc", "~> 3.12"
26
31
  gem.add_development_dependency "bundler", "~> 1.0"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 8.0.0
1
+ 9.0.0
data/bin/scout CHANGED
@@ -35,6 +35,12 @@ if dev_dir.nil?
35
35
  ARGV.delete _s if _s
36
36
  end
37
37
 
38
+ if dev_dir.nil? && ENV["SCOUT_DEV"]
39
+ dev_dir = ENV["SCOUT_DEV"]
40
+ ARGV.delete "--dev"
41
+ ARGV.delete dev_dir
42
+ end
43
+
38
44
  if dev_dir
39
45
  ['scout-*/lib'].each do |pattern|
40
46
  Dir.glob(File.join(File.expand_path(dev_dir), pattern)).each do |f|
@@ -48,6 +54,7 @@ if dev_dir
48
54
  end
49
55
  end
50
56
 
57
+ require 'scout'
51
58
 
52
59
  require 'scout/simple_opt'
53
60
 
@@ -62,6 +69,7 @@ $ #{$0} <command> <subcommand> ... -a --arg1 --arg2='value' --arg3 'another-valu
62
69
  --nocolor #{Log.color :yellow, "Disable colored output"}
63
70
  --nobar #{Log.color :yellow, "Disable progress report"}
64
71
  --locate_file #{Log.color :yellow, "Report the location of the script instead of executing it"}
72
+ -ck--config_keys* #{Log.color :yellow, "Override some config keys"}
65
73
  EOF
66
74
 
67
75
  Log.nocolor = true if options[:nocolor]
@@ -84,6 +92,14 @@ else
84
92
  end
85
93
  end
86
94
 
95
+ if config_keys = options.delete(:config_keys)
96
+ config_keys.split(",").each do |config|
97
+ config = config.strip
98
+ Scout::Config.process_config config
99
+ end
100
+ end
101
+
102
+
87
103
  $scout_command_dir = Scout.bin.scout
88
104
  $scout_command_dir.path_maps[:scout_commands] = File.join(File.dirname(__dir__), "{PATH/bin\\/scout/scout_commands}")
89
105
 
@@ -217,7 +233,6 @@ begin
217
233
 
218
234
  scout_usage($previous_commands)
219
235
  exit_status = 0
220
- exit exit_status
221
236
 
222
237
  rescue ParameterException
223
238
  puts
@@ -225,14 +240,11 @@ rescue ParameterException
225
240
  print_error($!.message, $!.backtrace)
226
241
  puts
227
242
  exit_status = -1
228
- exit exit_status
229
243
  rescue SystemExit,CmdStop
230
244
  exit_status = $!.status
231
- exit exit_status
232
245
  rescue Exception
233
246
  Log.exception $!
234
247
  exit_status = -1
235
- exit exit_status
236
248
  ensure
237
249
  if options[:profile]
238
250
  result = RubyProf.stop
@@ -0,0 +1,35 @@
1
+ Path
2
+ ===
3
+
4
+ ```ruby
5
+ :current => '{PWD}/{TOPLEVEL}/{SUBPATH}',
6
+ :user => '{HOME}/.{PKGDIR}/{TOPLEVEL}/{SUBPATH}',
7
+ :global => '/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
8
+ :usr => '/usr/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
9
+ :local => '/usr/local/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
10
+ :fast => '/fast/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
11
+ :cache => '/cache/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
12
+ :bulk => '/bulk/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
13
+ :lib => '{LIBDIR}/{TOPLEVEL}/{SUBPATH}',
14
+ :scout_gear => File.join(Path.caller_lib_dir(__FILE__), "{TOPLEVEL}/{SUBPATH}"),
15
+ :tmp => '/tmp/{PKGDIR}/{TOPLEVEL}/{SUBPATH}',
16
+ :default => :user
17
+
18
+ @@basic_map_order ||= %w(current workflow user local global lib fast cache bulk)
19
+
20
+ ```
21
+
22
+
23
+
24
+ # tags
25
+ {PKGDIR}
26
+ {LIBDIR}
27
+ {RESOURCE}
28
+ {HOME}
29
+ {PWD}
30
+ {TOPLEVEL}
31
+ {SUBPATH}
32
+ {BASENAME}
33
+ {PATH}
34
+ {MAPNAME}
35
+ {REMOVE}
@@ -0,0 +1,13 @@
1
+ Task
2
+ ====
3
+
4
+ ```ruby
5
+ wf = Workflow.annonymous_workflow "TaskInputs" do
6
+ input :input1, :integer
7
+ task :step1 => :integer do |i| i end
8
+
9
+ dep :step1
10
+ input :input2, :integer, "Integer", 3
11
+ task :step2 => :integer do |i| i * step(:step1).load end
12
+ end
13
+ ```
data/lib/rbbt-scout.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift File.join(__dir__, '../modules/rbbt-util/lib')
2
2
  module Rbbt
3
3
  extend Resource
4
- self.pkgdir = 'rbbt'
5
4
  self.path_maps = Path.path_maps.merge(:rbbt_lib => File.expand_path(File.join(__dir__, '../modules/rbbt-util/', '{TOPLEVEL}','{SUBPATH}')))
6
5
  end
6
+
7
+ Resource.set_software_env Rbbt.software
data/lib/scout/cmd.rb CHANGED
@@ -14,23 +14,28 @@ module CMD
14
14
 
15
15
  def self.conda(tool, env = nil, channel = 'bioconda')
16
16
  if env
17
- CMD.cmd("bash -l -c '(conda activate #{env} && conda install #{tool} -c #{channel})'")
17
+ CMD.cmd("bash -l -c '(conda activate #{env} && conda install #{tool} -c #{channel})'")
18
18
  else
19
- CMD.cmd("bash -l -c 'conda install #{tool} -c #{channel}'")
19
+ CMD.cmd("bash -l -c 'conda install #{tool} -c #{channel}'")
20
20
  end
21
21
  end
22
22
 
23
+
23
24
  def self.get_tool(tool)
24
25
  return tool.to_s unless TOOLS[tool]
25
26
 
26
27
  @@init_cmd_tool ||= IndiferentHash.setup({})
28
+
29
+ claim, test, block, cmd = TOOLS[tool]
30
+ cmd = tool.to_s if cmd.nil?
31
+
27
32
  if !@@init_cmd_tool[tool]
28
- claim, test, block, cmd = TOOLS[tool]
33
+
29
34
  begin
30
35
  if test
31
36
  CMD.cmd(test + " ")
32
37
  else
33
- CMD.cmd("#{tool} --help")
38
+ CMD.cmd("#{cmd} --help")
34
39
  end
35
40
  rescue
36
41
  if claim
@@ -43,7 +48,7 @@ module CMD
43
48
  version = nil
44
49
  ["--version", "-version", "--help", ""].each do |f|
45
50
  begin
46
- version_txt += CMD.cmd("#{tool} #{f} 2>&1", :nofail => true).read
51
+ version_txt += CMD.cmd("#{cmd} #{f} 2>&1", :nofail => true).read
47
52
  version = CMD.scan_version_text(version_txt, tool)
48
53
  break if version
49
54
  rescue
@@ -56,11 +61,11 @@ module CMD
56
61
  return cmd if cmd
57
62
  end
58
63
 
59
- tool.to_s
64
+ cmd
60
65
  end
61
-
62
66
  def self.scan_version_text(text, cmd = nil)
63
67
  cmd = "NOCMDGIVE" if cmd.nil? || cmd.empty?
68
+ text = Misc.fixutf8 text
64
69
  text.split("\n").each do |line|
65
70
  next unless line =~ /\W#{cmd}\W/i
66
71
  m = line.match(/(v(?:\d+\.)*\d+(?:-[a-z_]+)?)/i)
@@ -98,8 +103,8 @@ module CMD
98
103
 
99
104
  option = "--" << option.to_s if add_dashes and option.to_s[0] != '-'
100
105
 
101
- case
102
- when value.nil? || FalseClass === value
106
+ case
107
+ when value.nil? || FalseClass === value
103
108
  next
104
109
  when TrueClass === value
105
110
  string << "#{option} "
@@ -136,8 +141,8 @@ module CMD
136
141
  dont_close_in = options.delete(:dont_close_in)
137
142
 
138
143
  log = true if log.nil?
139
-
140
- if cmd.nil? && ! Symbol === tool
144
+
145
+ if cmd.nil? && ! Symbol === tool
141
146
  cmd = tool
142
147
  else
143
148
  tool = get_tool(tool)
@@ -163,7 +168,7 @@ module CMD
163
168
 
164
169
  cmd_options = process_cmd_options options
165
170
  if cmd =~ /'\{opt\}'/
166
- cmd.sub!('\'{opt}\'', cmd_options)
171
+ cmd.sub!('\'{opt}\'', cmd_options)
167
172
  else
168
173
  cmd << " " << cmd_options
169
174
  end
@@ -179,29 +184,28 @@ module CMD
179
184
  end
180
185
  pid = wait_thr.pid
181
186
 
182
- Log.debug{"CMD: [#{pid}] #{cmd}" if log}
187
+ Log.debug{"CMD: [#{pid}] #{cmd}".strip if log}
183
188
 
184
189
  if in_content.respond_to?(:read)
185
190
  in_thread = Thread.new(Thread.current) do |parent|
186
- Thread.current.report_on_exception = false if no_fail
187
191
  begin
188
- begin
189
- while c = in_content.readpartial(Open::BLOCK_SIZE)
190
- sin << c
191
- end
192
- rescue EOFError
192
+ Thread.current.report_on_exception = false if no_fail
193
+ Thread.current["name"] = "CMD in"
194
+ while c = in_content.read(Open::BLOCK_SIZE)
195
+ sin << c
193
196
  end
194
197
  sin.close unless sin.closed?
195
198
 
196
199
  unless dont_close_in
197
- in_content.close unless in_content.closed?
198
- in_content.join if in_content.respond_to? :join
200
+ in_content.close unless in_content.closed?
201
+ in_content.join if in_content.respond_to? :join
199
202
  end
200
203
  rescue
201
204
  Log.error "Error in CMD [#{pid}] #{cmd}: #{$!.message}" unless no_fail
202
205
  raise $!
203
206
  end
204
207
  end
208
+ Thread.pass until in_thread["name"]
205
209
  else
206
210
  in_thread = nil
207
211
  sin.close
@@ -211,7 +215,7 @@ module CMD
211
215
 
212
216
  if pipe
213
217
 
214
- ConcurrentStream.setup sout, :pids => pids, :autojoin => autojoin, :no_fail => no_fail
218
+ ConcurrentStream.setup sout, :pids => pids, :autojoin => autojoin, :no_fail => no_fail
215
219
 
216
220
  sout.callback = post if post
217
221
 
@@ -224,7 +228,7 @@ module CMD
224
228
  sout.log = line
225
229
  sout.std_err << line if save_stderr
226
230
  Log.log "STDERR [#{pid}]: " + line, stderr if log
227
- end
231
+ end
228
232
  serr.close
229
233
  rescue
230
234
  Log.exception $!
@@ -244,8 +248,8 @@ module CMD
244
248
  err = ""
245
249
  err_thread = Thread.new do
246
250
  while not serr.eof?
247
- line = serr.gets
248
- bar.process(line)
251
+ line = serr.gets
252
+ bar.process(line)
249
253
  err << line if Integer === stderr and log
250
254
  end
251
255
  serr.close
@@ -254,18 +258,17 @@ module CMD
254
258
  err = ""
255
259
  err_thread = Thread.new do
256
260
  while not serr.eof?
257
- err << serr.gets
261
+ err << serr.gets
258
262
  end
259
263
  serr.close
260
264
  end
261
265
  else
262
266
  Open.consume_stream(serr, true)
263
- #serr.close
264
267
  err_thread = nil
265
268
  err = ""
266
269
  end
267
270
 
268
- ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread].compact, :autojoin => autojoin, :no_fail => no_fail
271
+ ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread].compact, :autojoin => autojoin, :no_fail => no_fail
269
272
 
270
273
  begin
271
274
  out = StringIO.new sout.read
@@ -324,7 +327,7 @@ module CMD
324
327
  starting = true
325
328
  line = "" if bar
326
329
  end
327
- end
330
+ end
328
331
  begin
329
332
  io.join
330
333
  bar.remove if bar
@@ -12,13 +12,12 @@ module ConcurrentStream
12
12
  attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined, :aborted, :autojoin, :lock, :no_fail, :pair, :thread, :stream_exception, :log, :std_err, :next
13
13
 
14
14
  def self.setup(stream, options = {}, &block)
15
-
16
15
  threads, pids, callback, abort_callback, filename, autojoin, lock, no_fail, pair, next_stream = IndiferentHash.process_options options, :threads, :pids, :callback, :abort_callback, :filename, :autojoin, :lock, :no_fail, :pair, :next
17
16
  stream.extend ConcurrentStream unless ConcurrentStream === stream
18
17
 
19
18
  stream.threads ||= []
20
19
  stream.pids ||= []
21
- stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
20
+ stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
22
21
  stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
23
22
  stream.autojoin = autojoin unless autojoin.nil?
24
23
  stream.no_fail = no_fail unless no_fail.nil?
@@ -36,7 +35,7 @@ module ConcurrentStream
36
35
  callback.call
37
36
  end
38
37
  else
39
- stream.callback = callback
38
+ stream.callback = callback
40
39
  end
41
40
  end
42
41
 
@@ -48,7 +47,7 @@ module ConcurrentStream
48
47
  abort_callback.call
49
48
  end
50
49
  else
51
- stream.abort_callback = abort_callback
50
+ stream.abort_callback = abort_callback
52
51
  end
53
52
  end
54
53
 
@@ -80,7 +79,7 @@ module ConcurrentStream
80
79
 
81
80
  def join_threads
82
81
  if @threads
83
- @threads.each do |t|
82
+ @threads.each do |t|
84
83
  next if t == Thread.current
85
84
  begin
86
85
  t.join
@@ -101,7 +100,7 @@ module ConcurrentStream
101
100
  Log.low "Not failing on exception joining thread in ConcurrenStream - #{filename} - #{$!.message}"
102
101
  else
103
102
  Log.low "Exception joining thread in ConcurrenStream #{Log.fingerprint self} - #{Log.fingerprint t} - #{$!.message}"
104
- stream_raise_exception $!
103
+ stream_raise_exception $!
105
104
  end
106
105
  end
107
106
  end
@@ -111,13 +110,13 @@ module ConcurrentStream
111
110
 
112
111
  def join_pids
113
112
  if @pids and @pids.any?
114
- @pids.each do |pid|
113
+ @pids.each do |pid|
115
114
  begin
116
115
  Process.waitpid(pid, Process::WUNTRACED)
117
116
  stream_raise_exception ConcurrentStreamProcessFailed.new(pid, "Error in waitpid", self) unless $?.success? or no_fail
118
117
  rescue Errno::ECHILD
119
118
  end
120
- end
119
+ end
121
120
  @pids = []
122
121
  end
123
122
  end
@@ -143,7 +142,7 @@ module ConcurrentStream
143
142
  @joined = true
144
143
  begin
145
144
  lock.unlock if lock && lock.locked?
146
- rescue
145
+ rescue
147
146
  Log.exception $!
148
147
  end
149
148
  raise stream_exception if stream_exception
@@ -158,7 +157,7 @@ module ConcurrentStream
158
157
 
159
158
  threads = @threads.dup
160
159
  @threads.clear
161
- threads.each do |t|
160
+ threads.each do |t|
162
161
  next if t == Thread.current
163
162
  next if t["aborted"]
164
163
  t["aborted"] = true
@@ -166,14 +165,14 @@ module ConcurrentStream
166
165
  Log.debug "Aborting thread #{Log.fingerprint(t)} with exception: #{exception}"
167
166
  t.raise(exception)
168
167
  t.join
169
- end
168
+ end
170
169
  end
171
170
 
172
171
  def abort_pids
173
172
  @pids.each do |pid|
174
- begin
173
+ begin
175
174
  Log.low "Killing PID #{pid} in ConcurrentStream #{filename}"
176
- Process.kill :INT, pid
175
+ Process.kill :INT, pid
177
176
  rescue Errno::ESRCH
178
177
  end
179
178
  end if @pids
@@ -189,7 +188,7 @@ module ConcurrentStream
189
188
  Log.medium "Aborting stream #{Log.fingerprint self} [#{@aborted}]"
190
189
  end
191
190
  AbortedStream.setup(self, exception)
192
- @aborted = true
191
+ @aborted = true
193
192
  begin
194
193
  @abort_callback.call exception if @abort_callback
195
194
 
@@ -207,7 +206,7 @@ module ConcurrentStream
207
206
  close unless closed?
208
207
 
209
208
  if lock and lock.locked?
210
- lock.unlock
209
+ lock.unlock
211
210
  end
212
211
  end
213
212
  end
@@ -218,7 +217,7 @@ module ConcurrentStream
218
217
  super(*args)
219
218
  rescue
220
219
  self.abort
221
- self.join
220
+ self.join
222
221
  stream_raise_exception $!
223
222
  ensure
224
223
  self.join if ! @stream_exception && (self.closed? || self.eof?)
@@ -249,19 +248,37 @@ module ConcurrentStream
249
248
 
250
249
  def add_callback(&block)
251
250
  old_callback = callback
252
- @callback = Proc.new do
251
+ @callback = Proc.new do
253
252
  old_callback.call if old_callback
254
253
  block.call
255
254
  end
256
255
  end
257
256
 
258
257
  def stream_raise_exception(exception)
258
+ self.stream_exception = exception
259
259
  threads.each do |thread|
260
260
  thread.raise exception
261
261
  end
262
- self.stream_exception = exception
263
-
264
262
  self.abort
265
263
  end
266
264
 
265
+ def self.process_stream(stream, close: true, join: true, message: "process_stream", **kwargs, &block)
266
+ ConcurrentStream.setup(stream, **kwargs)
267
+ begin
268
+ begin
269
+ yield
270
+ ensure
271
+ stream.close if close && stream.respond_to?(:close) && ! (stream.respond_to?(:closed?) && stream.closed?)
272
+ stream.join if join && stream.respond_to?(:join) && ! stream.joined?
273
+ end
274
+ rescue Aborted
275
+ Log.low "Aborted #{message}: #{$!.message}"
276
+ stream.abort($!) if stream.respond_to?(:abort) && ! stream.aborted?
277
+ raise $!
278
+ rescue Exception
279
+ Log.low "Exception #{message}: #{$!.message}"
280
+ stream.abort($!) if stream.respond_to?(:abort) && ! stream.aborted?
281
+ raise $!
282
+ end
283
+ end
267
284
  end
@@ -139,3 +139,13 @@ class SemaphoreInterrupted < TryAgain; end
139
139
  #
140
140
  #
141
141
  class ResourceNotFound < ScoutException; end
142
+
143
+ class SSHProcessFailed < StandardError
144
+ attr_accessor :host, :cmd
145
+ def initialize(host, cmd)
146
+ @host = host
147
+ @cmd = cmd
148
+ message = "SSH server #{host} failed cmd '#{cmd}'"
149
+ super(message)
150
+ end
151
+ end
@@ -75,5 +75,22 @@ module IndiferentHash
75
75
  end
76
76
  clean
77
77
  end
78
+
79
+ def slice(*list)
80
+ ext_list = []
81
+ list.each do |e|
82
+ case e
83
+ when Symbol
84
+ ext_list << e
85
+ ext_list << e.to_s
86
+ when String
87
+ ext_list << e
88
+ ext_list << e.to_sym
89
+ else
90
+ ext_list << e
91
+ end
92
+ end
93
+ IndiferentHash.setup(super(*ext_list))
94
+ end
78
95
  end
79
96