scout-gear 10.8.3 → 10.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +17 -0
  3. data/README.md +352 -0
  4. data/Rakefile +1 -0
  5. data/VERSION +1 -1
  6. data/doc/Association.md +288 -0
  7. data/doc/Entity.md +296 -0
  8. data/doc/KnowledgeBase.md +433 -0
  9. data/doc/Persist.md +356 -0
  10. data/doc/Semaphore.md +171 -0
  11. data/doc/TSV.md +449 -0
  12. data/doc/WorkQueue.md +359 -0
  13. data/doc/Workflow.md +586 -0
  14. data/lib/scout/association.rb +4 -2
  15. data/lib/scout/entity/identifiers.rb +1 -1
  16. data/lib/scout/entity/object.rb +1 -1
  17. data/lib/scout/entity/property.rb +5 -5
  18. data/lib/scout/entity.rb +1 -1
  19. data/lib/scout/knowledge_base/description.rb +1 -1
  20. data/lib/scout/knowledge_base/list.rb +7 -2
  21. data/lib/scout/knowledge_base/registry.rb +2 -2
  22. data/lib/scout/knowledge_base.rb +20 -2
  23. data/lib/scout/monitor.rb +300 -0
  24. data/lib/scout/persist/engine/packed_index.rb +2 -2
  25. data/lib/scout/persist/engine/sharder.rb +1 -1
  26. data/lib/scout/persist/tsv.rb +1 -0
  27. data/lib/scout/semaphore.rb +1 -1
  28. data/lib/scout/tsv/dumper.rb +3 -3
  29. data/lib/scout/tsv/open.rb +1 -0
  30. data/lib/scout/tsv/parser.rb +1 -1
  31. data/lib/scout/tsv/transformer.rb +1 -0
  32. data/lib/scout/tsv/util.rb +2 -2
  33. data/lib/scout/work_queue/socket.rb +1 -1
  34. data/lib/scout/work_queue/worker.rb +7 -5
  35. data/lib/scout/workflow/documentation.rb +1 -1
  36. data/lib/scout/workflow/entity.rb +22 -1
  37. data/lib/scout/workflow/step/config.rb +3 -3
  38. data/lib/scout/workflow/step/file.rb +4 -0
  39. data/lib/scout/workflow/step/info.rb +8 -2
  40. data/lib/scout/workflow/step.rb +10 -5
  41. data/lib/scout/workflow/task/inputs.rb +1 -1
  42. data/lib/scout/workflow/usage.rb +3 -2
  43. data/lib/scout/workflow/util.rb +22 -0
  44. data/scout-gear.gemspec +20 -6
  45. data/scout_commands/cat +86 -0
  46. data/scout_commands/doc +3 -1
  47. data/scout_commands/entity +151 -0
  48. data/scout_commands/system/clean +146 -0
  49. data/scout_commands/system/status +238 -0
  50. data/scout_commands/workflow/info +23 -10
  51. data/scout_commands/workflow/install +1 -1
  52. data/scout_commands/workflow/task +1 -1
  53. data/test/scout/entity/test_property.rb +1 -1
  54. data/test/scout/knowledge_base/test_registry.rb +19 -0
  55. data/test/scout/test_work_queue.rb +1 -1
  56. data/test/scout/work_queue/test_worker.rb +12 -10
  57. metadata +32 -5
  58. data/doc/lib/scout/path.md +0 -35
  59. data/doc/lib/scout/workflow/task.md +0 -13
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+ require 'scout/monitor'
5
+
6
+ $0 = "rbbt #{$previous_commands*""} #{ File.basename(__FILE__) }" if $previous_commands
7
+
8
+ options = SOPT.setup <<EOF
9
+
10
+ Report the status of the system
11
+
12
+ $ rbbt system status <workflow> <task>
13
+
14
+ Specify workflow '.' and no task to examine the jobs of the current directory (usefull for web-server cache).
15
+
16
+ -h--help Print this help
17
+ -q--quick Quick check
18
+ -a--all Print all jobs, not only uncompleted
19
+ -i--inputs* List of inputs to print
20
+ -if--info_fields* List of info fields to print
21
+ EOF
22
+ scout_usage and exit 0 if options[:help]
23
+
24
+ workflow, task = ARGV
25
+
26
+
27
+ workflow = workflow.split "," if workflow
28
+ task = task.split "," if task
29
+
30
+ all = options.delete :all
31
+
32
+ inputs = (options[:inputs] || "").split(",")
33
+ info_fields = (options[:info_fields] || "").split(",")
34
+
35
+ def pid_msg(pid)
36
+ color = if pid and Misc.pid_alive? pid
37
+ :green
38
+ else
39
+ :red
40
+ end
41
+ if pid.nil?
42
+ ""
43
+ else
44
+ Log.color(color, pid)
45
+ end
46
+ end
47
+
48
+
49
+ #def status_msg(status)
50
+ # color = case status.to_sym
51
+ # when :error, :aborted, :missing, :dead, :broken
52
+ # :red
53
+ # when :streaming, :started
54
+ # :cyan
55
+ # when :done
56
+ # :green
57
+ # when :noinfo, :notfound
58
+ # :blue
59
+ # when :dependencies, :waiting, :setup
60
+ # :yellow
61
+ # else
62
+ # if status.to_s.index ">"
63
+ # :cyan
64
+ # else
65
+ # :cyan
66
+ # end
67
+ # end
68
+ # Log.color(color, status.to_s)
69
+ #end
70
+
71
+ def input_msg(file, inputs)
72
+
73
+ str = ""
74
+ job_inputs = Step.new(file).recursive_inputs.to_hash
75
+ IndiferentHash.setup(job_inputs)
76
+
77
+ inputs.each do |input|
78
+ value = job_inputs[input]
79
+ next if value.nil?
80
+ value_str = Misc.fingerprint(value)
81
+ str << "\t#{Log.color :magenta, input}=#{value_str}"
82
+ end
83
+ str
84
+ end
85
+
86
+ def info_msg(info, info_fields)
87
+
88
+ str = ""
89
+ info_fields.each do |field|
90
+ value = info[field]
91
+ next if value.nil?
92
+ value_str = Misc.fingerprint(value)
93
+ str << "\t#{Log.color :magenta, field}=#{value_str}"
94
+ end
95
+ str
96
+ end
97
+
98
+
99
+ puts Log.color(:magenta, "# System report")
100
+ puts
101
+ sort_files = Proc.new do |a,b|
102
+ fa,ia = a
103
+ fb,ib = b
104
+
105
+ dira = fa.split(/[:_][^\/>]*$/).first
106
+ dirb = fb.split(/[:_][^\/>]*$/).first
107
+
108
+ case dira <=> dirb
109
+ when -1
110
+ -1
111
+ when 1
112
+ 1
113
+ else
114
+ ia[:ctime] <=> ib[:ctime]
115
+ end
116
+ end
117
+
118
+
119
+ persists = Scout.persist_info
120
+ if persists.any?
121
+ puts Log.color(:magenta, "Persist:")
122
+ persists.sort_by{|f,i| i[:ctime] }.each do |file,info|
123
+ elapsed = info[:elapsed]
124
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}")
125
+ end
126
+ puts
127
+ end
128
+
129
+ sensiblewrites = Scout.sensiblewrite_info
130
+ if sensiblewrites.any?
131
+ puts Log.color(:magenta, "Writing:")
132
+ sensiblewrites.sort_by{|f,i| i[:ctime] }.each do |file,info|
133
+ elapsed = info[:elapsed]
134
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}")
135
+ end
136
+ puts
137
+ end
138
+
139
+ locks = Scout.lock_info
140
+ if locks.any?
141
+ puts Log.color(:magenta, "Locks:")
142
+ locks.sort(&sort_files).each do |file,info|
143
+ elapsed, pid, ppid = info.values_at :elapsed, :pid, :ppid
144
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}; ppid: #{ppid}; pid: #{pid_msg pid}")
145
+ end
146
+ puts
147
+ end
148
+
149
+ exit 0 if workflow.nil?
150
+ workflow = nil if workflow == ["all"]
151
+
152
+ puts Log.color(:magenta, "# Workflows")
153
+
154
+ if workflow === ['.']
155
+ jobs = Scout.job_info ["all"], task, ['.']
156
+ else
157
+ jobs = Scout.job_info workflow, task
158
+ end
159
+
160
+ workflows = {}
161
+
162
+ TSV.traverse jobs, :_bar => "Checking job status" do |file,info|
163
+ next unless all || ! info[:done] || ! File.exist?(file)
164
+ workflow = info[:workflow]
165
+ task = info[:task]
166
+ workflows[workflow] ||= {}
167
+ workflows[workflow][task] ||= {}
168
+ workflows[workflow][task][file] ||= info
169
+ end
170
+
171
+ workflows.sort.each do |workflow,tasks|
172
+ tasks.sort.each do |task,jobs|
173
+ puts "* " << Log.color(:magenta, workflow) << "#" << Log.color(:yellow, task) << ": " << Log.color(:blue, jobs.length.to_s)
174
+
175
+ files_txt = jobs.collect do |file, i|
176
+ str = file.dup
177
+ if options[:quick] and i[:done]
178
+ status = 'done'
179
+ str << " #{ Step.prov_status_msg status }"
180
+ if inputs and inputs.any?
181
+ str << input_msg(file, inputs)
182
+ end
183
+
184
+ if info_fields and info_fields.any?
185
+ info = begin
186
+ Open.open(i[:info_file]) do |f|
187
+ Step.load_info(f)
188
+ end
189
+ rescue
190
+ Log.exception $!
191
+ {:status => :noinfo}
192
+ end
193
+ IndiferentHash.setup(info)
194
+ str << info_msg(info, info_fields)
195
+ end
196
+ else
197
+ info = begin
198
+ Open.open(i[:info_file]) do |f|
199
+ Step.load_info(f)
200
+ end
201
+ rescue
202
+ {:status => :noinfo}
203
+ end
204
+ IndiferentHash.setup(info)
205
+
206
+ pid = info[:pid]
207
+ status = info[:status]
208
+ status = :missing if status == :done and not (Open.exist?(file) && ! Open.broken_link?(file))
209
+ status = :broken if Open.broken_link?(file)
210
+ status = status.to_s
211
+ if status != "done" and pid and not Misc.pid_alive?(pid)
212
+ if File.exist? file
213
+ status << Log.color(:red, " (out of sync)")
214
+ else
215
+ status << Log.color(:red, " (dead)")
216
+ end
217
+ end
218
+ str << " #{ Step.prov_status_msg status }"
219
+ str << " (dirty)" if status == 'done' && Step.new(file).dirty?
220
+
221
+ if inputs and inputs.any?
222
+ str << input_msg(file, inputs)
223
+ end
224
+
225
+ if info_fields and info_fields.any?
226
+ str << info_msg(info, info_fields)
227
+ end
228
+ end
229
+ str << "; #{pid_msg pid}" unless status == "done"
230
+ str
231
+ end
232
+
233
+ files_txt.each do |f|
234
+ next if f.nil?
235
+ puts " " << f
236
+ end
237
+ end
238
+ end
@@ -11,6 +11,8 @@ Show info from job
11
11
  $ #{$0} [<options>] <step_path>
