scout-gear 7.3.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +44 -16
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +21 -7
  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 +1 -0
  9. data/lib/scout/cmd.rb +24 -25
  10. data/lib/scout/concurrent_stream.rb +59 -39
  11. data/lib/scout/config.rb +1 -1
  12. data/lib/scout/exceptions.rb +10 -0
  13. data/lib/scout/log/color.rb +15 -12
  14. data/lib/scout/log/progress/report.rb +8 -6
  15. data/lib/scout/log/progress/util.rb +61 -54
  16. data/lib/scout/log/progress.rb +1 -1
  17. data/lib/scout/log/trap.rb +107 -0
  18. data/lib/scout/log.rb +115 -52
  19. data/lib/scout/meta_extension.rb +47 -6
  20. data/lib/scout/misc/digest.rb +12 -3
  21. data/lib/scout/misc/format.rb +24 -7
  22. data/lib/scout/misc/insist.rb +1 -1
  23. data/lib/scout/misc/monitor.rb +22 -0
  24. data/lib/scout/misc/system.rb +58 -0
  25. data/lib/scout/named_array.rb +73 -3
  26. data/lib/scout/offsite/ssh.rb +171 -0
  27. data/lib/scout/offsite/step.rb +83 -0
  28. data/lib/scout/offsite/sync.rb +55 -0
  29. data/lib/scout/offsite.rb +3 -0
  30. data/lib/scout/open/lock/lockfile.rb +587 -0
  31. data/lib/scout/open/lock.rb +9 -2
  32. data/lib/scout/open/remote.rb +16 -1
  33. data/lib/scout/open/stream.rb +146 -83
  34. data/lib/scout/open/util.rb +22 -3
  35. data/lib/scout/open.rb +5 -4
  36. data/lib/scout/path/find.rb +24 -11
  37. data/lib/scout/path/util.rb +40 -0
  38. data/lib/scout/persist/serialize.rb +19 -6
  39. data/lib/scout/persist.rb +29 -13
  40. data/lib/scout/resource/path.rb +57 -0
  41. data/lib/scout/resource/produce.rb +0 -8
  42. data/lib/scout/resource/util.rb +12 -5
  43. data/lib/scout/tmpfile.rb +7 -8
  44. data/lib/scout/tsv/attach.rb +177 -0
  45. data/lib/scout/tsv/change_id.rb +40 -0
  46. data/lib/scout/tsv/dumper.rb +74 -46
  47. data/lib/scout/tsv/index.rb +85 -87
  48. data/lib/scout/tsv/open.rb +160 -85
  49. data/lib/scout/tsv/parser.rb +142 -80
  50. data/lib/scout/tsv/path.rb +1 -2
  51. data/lib/scout/tsv/persist/adapter.rb +15 -45
  52. data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
  53. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -1
  54. data/lib/scout/tsv/persist.rb +4 -0
  55. data/lib/scout/tsv/stream.rb +204 -0
  56. data/lib/scout/tsv/transformer.rb +152 -0
  57. data/lib/scout/tsv/traverse.rb +96 -92
  58. data/lib/scout/tsv/util/filter.rb +9 -0
  59. data/lib/scout/tsv/util/reorder.rb +81 -0
  60. data/lib/scout/tsv/util/select.rb +78 -33
  61. data/lib/scout/tsv/util/unzip.rb +86 -0
  62. data/lib/scout/tsv/util.rb +60 -11
  63. data/lib/scout/tsv.rb +34 -4
  64. data/lib/scout/work_queue/socket.rb +6 -1
  65. data/lib/scout/work_queue/worker.rb +5 -2
  66. data/lib/scout/work_queue.rb +51 -20
  67. data/lib/scout/workflow/definition.rb +23 -3
  68. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  69. data/lib/scout/workflow/deployment.rb +1 -0
  70. data/lib/scout/workflow/step/dependencies.rb +56 -10
  71. data/lib/scout/workflow/step/file.rb +5 -0
  72. data/lib/scout/workflow/step/info.rb +40 -7
  73. data/lib/scout/workflow/step/load.rb +1 -1
  74. data/lib/scout/workflow/step/provenance.rb +9 -7
  75. data/lib/scout/workflow/step/status.rb +43 -0
  76. data/lib/scout/workflow/step.rb +160 -49
  77. data/lib/scout/workflow/task/dependencies.rb +114 -0
  78. data/lib/scout/workflow/task/inputs.rb +40 -32
  79. data/lib/scout/workflow/task.rb +38 -102
  80. data/lib/scout/workflow/usage.rb +48 -18
  81. data/lib/scout/workflow.rb +4 -2
  82. data/lib/scout-gear.rb +2 -0
  83. data/lib/scout.rb +6 -0
  84. data/scout-gear.gemspec +52 -23
  85. data/scout_commands/doc +37 -0
  86. data/scout_commands/find +1 -0
  87. data/scout_commands/offsite +30 -0
  88. data/scout_commands/update +29 -0
  89. data/scout_commands/workflow/info +15 -3
  90. data/scout_commands/workflow/install +102 -0
  91. data/scout_commands/workflow/task +57 -9
  92. data/test/scout/offsite/test_ssh.rb +15 -0
  93. data/test/scout/offsite/test_step.rb +33 -0
  94. data/test/scout/offsite/test_sync.rb +36 -0
  95. data/test/scout/offsite/test_task.rb +0 -0
  96. data/test/scout/open/test_stream.rb +60 -58
  97. data/test/scout/path/test_find.rb +10 -1
  98. data/test/scout/resource/test_path.rb +6 -0
  99. data/test/scout/resource/test_produce.rb +15 -0
  100. data/test/scout/test_meta_extension.rb +25 -0
  101. data/test/scout/test_named_array.rb +24 -0
  102. data/test/scout/test_persist.rb +9 -2
  103. data/test/scout/test_tsv.rb +229 -2
  104. data/test/scout/test_work_queue.rb +65 -41
  105. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  106. data/test/scout/tsv/test_attach.rb +227 -0
  107. data/test/scout/tsv/test_change_id.rb +98 -0
  108. data/test/scout/tsv/test_dumper.rb +1 -1
  109. data/test/scout/tsv/test_index.rb +49 -3
  110. data/test/scout/tsv/test_open.rb +160 -2
  111. data/test/scout/tsv/test_parser.rb +33 -2
  112. data/test/scout/tsv/test_persist.rb +2 -0
  113. data/test/scout/tsv/test_stream.rb +200 -0
  114. data/test/scout/tsv/test_transformer.rb +120 -0
  115. data/test/scout/tsv/test_traverse.rb +88 -3
  116. data/test/scout/tsv/test_util.rb +1 -0
  117. data/test/scout/tsv/util/test_reorder.rb +94 -0
  118. data/test/scout/tsv/util/test_select.rb +25 -11
  119. data/test/scout/tsv/util/test_unzip.rb +112 -0
  120. data/test/scout/work_queue/test_socket.rb +0 -1
  121. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  122. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  123. data/test/scout/workflow/step/test_info.rb +18 -0
  124. data/test/scout/workflow/step/test_status.rb +30 -0
  125. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  126. data/test/scout/workflow/task/test_inputs.rb +67 -14
  127. data/test/scout/workflow/test_definition.rb +18 -0
  128. data/test/scout/workflow/test_documentation.rb +24 -0
  129. data/test/scout/workflow/test_step.rb +112 -3
  130. data/test/scout/workflow/test_task.rb +0 -151
  131. data/test/scout/workflow/test_usage.rb +33 -6
  132. data/test/test_scout.rb +9 -0
  133. metadata +100 -8
  134. data/scout_commands/workflow/task_old +0 -706
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7273030ac34bd180620d9075ee85b26d8a9883831a5925fc911915f1edeeecf3
4
- data.tar.gz: 4e445acb896844240c0024b7754cffee93af71feb62f9c4251fda70aee79121a
3
+ metadata.gz: 9ca509bfb5065aabcdae73545139db0f8b04748084821e002c0475a55be5cb70
4
+ data.tar.gz: 6f0333ca6dd0ceee0ea9290cf3c30f7164c2f0732b76ce739e29da19a0687242
5
5
  SHA512:
