scout-gear 10.8.4 → 10.10.1

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +38 -0
  3. data/README.md +352 -0
  4. data/VERSION +1 -1
  5. data/bin/scout +4 -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 +4 -5
  22. data/lib/scout/knowledge_base.rb +20 -2
  23. data/lib/scout/monitor.rb +10 -6
  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/definition.rb +11 -0
  36. data/lib/scout/workflow/deployment/local.rb +288 -0
  37. data/lib/scout/workflow/deployment/orchestrator/batches.rb +130 -0
  38. data/lib/scout/workflow/deployment/orchestrator/chains.rb +104 -0
  39. data/lib/scout/workflow/deployment/orchestrator/rules.rb +256 -0
  40. data/lib/scout/workflow/deployment/orchestrator/workload.rb +67 -0
  41. data/lib/scout/workflow/deployment/scheduler/job.rb +740 -0
  42. data/lib/scout/workflow/deployment/scheduler/lfs.rb +125 -0
  43. data/lib/scout/workflow/deployment/scheduler/pbs.rb +176 -0
  44. data/lib/scout/workflow/deployment/scheduler/slurm.rb +158 -0
  45. data/lib/scout/workflow/deployment/scheduler.rb +73 -0
  46. data/lib/scout/workflow/deployment.rb +10 -1
  47. data/lib/scout/workflow/entity.rb +22 -1
  48. data/lib/scout/workflow/exceptions.rb +2 -0
  49. data/lib/scout/workflow/step/config.rb +6 -3
  50. data/lib/scout/workflow/step/file.rb +4 -0
  51. data/lib/scout/workflow/step/info.rb +10 -4
  52. data/lib/scout/workflow/step/progress.rb +52 -0
  53. data/lib/scout/workflow/step.rb +39 -5
  54. data/lib/scout/workflow/task/inputs.rb +1 -1
  55. data/lib/scout/workflow/task.rb +2 -0
  56. data/lib/scout/workflow/usage.rb +3 -2
  57. data/lib/scout/workflow/util.rb +22 -0
  58. data/scout-gear.gemspec +37 -7
  59. data/scout_commands/batch/list +1 -1
  60. data/scout_commands/cat +86 -0
  61. data/scout_commands/doc +3 -1
  62. data/scout_commands/entity +151 -0
  63. data/scout_commands/system/status +238 -0
  64. data/scout_commands/workflow/cmd +5 -13
  65. data/scout_commands/workflow/info +23 -10
  66. data/scout_commands/workflow/install +1 -1
  67. data/scout_commands/workflow/task +61 -25
  68. data/test/scout/entity/test_property.rb +1 -1
  69. data/test/scout/knowledge_base/test_registry.rb +19 -0
  70. data/test/scout/test_work_queue.rb +1 -1
  71. data/test/scout/work_queue/test_worker.rb +12 -10
  72. data/test/scout/workflow/deployment/orchestrator/test_batches.rb +138 -0
  73. data/test/scout/workflow/deployment/orchestrator/test_chains.rb +171 -0
  74. data/test/scout/workflow/deployment/orchestrator/test_rules.rb +219 -0
  75. data/test/scout/workflow/deployment/orchestrator/test_workload.rb +117 -0
  76. data/test/scout/workflow/deployment/scheduler/test_job.rb +31 -0
  77. data/test/scout/workflow/deployment/scheduler/test_lfs.rb +32 -0
  78. data/test/scout/workflow/deployment/scheduler/test_pbs.rb +32 -0
  79. data/test/scout/workflow/deployment/scheduler/test_slurm.rb +32 -0
  80. data/test/scout/workflow/deployment/{test_orchestrator.rb → test_local.rb} +161 -33
  81. data/test/scout/workflow/deployment/test_scheduler.rb +75 -0
  82. data/test/scout/workflow/deployment/test_trace.rb +1 -1
  83. data/test/scout/workflow/step/test_progress.rb +27 -0
  84. data/test/scout/workflow/task/test_inputs.rb +17 -0
  85. data/test/test_helper.rb +2 -1
  86. metadata +36 -6
  87. data/doc/lib/scout/path.md +0 -35
  88. data/doc/lib/scout/workflow/task.md +0 -13
  89. data/lib/scout/workflow/deployment/orchestrator.rb +0 -292