12
12
 
13
13
  -h--help Print this help
14
+ -i--inputs Pretty print the inputs
15
+ -ri--recursive_inputs Pretty print the inputs (recursively)
14
16
  EOF
15
17
  if options[:help]
16
18
  if defined? scout_usage
@@ -25,17 +27,28 @@ path = ARGV.first
25
27
  raise MissingParameterException.new :step_path if path.nil?
26
28
  step = Step.load(path.dup)
27
29
 
28
- step.info.each do |k,v|
29
- case v
30
- when nil
30
+ if options[:inputs]
31
+ names, values = step.info.values_at :input_names, :inputs
32
+ names.zip(values).each do |name,value|
33
+ puts [Log.color(:title, name), Log.fingerprint(value)] * " = "
34
+ end
35
+ elsif options[:recursive_inputs]
36
+ step.recursive_inputs.each do |name,value|
37
+ puts [Log.color(:title, name), Log.fingerprint(value)] * " = "
38
+ end
39
+ else
40
+ step.info.each do |k,v|
41
+ case v
42
+ when nil
43
+ next
44
+ when Exception
45
+ puts Log.color(:title, "Exception")
46
+ Log.exception v
47
+ else
48
+ puts [Log.color(:title, k), Log.fingerprint(v)] * " = "
49
+ end
50
+ rescue
31
51
  next