6
- metadata.gz: '029a8eb23eda77c7e0c11ac2966e1e8ebf3eae479bbee0c76e113f5b839c655e97e0fec5025cc3c251795afcfc92ac3395a79b68c8eb99158d1cee8e2310f002'
7
- data.tar.gz: 04ed4bcabfa7c41b80ba520074404bfb09c723ecdb8d02a2052f73fe86759bab7fdadff31f0f66284ed4938ebe5a1cad56fb94182b3edcc0de6325decdcb84f6
6
+ metadata.gz: 2cbd82d97ec0dad50e624cda26ae6a05aeba8b9e5ff07a5b4746c677b8e2ab1996378237095ba09a70f8ed8cc926d782c1677aa24d6f94784f560090d6845a2c
7
+ data.tar.gz: aa9529b3393016c846b578b736428b964519d2fb5c1507a6335eff651d0588a5d9191cc61cff52279c18902f2efce386415099bcd92f8736f6d67cef1d33b561
data/.vimproject CHANGED
@@ -8,11 +8,14 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
8
8
  alias
9
9
  find
10
10
  glob
11
+ doc
12
+ update
13
+ offsite
11
14
  workflow=workflow{
12
- task_old
13
15
  task
14
16
  list
15
17
  info
18
+ install
16
19
  }