@@ -25,5 +25,57 @@ class Step
25
25
  kwargs[:bar] = self.progress_bar(desc) unless kwargs.include?(:bar)
26
26
  TSV.traverse obj, **kwargs, &block
27
27
  end
28
+
29
+ def monitor_stream(stream, options = {}, &block)
30
+ case options[:bar]
31
+ when TrueClass
32
+ bar = progress_bar
33
+ when Hash
34
+ bar = progress_bar options[:bar]
35
+ when Numeric
36
+ bar = progress_bar :max => options[:bar]
37
+ else
38
+ bar = options[:bar]
39
+ end
40
+
41
+ out = if bar.nil?
42
+ Open.line_monitor_stream stream, &block
43
+ elsif (block.nil? || block.arity == 0)
44
+ Open.line_monitor_stream stream do
45
+ bar.tick
46
+ end
47
+ elsif block.arity == 1
48
+ Open.line_monitor_stream stream do |line|
49
+ bar.tick
50
+ block.call line
51
+ end
52
+ elsif block.arity == 2
53
+ Open.line_monitor_stream stream do |line|
54
+ block.call line, bar
55
+ end
56
+ end
57
+
58
+ if bar
59
+ ConcurrentStream.setup(out, :abort_callback => Proc.new{
60
+ bar.done
61
+ Log::ProgressBar.remove_bar(bar, true)
62
+ }, :callback => Proc.new{
63
+ bar.done
64
+ Log::ProgressBar.remove_bar(bar)
65
+ })
66
+ end
67
+
68
+ bgzip = (options[:compress] || options[:gzip]).to_s == 'bgzip'
69
+ bgzip = true if options[:bgzip]
70
+
71
+ gzip = true if options[:compress] || options[:gzip]
72
+ if bgzip
73
+ Open.bgzip(out)
74
+ elsif gzip
75
+ Open.gzip(out)
76
+ else
77
+ out
78
+ end
79
+ end
28
80
  end
29
81
 
@@ -16,7 +16,7 @@ require_relative 'step/archive'
16
16
  class Step
17
17
 
18
18
  attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs, :provided_inputs, :compute, :overriden_task, :overriden_workflow, :workflow, :exec_context, :overriden
19
- def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context = nil, &task)
19
+ def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context: nil, &task)
20
20
  @path = path
21
21
  @inputs = inputs
22
22
  @dependencies = dependencies
@@ -43,6 +43,18 @@ class Step
43
43
  end
44
44
  end
45
45
  end
46
+
47
+ def non_default_inputs
48
+ @non_default_inputs ||= begin
49
+ if info_file && Open.exists?(info_file)
50
+ info[:non_default_inputs]
51
+ else
52
+ []
53
+ end
54
+ end
55
+ end
56
+
57
+
46
58
  def inputs
47
59
  @inputs ||= begin
48
60
  if info_file && Open.exists?(info_file)
@@ -90,6 +102,8 @@ class Step
90
102
  return name.split(".").first
91
103
  end
92
104
 
105
+ attr_accessor :task_name
106
+
93
107
  def task_name
94
108
  return @task_name if @task_name
95
109
  @task_name ||= @task.name if @task.respond_to?(:name)
@@ -112,17 +126,22 @@ class Step
112
126
 
113
127
  def exec
114
128
 
115
- if inputs
129
+ if inputs
116
130
  if Task === task
117
131
  types = task.inputs.collect{|name,type| type }