32
- when Exception
33
- puts Log.color(:title, "Exception")
34
- Log.exception v
35
- else
36
- puts [Log.color(:title, k), Log.fingerprint(v)] * " = "
37
52
  end
38
- rescue
39
- next
40
53
  end
41
54
 
@@ -65,7 +65,7 @@ Misc.in_dir(workflow_dir) do
65
65
  Log.info "Installing: " + workflow
66
66
 
67
67
  if base_repo.nil?
68
- repo_base_url = Rbbt.etc.workflow_repo.exists? ? Rbbt.etc.workflow_repo.read.strip : 'https://github.com/Rbbt-Workflows/'
68
+ repo_base_url = Scout.etc.workflow_repo.exists? ? Scout.etc.workflow_repo.read.strip : 'https://github.com/Rbbt-Workflows/'
69
69
  else
70
70
  repo_base_url = base_repo
71
71
  end
@@ -115,7 +115,7 @@ else
115
115
  when "serial"
116
116
  job.run(true)
117
117
  when "local"
118
- refresh = Scout::Config.get :refresh, :deploy, :local, :orchestrator, default: 3
118
+ refresh = Scout::Config.get :refresh, :deploy, :local, :orchestrator, default: 0.5
119
119
  orchestrator = Workflow::Orchestrator.new refresh.to_f, "cpus" => Misc.processors