17
20
  }
18
21
  lib=lib {
@@ -32,7 +35,6 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
32
35
  filesystem.rb
33
36
  monitor.rb
34
37
  system.rb
35
- helper.rb
36
38
  }
37
39
  named_array.rb
38
40
  indiferent_hash.rb
@@ -50,6 +52,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
50
52
  report.rb
51
53
  util.rb
52
54
  }
55
+ trap.rb
53
56
  }
54
57
  tmpfile.rb
55
58
  simple_opt.rb
@@ -71,6 +74,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
71
74
  open.rb
72
75
  open=open{
73
76
  lock.rb
77
+ lock=lock{
78
+ lockfile.rb
79
+ }
74
80
  stream.rb
75
81
  remote.rb
76
82
  util.rb
@@ -96,23 +102,29 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
96
102
  workflow.rb
97
103
  workflow=workflow{
98
104
  definition.rb
105
+ documentation.rb
106
+ usage.rb
107
+ util.rb
99
108
  step.rb
100
109
  step=step{
101
- info.rb
102
- load.rb
103
- file.rb
104
110
  config.rb
105
111
  dependencies.rb
106
- provenance.rb
112
+ file.rb
113
+ info.rb
114
+ load.rb
107
115
  progress.rb
116
+ provenance.rb
117
+ status.rb
108
118
  }
109
119
  task.rb
110
120
  task=task{
121
+ dependencies.rb
111
122
  inputs.rb
112
123
  }
113
- documentation.rb
114
- usage.rb
115
- util.rb
124
+ deployment.rb
125
+ deployment=deployment{
126
+ orchestrator.rb
127
+ }
116
128
  }
117
129
  semaphore.rb
118
130
  work_queue.rb
@@ -122,26 +134,40 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
122
134
  }
123
135
  tsv.rb
124
136
  tsv=tsv{
137
+ util.rb
138
+ util=util{
139
+ process.rb
140
+ select.rb
141
+ process.rb
142
+ unzip.rb
143
+ reorder.rb
144
+ }
125
145
  parser.rb
126
146
  dumper.rb
147
+ transformer.rb
127
148
  persist.rb
128
149
  persist=persist{
129
150
  adapter.rb
130
151
  serialize.rb
152
+ sdbm.rb
153
+ tkrzw.rb
131
154
  tokyocabinet.rb
132
155
  fix_width_table.rb
133
156
  }
134
157
  index.rb
135
158
  traverse.rb
136
- util.rb
137
- util=util{
138
- process.rb
139
- select.rb
140
- filter.rb
141
- }
159
+ attach.rb
160
+ change_id.rb
142
161
  path.rb
162
+ stream.rb
143
163
  open.rb
144
164
  }
165
+ offsite.rb
166
+ offsite=offsite{
167
+ ssh.rb
168
+ sync.rb
169
+ step.rb
170
+ }
145
171
  }
146
172
  }