118
- new_inputs = inputs.zip(types).collect{|input,info|
132
+ new_inputs = inputs.zip(types).collect{|input,info|
119
133
  type, desc, default, options = info
120
134
  next input unless Step === input
121
135
  input.join if input.streaming?
122
136
  Task.format_input(input.join.path, type, options)
123
137
  }
124
138
  else
125
- new_inputs = inputs.collect{|input|
139
+ if Hash === inputs
140
+ new_inputs = inputs.values
141
+ else
142
+ new_inputs = inputs
143
+ end
144
+ new_inputs = new_inputs.collect{|input|
126
145
  Step === input ? input.load : input
127
146
  }
128
147
  end
@@ -184,6 +203,7 @@ class Step
184
203
  :pid => Process.pid, :pid_hostname => Misc.hostname,
185
204
  :task_name => task_name, :workflow => workflow.to_s,
186
205
  :provided_inputs => Annotation.purge(provided_inputs),
206
+ :non_default_inputs => non_default_inputs,
187
207
  :inputs => Annotation.purge(inputs), :input_names => input_names, :type => type,
188
208
  :dependencies => (dependencies || []) .collect{|d| d.path }
189
209
 
@@ -218,8 +238,22 @@ class Step
218
238
 
219
239
  @result
220
240
  rescue Exception => e
221
- merge_info :status => :error, :exception => e, :end => Time.now, :backtrace => e.backtrace, :message => "#{e.class}: #{e.message}"
222
241
  begin
242
+ begin
243
+ if ConcurrentStreamProcessFailed === e
244
+ s = e.concurrent_stream
245
+ e.concurrent_stream = nil
246
+ exception_encoded = Base64.encode64(Marshal.dump(e))
247
+ e.concurrent_stream = s
248
+ else
249
+ exception_encoded = Base64.encode64(Marshal.dump(e))
250
+ end
251
+ merge_info :status => :error, :exception => exception_encoded, :end => Time.now, :backtrace => e.backtrace, :message => "#{e.class}: #{e.message}"
252
+ rescue Exception
253
+ exception_encoded = Base64.encode64(Marshal.dump(Exception.new(e.message)))
254
+ merge_info :status => :error, :exception => exception_encoded, :end => Time.now, :backtrace => e.backtrace, :message => "#{e.class}: #{e.message}"
255
+ end
256
+
223
257
  abort_dependencies
224
258
  ensure
225
259
  raise e
@@ -169,7 +169,7 @@ module Task
169
169
  end
170
170
 
171
171
  def load_inputs(directory)
172
- if Open.exists?(directory) && ! Open.directory?(directory)
172
+ if Open.exists?(directory) && ! Open.directory?(directory) && ! Open.size(directory) == 0
173
173
  TmpFile.with_file do |tmp_directory|
174
174
  Misc.in_dir tmp_directory do
175
175
  CMD.cmd("tar xvfz '#{directory}'")
@@ -42,6 +42,8 @@ module Task
42
42
  memory_inputs = provided_inputs
43
43
  end
44
44
 
45
+ memory_inputs = nil if Array === memory_inputs && memory_inputs.compact.empty?
46
+ memory_inputs = nil if Hash === memory_inputs && memory_inputs.empty?
45
47
  Persist.memory("Task job #{self.name}", repo: Workflow.job_cache, other: {task: self.name, id: id, provided_inputs: memory_inputs}) do
46
48
  provided_inputs, id = id, nil if (provided_inputs.nil? || provided_inputs.empty?) && (Hash === id || Array === id)
47
49
  provided_inputs = {} if provided_inputs.nil?
@@ -35,6 +35,7 @@ module Task
35
35
  str.puts SOPT.input_array_doc(inputs)
36
36
 
37
37
  inputs.select{|name,type, _| type == :select }.each do |name,_,_,_,options|
38
+ next unless options
38
39
  selects << [name, options[:select_options]] if options[:select_options]
39
40
  end
40
41
  end
@@ -194,9 +195,9 @@ module Workflow
194
195
  if child
195
196
  #·description << "->" << task_name.to_s
196
197
  elsif first
197
- description << "" << task_name.to_s
198
+ description += "" + task_name.to_s
198
199
  else
199
- description << ";" << task_name.to_s
200
+ description += ";" + task_name.to_s
200
201
  end
201
202
 
202
203
  seen << [workflow, task_name]
@@ -16,5 +16,27 @@ module Workflow
16
16
  name = name.to_sym
17
17
  dependencies.select{|dep| dep.task_name.to_sym == name }
18
18
  end
19
+
20
+ def all_tasks
21
+ tasks.keys
22
+ end
23
+
24
+ def self.list
25
+ Path.setup('workflows').glob('*').collect{|p| p.basename }
26
+ end
27
+
28
+ def task_jobs_files(task_name)
29
+ self.directory[task_name].glob("**").
30
+ collect{|f| %w(info files).include?(f.get_extension) ? f.unset_extension : f }.
31
+ uniq
32
+ end
33
+
34
+ def task_jobs(task_name)
35
+ task_jobs_files(task_name).collect{|f| Step.load f }
36
+ end
37
+
38
+ def load_job(task_name, name)
39
+ Step.new self.directory[task_name][name]
40
+ end
19
41
  end
20
42
 
data/scout-gear.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: scout-gear 10.8.4 ruby lib
5
+ # stub: scout-gear 10.10.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-gear".freeze
9
- s.version = "10.8.4".freeze
9
+ s.version = "10.10.1".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.executables = ["scout".freeze]
18
18
  s.extra_rdoc_files = [
19
19
  "LICENSE.txt",
20
+ "README.md",
20
21
  "README.rdoc"
21
22
  ]
22
23
  s.files = [
@@ -24,12 +25,19 @@ Gem::Specification.new do |s|
24
25
  ".gitmodules",
25
26
  ".vimproject",
26
27
  "LICENSE.txt",
28
+ "README.md",
27
29
  "README.rdoc",
28
30
  "Rakefile",
29
31
  "VERSION",
30
32
  "bin/scout",
31
- "doc/lib/scout/path.md",
32
- "doc/lib/scout/workflow/task.md",
33
+ "doc/Association.md",
34
+ "doc/Entity.md",
35
+ "doc/KnowledgeBase.md",
36
+ "doc/Persist.md",
37
+ "doc/Semaphore.md",
38
+ "doc/TSV.md",
39
+ "doc/WorkQueue.md",
40
+ "doc/Workflow.md",
33
41
  "lib/scout-gear.rb",
34
42
  "lib/scout.rb",
35
43
  "lib/scout/association.rb",
@@ -98,8 +106,17 @@ Gem::Specification.new do |s|
98
106
  "lib/scout/workflow.rb",
99
107
  "lib/scout/workflow/definition.rb",
100
108
  "lib/scout/workflow/deployment.rb",
101
- "lib/scout/workflow/deployment/orchestrator.rb",
109
+ "lib/scout/workflow/deployment/local.rb",
110
+ "lib/scout/workflow/deployment/orchestrator/batches.rb",
111
+ "lib/scout/workflow/deployment/orchestrator/chains.rb",
112
+ "lib/scout/workflow/deployment/orchestrator/rules.rb",
113
+ "lib/scout/workflow/deployment/orchestrator/workload.rb",
102
114
  "lib/scout/workflow/deployment/queue.rb",
115
+ "lib/scout/workflow/deployment/scheduler.rb",
116
+ "lib/scout/workflow/deployment/scheduler/job.rb",
117
+ "lib/scout/workflow/deployment/scheduler/lfs.rb",
118
+ "lib/scout/workflow/deployment/scheduler/pbs.rb",
119
+ "lib/scout/workflow/deployment/scheduler/slurm.rb",
103
120
  "lib/scout/workflow/deployment/trace.rb",
104
121
  "lib/scout/workflow/documentation.rb",
105
122
  "lib/scout/workflow/entity.rb",
@@ -130,7 +147,9 @@ Gem::Specification.new do |s|
130
147
  "scout_commands/alias",
131
148
  "scout_commands/batch/clean",
132
149
  "scout_commands/batch/list",
150
+ "scout_commands/cat",
133
151
  "scout_commands/doc",
152
+ "scout_commands/entity",
134
153
  "scout_commands/find",
135
154
  "scout_commands/glob",
136
155
  "scout_commands/kb/config",
@@ -145,6 +164,7 @@ Gem::Specification.new do |s|
145
164
  "scout_commands/resource/produce",
146
165
  "scout_commands/resource/sync",
147
166
  "scout_commands/system/clean",
167
+ "scout_commands/system/status",
148
168
  "scout_commands/template",
149
169
  "scout_commands/update",
150
170
  "scout_commands/workflow/cmd",
@@ -226,13 +246,23 @@ Gem::Specification.new do |s|
226
246
  "test/scout/tsv/util/test_unzip.rb",
227
247
  "test/scout/work_queue/test_socket.rb",
228
248
  "test/scout/work_queue/test_worker.rb",
229
- "test/scout/workflow/deployment/test_orchestrator.rb",
249
+ "test/scout/workflow/deployment/orchestrator/test_batches.rb",
250
+ "test/scout/workflow/deployment/orchestrator/test_chains.rb",
251
+ "test/scout/workflow/deployment/orchestrator/test_rules.rb",
252
+ "test/scout/workflow/deployment/orchestrator/test_workload.rb",
253
+ "test/scout/workflow/deployment/scheduler/test_job.rb",
254
+ "test/scout/workflow/deployment/scheduler/test_lfs.rb",
255
+ "test/scout/workflow/deployment/scheduler/test_pbs.rb",
256
+ "test/scout/workflow/deployment/scheduler/test_slurm.rb",
257
+ "test/scout/workflow/deployment/test_local.rb",
258
+ "test/scout/workflow/deployment/test_scheduler.rb",
230
259
  "test/scout/workflow/deployment/test_trace.rb",
231
260
  "test/scout/workflow/step/test_archive.rb",
232
261
  "test/scout/workflow/step/test_children.rb",
233
262
  "test/scout/workflow/step/test_dependencies.rb",
234
263
  "test/scout/workflow/step/test_info.rb",
235
264
  "test/scout/workflow/step/test_load.rb",
265
+ "test/scout/workflow/step/test_progress.rb",
236
266
  "test/scout/workflow/step/test_provenance.rb",
237
267
  "test/scout/workflow/step/test_status.rb",
238
268
  "test/scout/workflow/task/test_dependencies.rb",
@@ -252,7 +282,7 @@ Gem::Specification.new do |s|
252
282
  ]
253
283
  s.homepage = "http://github.com/mikisvaz/scout-gear".freeze
254
284
  s.licenses = ["MIT".freeze]
255
- s.rubygems_version = "3.6.7".freeze
285
+ s.rubygems_version = "3.7.0.dev".freeze
256
286
  s.summary = "basic gear for scouts".freeze
257
287
 
258
288
  s.specification_version = 4
@@ -334,7 +334,7 @@ workdir.glob("**/command.batch").sort_by{|f| File.mtime(f)}.each do |fcmd|
334
334
  step_path = step_line.split(": ").last.strip
335
335
  step = Step.new step_path
336
336
  has_bar = false
337
- (step.rec_dependencies + [step]).reverse.each do |j|
337
+ (step.rec_dependencies.to_a + [step]).reverse.each do |j|
338
338
  next if j.done?
339
339
  if j.file(:progress).exists?
340
340
  bar = Log::ProgressBar.new
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout-gear'
4
+
5
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
+
7
+ options = SOPT.setup <<EOF
8
+
9
+ Cat a file
10
+
11
+ $ #{$0} [<options>] (<resource> <path>|<path>)
12
+
13
+ -h--help Print this help
14
+ -r--requires* Files to require; 'all' for all in Scout.etc.requires
15
+ -lw--load_workflow* Files to require; 'all' for all in Scout.etc.requires
16
+ -w--where* Where to look for the path
17
+ EOF
18
+ if options[:help]
19
+ if defined? scout_usage
20
+ scout_usage
21
+ else
22
+ puts SOPT.doc
23
+ end
24
+ exit 0
25
+ end
26
+
27
+ resource, path = ARGV
28
+ path, resource = resource, nil if path.nil?
29
+
30
+ raise MissingParameterException.new(:path) if path.nil?
31
+
32
+ case options[:workflows]
33
+ when nil, false, "false", "none"
34
+ when "all"
35
+ Scout.etc.workflows.list.each do |workflow|
36
+ Workflow.require_workflow file
37
+ end if Scout.etc.workflows.exists?
38
+ else
39
+ options[:workflows].split(/[ ,;|]/).each do |workflow|
40
+ Workflow.require_workflow workflow
41
+ end
42
+ end
43
+
44
+ case options[:requires]
45
+ when nil, false, "false", "none"
46
+ when "all"
47
+ Scout.etc.requires.list.each do |file|
48
+ require file
49
+ end if Scout.etc.requires.exists?
50
+ else
51
+ options[:requires].split(/[ ,;|]/).each do |file|
52
+ require file
53
+ end
54
+ end
55
+
56
+ location = nil
57
+ where = options[:where]
58
+ all = options[:all]
59
+
60
+ begin
61
+ resource = Workflow.require_workflow resource
62
+ rescue
63
+ begin
64
+ resource = Kernel.const_get(resource)
65
+ rescue
66
+ raise "Resource not found: #{ resource }"
67
+ end
68
+ end if resource
69
+
70
+ path = (resource || Scout)[path.dup]
71
+
72
+ if where.nil? || where == 'all' || path.path_maps.include?(where.to_sym)
73
+ location = path.find(where)
74
+
75
+ if Array === location
76
+ file = location.first
77
+ puts location.first.read
78
+ puts location * "\n"
79
+ else
80
+ file = Open.exists?(location)? location : nil
81
+ end
82
+
83
+ puts file.read if file
84
+ else
85
+ raise ParameterException, "Where '#{where}' not identified. Try scout-camp if looking for a remote file"
86
+ end
data/scout_commands/doc CHANGED
@@ -26,7 +26,9 @@ end
26
26
 
27
27
  module_name = ARGV.first
28
28
  if module_name.nil?
29
- puts Scout.doc.lib.scout.glob("**/*.md").collect{|f| File.basename(f.unset_extension) } * "\n"
29
+ puts Scout.doc.lib.scout.glob("**/*.md").collect{|f|
30
+ f.find.unset_extension.sub(Scout.doc.lib.scout.find + "/", '')
31
+ } * "\n"
30
32
  else
31
33
  begin
32
34
  puts Scout.doc.lib.scout[module_name].find_with_extension('md', :lib).read
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+
5
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
+
7
+ options = SOPT.setup <<EOF
8
+
9
+ Execute an entity property
10
+
11
+ $ #{$0} [<options>] <entity_type> <property> <entity> [<entity_options>] [<property_parameters>]*
12
+
13
+ Property options are an array of strings that get passed to the property, the
14
+ remaining ARGV elements; property parameters may be optional
15
+
16
+ -h--help Print this help
17
+ -W--workflows* Workflows to load
18
+ EOF
19
+
20
+ type, property, entity = ARGV
21
+
22
+ if options[:help] and type.nil?
23
+ if defined? scout_usage
24
+ scout_usage
25
+ else
26
+ puts SOPT.doc
27
+ end
28
+ exit 0
29
+ end
30
+
31
+ raise MissingParameterException, :type if type.nil?
32
+
33
+ workflows = IndiferentHash.process_options options, :workflows, workflows: 'local'
34
+
35
+ workflows = workflows.split(",")
36
+
37
+ workflows.each do |workflow|
38
+ workflow = workflow.strip
39
+ wf = case workflow
40
+ when 'local'
41
+ [:lib, :current].each do |location|
42
+ Workflow.require_workflow Scout.root['workflow.rb'].find(location) if Scout.root['workflow.rb'].find(location).exists?
43
+ end
44
+ when 'lib'
45
+ Workflow.require_workflow Scout.root['workflow.rb'].find(:lib) if Scout.root['workflow.rb'].find(:lib).exists?
46
+ when 'current'
47
+ Workflow.require_workflow Scout.root['workflow.rb'].find(:current) if Scout.root['workflow.rb'].find(:current).exists?
48
+ else
49
+ Workflow.require_workflow workflow
50
+ end
51
+
52
+ begin
53
+ require "#{wf.to_s}/entity/#{Misc.snake_case(type)}"
54
+ rescue Exception
55
+ end
56
+
57
+ end
58
+
59
+ begin
60
+ require "entity/#{Misc.snake_case(type)}"
61
+ rescue Exception
62
+ end
63
+ entity_module = Kernel.const_get type
64
+
65
+ entity_module.annotations.uniq.each do |attr|
66
+ SOPT.register attr.slice(0,1).to_s, attr, true, "Entity attribute"
67
+ end
68
+
69
+ if options[:help] and property.nil?
70
+ if defined? scout_usage
71
+ scout_usage
72
+ else
73
+ puts SOPT.doc
74
+ end
75
+ properties = entity_module.properties
76
+
77
+ puts Log.color :title, 'Properties: '
78
+ puts properties.keys * "\n"
79
+
80
+ exit 0
81
+ end
82
+
83
+ SOPT.synopsys[' [<entity_options>]'] = ""
84
+
85
+ raise MissingParameterException, :property if property.nil?
86
+
87
+
88
+ raise ParameterException, "Property no available" unless entity_module.instance_methods.include? property.to_sym
89
+
90
+ if options[:help]
91
+ properties = entity_module.properties[property.to_sym]
92
+
93
+ property_str = properties.collect do |type, name|
94
+ if type != :opt
95
+ "[<#{name} (#{type})>]"
96
+ else
97
+ "[<#{name}>]"
98
+ end
99
+ end * " "
100
+
101
+ SOPT.synopsys['[<property_parameters>]*'] = property_str
102
+
103
+ if defined? scout_usage
104
+ scout_usage
105
+ else
106
+ puts SOPT.doc
107
+ end
108
+
109
+ exit 0
110
+ end
111
+
112
+ raise MissingParameterException, :entity if entity.nil?
113
+
114
+ entity = Entity.prepare_entity(entity, type, options)
115
+
116
+ entity_params = ARGV[3..-1]
117
+
118
+ entity_params = entity_params.collect do |param|
119
+ if Path.located?(param) && Path.can_read?(param)
120
+ Open.read(param)
121
+ else
122
+ case param
123
+ when 'true'
124
+ true
125
+ when 'false'
126
+ true
127
+ when /^-?\d+$/
128
+ param.to_i
129
+ when /^-?\d+\.\d+$/
130
+ param.to_f
131
+ else
132
+ param
133
+ end
134
+ end
135
+ end
136
+
137
+ res = entity.send(property, *entity_params)
138
+
139
+ case res
140
+ when nil
141
+ when Array
142
+ puts res * "\n"
143
+ when String
144
+ puts res unless res.empty?
145
+ when Symbol, Numeric
146
+ puts res.to_s
147
+ when Step
148
+ puts res.path
149
+ else
150
+ puts res.to_s
151
+ end