120
120
  orchestrator.process({}, job)
121
121
  when "slurm"
@@ -335,7 +335,7 @@ class TestEntityProperty < Test::Unit::TestCase
335
335
 
336
336
  def test_all_properties
337
337
  assert ReversableString.setup("TEST").all_properties.include?(:reverse_text_ary)
338
- assert_equal ReversableString.setup("TEST").all_properties, ReversableString.properties
338
+ assert_equal ReversableString.setup("TEST").all_properties.sort, ReversableString.properties.keys.sort
339
339
  end
340
340
 
341
341
  def test_times
@@ -31,5 +31,24 @@ Isa,IV
31
31
  end
32
32
  end
33
33
  end
34
+
35
+ def test_registry_identifiers_target
36
+ identifier =<<-EOF
37
+ #Alias,Initials
38
+ Clei,CC
39
+ Miki,MV
40
+ Guille,GC
41
+ Isa,IV
42
+ EOF
43
+ TmpFile.with_dir do |dir|
44
+ TmpFile.with_file(identifier) do |identifier_file|
45
+ identifiers = TSV.open(identifier_file, sep: ",", type: :single)
46
+ brothers = datafile_test(:person).brothers
47
+ kb = KnowledgeBase.new dir
48
+ kb.register :brothers, brothers, identifiers: identifiers
49
+ assert_include kb.get_index(:brothers, source: "=>Initials", target: "=>Initials"), "CC~GC"
50
+ end
51
+ end
52
+ end
34
53
  end
35
54
 
@@ -142,7 +142,7 @@ class TestWorkQueue < Test::Unit::TestCase
142
142
 
143
143
  res = []
144
144
  q.process do |out|
145
- raise ScoutException
145
+ raise ScoutException
146
146
  res << out
147
147
  end
148
148
 
@@ -156,7 +156,7 @@ class TestQueueWorker < Test::Unit::TestCase
156
156
  input = WorkQueue::Socket.new
157
157
  output = WorkQueue::Socket.new
158
158
 
159
- workers = 10.times.collect{ WorkQueue::Worker.new }
159
+ workers = 5.times.collect{ WorkQueue::Worker.new }
160
160
  workers.each do |w|
161
161
  w.process(input, output) do |obj|
162
162
  raise ScoutException