147
173
  test=test {
@@ -309,6 +335,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
309
335
 
310
336
  workflow.rb
311
337
  workflow=workflow{
338
+ refactor.rb
312
339
  annotate.rb
313
340
 
314
341
  definition.rb
@@ -390,6 +417,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
390
417
 
391
418
  tsv.rb
392
419
  tsv=tsv{
420
+ refactor.rb
393
421
  parser.rb
394
422
  dumper.rb
395
423
 
@@ -513,7 +541,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
513
541
  test_path.rb
514
542
  }
515
543
  workflow=workflow{
516
- _test_soap.rb
544
+ test_soap.rb
517
545
  test_doc.rb
518
546
  test_step.rb
519
547
  test_task.rb
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
- 7.3.0
1
+ 8.1.0
data/bin/scout CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  $LOAD_PATH.unshift File.join(__dir__, '../lib')
4
4
 
5
+ ENV["SCOUT_NOCOLOR"] = "true" if ARGV.include? "--nocolor"
6
+
7
+ ENV["SCOUT_NO_PROGRESS"] = "true" if ARGV.include? "--nobar"
8
+
5
9
  require 'scout-gear'
6
10
 
7
11
  class CmdStop < Exception
@@ -31,6 +35,12 @@ if dev_dir.nil?
31
35
  ARGV.delete _s if _s
32
36
  end
33
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
+
34
44
  if dev_dir
35
45
  ['scout-*/lib'].each do |pattern|
36
46
  Dir.glob(File.join(File.expand_path(dev_dir), pattern)).each do |f|
@@ -44,7 +54,6 @@ if dev_dir
44
54
  end
45
55
  end
46
56
 
47
- Log.nocolor = true if ARGV.include? "--nocolor"
48
57
 
49
58
  require 'scout/simple_opt'
50
59
 
@@ -59,6 +68,7 @@ $ #{$0} <command> <subcommand> ... -a --arg1 --arg2='value' --arg3 'another-valu
59
68
  --nocolor #{Log.color :yellow, "Disable colored output"}
60
69
  --nobar #{Log.color :yellow, "Disable progress report"}
61
70
  --locate_file #{Log.color :yellow, "Report the location of the script instead of executing it"}
71
+ -ck--config_keys* #{Log.color :yellow, "Override some config keys"}
62
72
  EOF
63
73
 
64
74
  Log.nocolor = true if options[:nocolor]
@@ -66,11 +76,11 @@ Log.nocolor = true if options[:nocolor]
66
76
  locate = options.delete :locate_file
67
77
 
68
78
  if options[:log_file]
69
- Log.logfile(options[:log_file])
79
+ Log.logfile(options.delete(:log_file))
70
80
  end
71
81
 
72
82
  if options[:log]
73
- Log.severity = options[:log].to_i
83
+ Log.severity = options.delete(:log).to_i
74
84
  else
75
85
  global_severity = Log.get_level(Scout.etc.log_severity.read.strip) if Scout.etc.log_severity.exists?
76
86
  if ENV["SCOUT_LOG"]
@@ -81,6 +91,14 @@ else
81
91
  end
82
92
  end
83
93
 
94
+ if config_keys = options.delete(:config_keys)
95
+ config_keys.split(",").each do |config|
96
+ config = config.strip
97
+ Scout::Config.process_config config
98
+ end
99
+ end
100
+
101
+
84
102
  $scout_command_dir = Scout.bin.scout
85
103
  $scout_command_dir.path_maps[:scout_commands] = File.join(File.dirname(__dir__), "{PATH/bin\\/scout/scout_commands}")
86
104
 
@@ -214,7 +232,6 @@ begin
214
232
 
215
233
  scout_usage($previous_commands)
216
234
  exit_status = 0
217
- exit exit_status
218
235
 
219
236
  rescue ParameterException
220
237
  puts
@@ -222,14 +239,11 @@ rescue ParameterException
222
239
  print_error($!.message, $!.backtrace)
223
240
  puts
224
241
  exit_status = -1
225
- exit exit_status
226
242
  rescue SystemExit,CmdStop
227
243
  exit_status = $!.status
228
- exit exit_status
229
244
  rescue Exception
230
245
  Log.exception $!
231
246
  exit_status = -1
232
- exit exit_status
233
247
  ensure
234
248
  if options[:profile]
235
249
  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
@@ -2,4 +2,5 @@ $LOAD_PATH.unshift File.join(__dir__, '../modules/rbbt-util/lib')
2
2
  module Rbbt
3
3
  extend Resource
4
4
  self.pkgdir = 'rbbt'
5
+ self.path_maps = Path.path_maps.merge(:rbbt_lib => File.expand_path(File.join(__dir__, '../modules/rbbt-util/', '{TOPLEVEL}','{SUBPATH}')))
5
6
  end
data/lib/scout/cmd.rb CHANGED
@@ -14,9 +14,9 @@ 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
 
@@ -61,6 +61,7 @@ module CMD
61
61
 
62
62
  def self.scan_version_text(text, cmd = nil)
63
63
  cmd = "NOCMDGIVE" if cmd.nil? || cmd.empty?
64
+ text = Misc.fixutf8 text
64
65
  text.split("\n").each do |line|
65
66
  next unless line =~ /\W#{cmd}\W/i
66
67
  m = line.match(/(v(?:\d+\.)*\d+(?:-[a-z_]+)?)/i)
@@ -98,8 +99,8 @@ module CMD
98
99
 
99
100
  option = "--" << option.to_s if add_dashes and option.to_s[0] != '-'
100
101
 
101
- case
102
- when value.nil? || FalseClass === value
102
+ case
103
+ when value.nil? || FalseClass === value
103
104
  next
104
105
  when TrueClass === value
105
106
  string << "#{option} "
@@ -136,8 +137,8 @@ module CMD
136
137
  dont_close_in = options.delete(:dont_close_in)
137
138
 
138
139
  log = true if log.nil?
139
-
140
- if cmd.nil? && ! Symbol === tool
140
+
141
+ if cmd.nil? && ! Symbol === tool
141
142
  cmd = tool
142
143
  else
143
144
  tool = get_tool(tool)
@@ -163,7 +164,7 @@ module CMD
163
164
 
164
165
  cmd_options = process_cmd_options options
165
166
  if cmd =~ /'\{opt\}'/
166
- cmd.sub!('\'{opt}\'', cmd_options)
167
+ cmd.sub!('\'{opt}\'', cmd_options)
167
168
  else
168
169
  cmd << " " << cmd_options
169
170
  end
@@ -179,29 +180,28 @@ module CMD
179
180
  end
180
181
  pid = wait_thr.pid
181
182
 
182
- Log.debug{"CMD: [#{pid}] #{cmd}" if log}
183
+ Log.debug{"CMD: [#{pid}] #{cmd}".strip if log}
183
184
 
184
185
  if in_content.respond_to?(:read)
185
186
  in_thread = Thread.new(Thread.current) do |parent|
186
- Thread.current.report_on_exception = false if no_fail
187
187
  begin
188
- begin
189
- while c = in_content.readpartial(Open::BLOCK_SIZE)
190
- sin << c
191
- end
192
- rescue EOFError
188
+ Thread.current.report_on_exception = false if no_fail
189
+ Thread.current["name"] = "CMD in"
190
+ while c = in_content.read(Open::BLOCK_SIZE)
191
+ sin << c
193
192
  end
194
193
  sin.close unless sin.closed?
195
194
 
196
195
  unless dont_close_in
197
- in_content.close unless in_content.closed?
198
- in_content.join if in_content.respond_to? :join
196
+ in_content.close unless in_content.closed?
197
+ in_content.join if in_content.respond_to? :join
199
198
  end
200
199
  rescue
201
200
  Log.error "Error in CMD [#{pid}] #{cmd}: #{$!.message}" unless no_fail
202
201
  raise $!
203
202
  end
204
203
  end
204
+ Thread.pass until in_thread["name"]
205
205
  else
206
206
  in_thread = nil
207
207
  sin.close
@@ -211,7 +211,7 @@ module CMD
211
211
 
212
212
  if pipe
213
213
 
214
- ConcurrentStream.setup sout, :pids => pids, :autojoin => autojoin, :no_fail => no_fail
214
+ ConcurrentStream.setup sout, :pids => pids, :autojoin => autojoin, :no_fail => no_fail
215
215
 
216
216
  sout.callback = post if post
217
217
 
@@ -224,7 +224,7 @@ module CMD
224
224
  sout.log = line
225
225
  sout.std_err << line if save_stderr
226
226
  Log.log "STDERR [#{pid}]: " + line, stderr if log
227
- end
227
+ end
228
228
  serr.close
229
229
  rescue
230
230
  Log.exception $!
@@ -244,8 +244,8 @@ module CMD
244
244
  err = ""
245
245
  err_thread = Thread.new do
246
246
  while not serr.eof?
247
- line = serr.gets
248
- bar.process(line)
247
+ line = serr.gets
248
+ bar.process(line)
249
249
  err << line if Integer === stderr and log
250
250
  end
251
251
  serr.close
@@ -254,25 +254,24 @@ module CMD
254
254
  err = ""
255
255
  err_thread = Thread.new do
256
256
  while not serr.eof?
257
- err << serr.gets
257
+ err << serr.gets
258
258
  end
259
259
  serr.close
260
260
  end
261
261
  else
262
262
  Open.consume_stream(serr, true)
263
- #serr.close
264
263
  err_thread = nil
265
264
  err = ""
266
265
  end
267
266
 
268
- ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread].compact, :autojoin => autojoin, :no_fail => no_fail
267
+ ConcurrentStream.setup sout, :pids => pids, :threads => [in_thread, err_thread].compact, :autojoin => autojoin, :no_fail => no_fail
269
268
 
270
269
  begin
271
270
  out = StringIO.new sout.read
272
271
  sout.close unless sout.closed?
273
272
 
274
273
  status = wait_thr.value
275
- if not status.success? and not no_fail
274
+ if status && ! status.success? && ! no_fail
276
275
  if !err.empty?
277
276
  raise ProcessFailed.new pid, "#{cmd} failed with error status #{status.exitstatus}.\n#{err}"
278
277
  else
@@ -324,7 +323,7 @@ module CMD
324
323
  starting = true
325
324
  line = "" if bar
326
325
  end
327
- end
326
+ end
328
327
  begin
329
328
  io.join
330
329
  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
@@ -141,7 +140,11 @@ module ConcurrentStream
141
140
  close unless closed?
142
141
  ensure
143
142
  @joined = true
144
- lock.unlock if lock and lock.locked?
143
+ begin
144
+ lock.unlock if lock && lock.locked?
145
+ rescue
146
+ Log.exception $!
147
+ end
145
148
  raise stream_exception if stream_exception
146
149
  end
147
150
  end
@@ -152,28 +155,24 @@ module ConcurrentStream
152
155
  name += " - file:#{filename}" if filename
153
156
  Log.low "Aborting threads (#{name}) - #{@threads.collect{|t| Log.fingerprint(t) } * ", "}"
154
157
 
155
- @threads.each do |t|
158
+ threads = @threads.dup
159
+ @threads.clear
160
+ threads.each do |t|
156
161
  next if t == Thread.current
162
+ next if t["aborted"]
163
+ t["aborted"] = true
164
+ exception = exception.nil? ? Aborted.new : exception
157
165
  Log.debug "Aborting thread #{Log.fingerprint(t)} with exception: #{exception}"
158
- t.raise((exception.nil? ? Aborted.new : exception))
159
- end
160
-
161
- @threads.each do |t|
162
- next if t == Thread.current
163
- begin
164
- t.join
165
- rescue Aborted
166
- rescue Exception
167
- Log.debug "Thread (#{name}) exception: #{$!.message}"
168
- end
166
+ t.raise(exception)
167
+ t.join
169
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
@@ -217,12 +216,11 @@ module ConcurrentStream
217
216
  begin
218
217
  super(*args)
219
218
  rescue
220
- Log.exception $!
221
219
  self.abort
222
- self.join
220
+ self.join
223
221
  stream_raise_exception $!
224
222
  ensure
225
- self.join if self.closed? or self.eof?
223
+ self.join if ! @stream_exception && (self.closed? || self.eof?)
226
224
  end
227
225
  else
228
226
  super(*args)
@@ -232,33 +230,55 @@ module ConcurrentStream
232
230
  def read(*args)
233
231
  begin
234
232
  super(*args)
235
- rescue
236
- raise stream_exception if stream_exception
237
- raise $!
233
+ rescue Exception
234
+ @stream_exception ||= $!
235
+ raise @stream_exception
238
236
  ensure
239
- begin
240
- close unless closed?
241
- rescue Exception
242
- raise $! if ConcurrentStreamProcessFailed === $!
243
- end if autojoin && ! closed? && eof?
237
+ if ! @stream_exception && autojoin && ! closed?
238
+ begin
239
+ done = eof?
240
+ rescue Exception
241
+ self.abort($!)
242
+ raise $!
243
+ end
244
+ close if done
245
+ end
244
246
  end
245
247
  end
246
248
 
247
249
  def add_callback(&block)
248
250
  old_callback = callback
249
- @callback = Proc.new do
251
+ @callback = Proc.new do
250
252
  old_callback.call if old_callback
251
253
  block.call
252
254
  end
253
255
  end
254
256
 
255
257
  def stream_raise_exception(exception)
258
+ self.stream_exception = exception
256
259
  threads.each do |thread|
257
260
  thread.raise exception
258
261
  end
259
- self.stream_exception = exception
260
-
261
262
  self.abort
262
263
  end
263
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
264
284
  end