@@ -164,18 +164,19 @@ class TestQueueWorker < Test::Unit::TestCase
164
164
  end
165
165
  end
166
166
 
167
- read = Thread.new do
167
+ Open.purge_pipes(input.swrite, output.sread)
168
+ read = Thread.new do
168
169
  Thread.current.report_on_exception = false
169
- begin
170
- while obj = output.read
171
- if DoneProcessing === obj
172
- pid = obj.pid
173
- @worker_mutex.synchronize{ @workers.delete_if{|w| w.pid = pid } }
174
- break if workers.empty?
175
- end
176
- raise obj if Exception === obj
170
+ while obj = output.read
171
+ if DoneProcessing === obj
172
+ pid = obj.pid
173
+ @worker_mutex.synchronize{ @workers.delete_if{|w| w.pid = pid } }
174
+ break if workers.empty?
177
175
  end
176
+ raise obj if Exception === obj
178
177
  end
178
+ ensure
179
+ output.close_read
179
180
  end
180
181
 
181
182
  write = Thread.new do
@@ -187,6 +188,7 @@ class TestQueueWorker < Test::Unit::TestCase
187
188
  input.write DoneProcessing.new
188
189
  end
189
190
  input.close_write
191
+ rescue
190
192
  end
191
193
 
192
194
  write.join
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout-gear
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.8.3
4
+ version: 10.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-06-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: scout-essentials
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: csv
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: juwelier
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -87,18 +101,26 @@ executables:
87
101
  extensions: []
88
102
  extra_rdoc_files:
89
103
  - LICENSE.txt
104
+ - README.md
90
105
  - README.rdoc
91
106
  files:
92
107
  - ".document"
93
108
  - ".gitmodules"
94
109
  - ".vimproject"
95
110
  - LICENSE.txt
111
+ - README.md
96
112
  - README.rdoc
97
113
  - Rakefile
98
114
  - VERSION
99
115
  - bin/scout
100
- - doc/lib/scout/path.md
101
- - doc/lib/scout/workflow/task.md
116
+ - doc/Association.md
117
+ - doc/Entity.md
118
+ - doc/KnowledgeBase.md
119
+ - doc/Persist.md
120
+ - doc/Semaphore.md
121
+ - doc/TSV.md
122
+ - doc/WorkQueue.md
123
+ - doc/Workflow.md
102
124
  - lib/scout-gear.rb
103
125
  - lib/scout.rb
104
126
  - lib/scout/association.rb
@@ -120,6 +142,7 @@ files:
120
142
  - lib/scout/knowledge_base/query.rb
121
143
  - lib/scout/knowledge_base/registry.rb
122
144
  - lib/scout/knowledge_base/traverse.rb
145
+ - lib/scout/monitor.rb
123
146
  - lib/scout/persist/engine.rb
124
147
  - lib/scout/persist/engine/fix_width_table.rb
125
148
  - lib/scout/persist/engine/packed_index.rb
@@ -198,7 +221,9 @@ files:
198
221
  - scout_commands/alias
199
222
  - scout_commands/batch/clean
200
223
  - scout_commands/batch/list
224
+ - scout_commands/cat
201
225
  - scout_commands/doc
226
+ - scout_commands/entity
202
227
  - scout_commands/find
203
228
  - scout_commands/glob
204
229
  - scout_commands/kb/config
@@ -212,6 +237,8 @@ files:
212
237
  - scout_commands/rbbt
213
238
  - scout_commands/resource/produce
214
239
  - scout_commands/resource/sync
240
+ - scout_commands/system/clean
241
+ - scout_commands/system/status
215
242
  - scout_commands/template
216
243
  - scout_commands/update
217
244
  - scout_commands/workflow/cmd
@@ -334,7 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
334
361
  - !ruby/object:Gem::Version
335
362
  version: '0'
336
363
  requirements: []
337
- rubygems_version: 3.6.6
364
+ rubygems_version: 3.7.0.dev
338
365
  specification_version: 4
339
366
  summary: basic gear for scouts
340
367
  test_files: []
@@ -1,35 +0,0 @@
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}
@@ -1,13 +0,0 @@
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
- ```