scout-gear 10.7.5 → 10.7.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60a8c5a91d83e96aaa721154fa4f7fdd63d2699c691b8c99962c6ba5561365eb
4
- data.tar.gz: 4b2303f3db25c1316286e8c6edbd8d76be66ba8b851626393f0c0b5ea34aac1d
3
+ metadata.gz: f346d283c182fbb5a090329100ad4bd32a50e7e84c058c156014ca1fd2e64772
4
+ data.tar.gz: d4457afe22a81e426232ee94ddc798921fc69dfcf35a628c8ecafa39fb3a271b
5
5
  SHA512:
6
- metadata.gz: 0eb9761f9cc9acab8842372de6bbe9f69413bc9d6b2c1b05ebae6c51e40ca292fbce9edce27d1c5d26a7e298273e700881bdd39f8bac3441b1e9af604c443eb0
7
- data.tar.gz: cb46e73a548bca55f41e088167eff7494691a6fdd61ed17f7a06f6a1a0257679441b7d62a56e67a376943e4e0a96acd39d3a4ee5888550c1721c5d79e4f7e6a4
6
+ metadata.gz: 27ac7e8599c5caabad5d63282c2f316404bce25d82dc0cb302acbb249c1ddb76eff171044b0f9c766e05ee582f399f4ba27076c6514bb3abab16857f11974846
7
+ data.tar.gz: 475df8c7b163a30dd09d608119633443c8bfc9eec1f6bcc657e3f2116bf23a678e18f3224f8da399c6923ac222f5cc1b953dd4035f44514bff90d1ee2b1ffcb7
data/.vimproject CHANGED
@@ -10,6 +10,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
10
10
  exceptions.rb
11
11
  export.rb
12
12
  definition.rb
13
+ persist.rb
13
14
  documentation.rb
14
15
  usage.rb
15
16
  util.rb
@@ -36,6 +37,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
36
37
  }
37
38
  deployment.rb
38
39
  deployment=deployment{
40
+ queue.rb
39
41
  trace.rb
40
42
  orchestrator.rb
41
43
  }
@@ -123,6 +125,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
123
125
  traverse.rb
124
126
  enrichment.rb
125
127
  list.rb
128
+ description.rb
126
129
  }
127
130
  semaphore.rb
128
131
  }
@@ -157,6 +160,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
157
160
  install
158
161
  trace
159
162
  prov
163
+ queue
164
+ process
165
+ cmd
160
166
  }
161
167
  batch=batch{
162
168
  list
@@ -172,6 +178,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
172
178
  test_scout.rb
173
179
  data=data filter="*"{
174
180
  person=person{
181
+ README.md
175
182
  brothers
176
183
  identifiers
177
184
  marriages
data/VERSION CHANGED
@@ -1 +1 @@
1
- 10.7.5
1
+ 10.7.6
@@ -1,7 +1,7 @@
1
1
  require 'scout/annotation'
2
2
  module Association
3
3
 
4
- def self.index(file, source: nil, target: nil, source_format: nil, target_format: nil, format: nil, **kwargs)
4
+ def self.index(file, source: nil, target: nil, source_format: nil, target_format: nil, format: nil, database: nil, **kwargs)
5
5
  IndiferentHash.setup(kwargs)
6
6
  source = kwargs.delete :source if kwargs.include?(:source)
7
7
  target = kwargs.delete :target if kwargs.include?(:target)
@@ -14,7 +14,7 @@ module Association
14
14
  index = Persist.tsv(file, kwargs, engine: "BDB", persist_options: index_persist_options) do |data|
15
15
  recycle, undirected = IndiferentHash.process_options kwargs, :recycle, :undirected
16
16
 
17
- database = Association.open(file, source: source, target: target, source_format: source_format, target_format: target_format, **kwargs.merge(persist_prefix: "Association::Database"))
17
+ database ||= Association.open(file, source: source, target: target, source_format: source_format, target_format: target_format, **kwargs.merge(persist_prefix: "Association::Database"))
18
18
 
19
19
  source_field = database.key_field
20
20
  target_field, *fields = database.fields
@@ -0,0 +1,108 @@
1
+ class KnowledgeBase
2
+ def self.doc_parse_up_to(str, pattern, keep = false)
3
+ pre, _pat, _post = str.partition pattern
4
+ if _pat
5
+ [pre, (keep ? _pat << _post : _post)]
6
+ else
7
+ _post
8
+ end
9
+ end
10
+
11
+ def self.doc_parse_chunks(str, pattern)
12
+ parts = str.split(pattern)
13
+ return {} if parts.length < 2
14
+ databases = Hash[*parts[1..-1].collect{|v| v.strip }]
15
+ databases.delete_if{|t,d| d.empty?}
16
+ databases.transform_keys!(&:downcase)
17
+ databases
18
+ end
19
+
20
+ def self.parse_knowledge_base_doc(doc)
21
+ description, db_description = doc_parse_up_to doc, /^#/, true
22
+ databases = doc_parse_chunks db_description, /^# (.*)/
23
+ IndiferentHash.setup({:description => description.strip, :databases => databases})
24
+ end
25
+
26
+ def documentation_markdown
27
+ return "" if @libdir.nil?
28
+ file = @libdir['README.md'].find unless file.exists?
29
+ if file.exists?
30
+ file.read
31
+ else
32
+ ""
33
+ end
34
+ end
35
+
36
+ def database_description_file(name)
37
+ dir[name.to_s + '.md']
38
+ end
39
+
40
+ def knowledge_base_description_file(name)
41
+ file = dir['README.md']
42
+ return file if file.exists?
43
+
44
+ file, options = registry[name]
45
+ file = Path.setup(file.dup) unless file.nil? or Path === file
46
+ source_readme = file.dirname['README.md'] if file
47
+ return source_readme if source_readme && source_readme.exists?
48
+ end
49
+
50
+ def description(name)
51
+ return registered_options(name)[:description] if registered_options(name)[:description]
52
+
53
+ return database_description_file(name).read if database_description_file(name).exist?
54
+
55
+ if knowledge_base_description_file(name)
56
+ KnowledgeBase.parse_knowledge_base_doc(knowledge_base_description_file(name).read)[:databases][name.to_s.downcase]
57
+ end
58
+ end
59
+
60
+ def markdown(name)
61
+ description = description(name)
62
+ source_type = source_type(name)
63
+ target_type = target_type(name)
64
+
65
+ full_description = []
66
+ empty_line = ''
67
+ full_description << ("# " << Misc.humanize(name))
68
+ full_description << empty_line
69
+
70
+ source_formats = begin
71
+ source_index(name).key_field.split(',')
72
+ rescue
73
+ []
74
+ end
75
+
76
+ target_formats = begin
77
+ target_index(name).key_field.split(',')
78
+ rescue
79
+ []
80
+ end
81
+
82
+ if source_type
83
+ full_description << "Source: #{source_type} - #{source(name)}"
84
+ else
85
+ full_description << "Source: #{source(name)}"
86
+ end
87
+ #full_description.last << ". Accepted formats: #{source_formats*", "}" if source_formats.any?
88
+
89
+ if target_type
90
+ full_description << "Target: #{target_type} - #{target(name)}"
91
+ else
92
+ full_description << "Target: #{target(name)}"
93
+ end
94
+ #full_description.last << ". Accepted formats: #{target_formats*", "}" if target_formats.any?
95
+
96
+ if undirected?(name)
97
+ full_description << "Undirected database, source and target can be reversed."
98
+ end
99
+
100
+ if description
101
+ full_description << empty_line
102
+ full_description << description
103
+ full_description << empty_line
104
+ end
105
+
106
+ full_description * "\n"
107
+ end
108
+ end
@@ -80,6 +80,7 @@ class KnowledgeBase
80
80
  end
81
81
  identifier_files.concat Entity.identifier_files(source(name)) if defined? Entity
82
82
  identifier_files.uniq!
83
+ identifier_files.collect!{|f| (Path === f) ? f : Path.setup(f.dup) }
83
84
  identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if namespace
84
85
  identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, db_namespace(name)))} if not namespace and db_namespace(name)
85
86
  identifier_files.reject!{|f| f.match(/\bNAMESPACE\b/)}
@@ -89,7 +90,11 @@ class KnowledgeBase
89
90
 
90
91
  def target_index(name)
91
92
  Persist.memory("Target index #{name}: KB directory #{dir}") do
92
- identifier_files = identifier_files(name)
93
+ if @identifier_files && @identifier_files.any?
94
+ identifier_files = @identifier_files
95
+ else
96
+ identifier_files = database_identifier_files(name)
97
+ end
93
98
  identifier_files.concat Entity.identifier_files(target(name)) if defined? Entity
94
99
  identifier_files.uniq!
95
100
  identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if self.namespace
@@ -15,9 +15,29 @@ class KnowledgeBase
15
15
  end
16
16
  end
17
17
 
18
+ def present_databases
19
+ dir.glob("*.database").collect{|file| File.basename(file, '.database')}
20
+ end
21
+
18
22
  def all_databases
19
23
  return [] unless @registry
20
- @registry.keys
24
+ (@registry.keys + present_databases).uniq
25
+ end
26
+
27
+ def database_file(name)
28
+ if @registry[name].nil?
29
+ nil
30
+ else
31
+ @registry[name].first
32
+ end
33
+ end
34
+
35
+ def registered_options(name)
36
+ if @registry[name].nil?
37
+ IndiferentHash.setup({})
38
+ else
39
+ IndiferentHash.setup(@registry[name].last)
40
+ end
21
41
  end
22
42
 
23
43
  def include?(name)
@@ -29,21 +49,21 @@ class KnowledgeBase
29
49
  @fields[name] ||= get_index(name).fields
30
50
  end
31
51
 
32
- def description(name)
33
- @descriptions ||= {}
34
- @descriptions[name] ||= get_index(name).key_field.split("~")
52
+ def pair(name)
53
+ @pairs ||= {}
54
+ @pairs[name] ||= get_index(name).key_field.split("~")
35
55
  end
36
56
 
37
57
  def source(name)
38
- description(name)[0]
58
+ pair(name)[0]
39
59
  end
40
60
 
41
61
  def target(name)
42
- description(name)[1]
62
+ pair(name)[1]
43
63
  end
44
64
 
45
65
  def undirected(name)
46
- description(name).length == 3
66
+ pair(name).length == 3
47
67
  end
48
68
 
49
69
  alias undirected? undirected
@@ -69,7 +89,12 @@ class KnowledgeBase
69
89
 
70
90
  persist_dir = dir
71
91
  persist_path = persist_dir[key].find
72
- file, registered_options = registry[name]
92
+
93
+ file = database_file(name)
94
+ registered_options = registered_options(name)
95
+ registered_options = IndiferentHash.setup(registered_options).except(:description)
96
+
97
+ registered_options = IndiferentHash.add_defaults registered_options, identifiers: self.identifier_files if registered_options
73
98
 
74
99
  options = IndiferentHash.add_defaults options, registered_options if registered_options and registered_options.any?
75
100
  options = IndiferentHash.add_defaults options, :persist_path => persist_path, :persist_dir => persist_dir, :persist => true
@@ -89,11 +114,11 @@ class KnowledgeBase
89
114
  Log.low "Re-opening index #{ name } from #{ Log.fingerprint persist_path }. #{options}"
90
115
  Association.index(file, **options, persist_options: persist_options.dup)
91
116
  else
92
- options = IndiferentHash.add_defaults options, registered_options if registered_options
93
- raise "Repo #{ name } not found and not registered" if file.nil?
94
- Log.medium "Opening index #{ name } from #{ Log.fingerprint file }. #{options}"
117
+ database = get_database name if file.nil?
95
118
  file = file.call if Proc === file
96
- Association.index(file, **options, persist_options: persist_options.dup)
119
+ Log.medium "Opening index #{ name } from #{ Log.fingerprint database }. #{options}"
120
+ options = IndiferentHash.add_defaults options, registered_options if registered_options
121
+ Association.index(file, **options, persist_options: persist_options.dup, database: database)
97
122
  end
98
123
 
99
124
  index.namespace = self.namespace unless self.namespace
@@ -128,7 +153,12 @@ class KnowledgeBase
128
153
 
129
154
  persist_dir = dir
130
155
  persist_path = persist_dir[key].find
131
- file, registered_options = registry[name]
156
+
157
+ file = database_file(name)
158
+ registered_options = registered_options(name)
159
+ registered_options = IndiferentHash.setup(registered_options).except(:description)
160
+
161
+ registered_options = IndiferentHash.add_defaults registered_options, identifiers: self.identifier_files if registered_options
132
162
 
133
163
  options = IndiferentHash.add_defaults options, registered_options if registered_options and registered_options.any?
134
164
  options = IndiferentHash.add_defaults options, :persist_path => persist_path, :persist => true
@@ -145,7 +175,6 @@ class KnowledgeBase
145
175
 
146
176
  database = if persist_path.exists? and persist_options[:persist] and not persist_options[:update]
147
177
  Log.low "Re-opening database #{ name } from #{ Log.fingerprint persist_path }. #{options}"
148
- #Association.database(file, **options, persist_options: persist_options)
149
178
  Association.database(file, **options.merge(persist_options: persist_options))
150
179
  else
151
180
  options = IndiferentHash.add_defaults options, registered_options if registered_options
@@ -153,7 +182,6 @@ class KnowledgeBase
153
182
  raise "Repo #{ name } not found and not registered" if file.nil?
154
183
  Log.medium "Opening database #{ name } from #{ Log.fingerprint file }. #{options}"
155
184
  file = file.call if Proc === file
156
- #Association.database(file, **options, persist_options: persist_options)
157
185
  Association.database(file, **options.merge(persist_options: persist_options))
158
186
  end
159
187
 
@@ -5,6 +5,7 @@ require_relative 'knowledge_base/entity'
5
5
  require_relative 'knowledge_base/query'
6
6
  require_relative 'knowledge_base/traverse'
7
7
  require_relative 'knowledge_base/list'
8
+ require_relative 'knowledge_base/description'
8
9
  #require 'scout/knowledge_base/query'
9
10
  #require 'scout/knowledge_base/syndicate'
10
11
 
@@ -23,12 +24,12 @@ class KnowledgeBase
23
24
  @entity_options ||= IndiferentHash.setup({})
24
25
 
25
26
  @format ||= IndiferentHash.setup({})
26
- @descriptions ||= IndiferentHash.setup({})
27
+ pairs ||= IndiferentHash.setup({})
27
28
  @indices ||= IndiferentHash.setup({})
28
29
  end
29
30
 
30
31
  def config_file(name)
31
- @dir.config[name.to_s]
32
+ @dir['config'][name.to_s]
32
33
  end
33
34
 
34
35
  def save_variable(name)
@@ -58,6 +58,7 @@ module TSV
58
58
  #next if Path === file && ! Open.exist?(file)
59
59
  begin
60
60
  file = file.produce if Path === file
61
+ raise "Could no produce file" if FalseClass === file
61
62
  rescue
62
63
  Log.warn $!.message
63
64
  next
@@ -153,6 +153,14 @@ module Open
153
153
  end
154
154
  obj.close
155
155
  obj.join if obj.respond_to? :join
156
+ elsif options[:type] == :matrix
157
+ Log.low "Traverse stream by lines #{Log.fingerprint obj}"
158
+ parser = options[:sep].nil? ? TSV::Parser.new(obj) : TSV::Parser.new(obj, sep: options[:sep])
159
+ parser.traverse **options do |parts|
160
+ res = block.call parts
161
+ callback.call res if callback
162
+ nil
163
+ end
156
164
  else
157
165
  Log.low "Traverse stream with parser #{Log.fingerprint obj}"
158
166
  parser = options[:sep].nil? ? TSV::Parser.new(obj) : TSV::Parser.new(obj, sep: options[:sep])
@@ -31,6 +31,12 @@ module TSV
31
31
 
32
32
  return nil if select && ! TSV.select(items[0], items[1..-1], select, fields: field_names, type: type, sep: sep2)
33
33
 
34
+ if String === key
35
+ raise "Key by name, but no field names" if field_names.nil?
36
+ key = field_names.index key
37
+ raise "Key #{key} not found in field names #{Log.fingerprint field_names}" if key.nil?
38
+ end
39
+
34
40
  if positions.nil? && key == 0
35
41
  key = items.shift
36
42
  elsif positions.nil?
@@ -65,7 +71,7 @@ module TSV
65
71
  [key, items]
66
72
  end
67
73
 
68
- def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, field_names: nil, head: nil, **kwargs, &block)
74
+ def self.parse_stream(stream, data: nil, source_type: nil, sep: "\t", type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, field_names: nil, head: nil, **kwargs, &block)
69
75
  begin
70
76
  bar = "Parsing #{Log.fingerprint stream}" if TrueClass === bar
71
77
  bar = Log::ProgressBar.get_obj_bar(stream, bar) if bar
@@ -81,7 +87,7 @@ module TSV
81
87
  data.serializer.to_s.include?("String") &&
82
88
  same_type &&
83
89
  ! (head || kwargs[:cast] || kwargs[:positions] || (kwargs[:key] && kwargs[:key] != 0) || Proc === fix ) &&
84
- (kwargs[:sep].nil? || kwargs[:sep] == "\t")
90
+ (sep.nil? || sep == "\t")
85
91
 
86
92
 
87
93
  Log.debug "Loading #{Log.fingerprint stream} directly into #{Log.fingerprint data}"
@@ -114,12 +120,17 @@ module TSV
114
120
  line = Misc.fixutf8(line)
115
121
  end
116
122
  bar.tick if bar
123
+
117
124
  if type == :array || type == :line
118
125
  block.call line
119
126
  next
127
+ elsif type == :matrix
128
+ parts = line.split(sep)
129
+ block.call parts
130
+ next
120
131
  end
121
132
 
122
- key, items = parse_line(line, type: source_type, field_names: field_names, **kwargs)
133
+ key, items = parse_line(line, type: source_type, field_names: field_names, sep: sep, **kwargs)
123
134
 
124
135
  next if key.nil?
125
136
 
@@ -1,6 +1,8 @@
1
1
  module Workflow
2
2
  class Orchestrator
3
3
 
4
+ class NoWork < Exception; end
5
+
4
6
  def self.job_workload(job)
5
7
  workload = {job => []}
6
8
  return workload if job.done? && job.updated?
@@ -202,7 +204,7 @@ module Workflow
202
204
 
203
205
  candidates = resources_used.keys + Orchestrator.candidates(workload, rules)
204
206
  candidates.uniq!
205
- raise "No candidates and no running jobs" if candidates.empty?
207
+ raise NoWork, "No candidates and no running jobs" if candidates.empty?
206
208
 
207
209
  candidates.each do |job|
208
210
  case
@@ -272,4 +274,10 @@ module Workflow
272
274
  orchestrator.process({}, produce_list)
273
275
  produce_list
274
276
  end
277
+
278
+ def self.produce(jobs, produce_cpus: Etc.nprocessors, produce_timer: 5)
279
+ jobs = [jobs] unless Array === jobs
280
+ orchestrator = Orchestrator.new produce_timer.to_i, cpus: produce_cpus.to_i
281
+ orchestrator.process({}, jobs)
282
+ end
275
283
  end
@@ -0,0 +1,26 @@
1
+ module Workflow
2
+ def self.name2clean_name(name)
3
+ name.reverse.partition("_").last.reverse
4
+ end
5
+
6
+ def self.queue_job(file)
7
+ workflow, task, name = file.split("/").values_at(-3, -2, -1) if file
8
+ workflow = Workflow.require_workflow workflow
9
+
10
+ if Open.directory?(file)
11
+ clean_name = name2clean_name name
12
+ inputs = workflow.tasks[task].load_inputs(file)
13
+ workflow.job(task, clean_name, inputs)
14
+ else
15
+ workflow.job(task, name)
16
+ end
17
+ end
18
+
19
+ def self.unqueue(file, &block)
20
+ Open.lock file do
21
+ job = queue_job(file)
22
+ puts job.run
23
+ Open.rm_rf file
24
+ end
25
+ end
26
+ end
@@ -18,6 +18,12 @@ module Workflow
18
18
  @exec_exports ||= []
19
19
  end
20
20
 
21
+ def clear_exports
22
+ asynchronous_exports.clear
23
+ synchronous_exports.clear
24
+ exec_exports.clear
25
+ stream_exports.clear
26
+ end
21
27
 
22
28
  def all_exports
23
29
  asynchronous_exports + synchronous_exports + exec_exports + stream_exports
@@ -0,0 +1,6 @@
1
+ module Workflow
2
+ def persist(name, type = :serializer, options = {}, &block)
3
+ options = IndiferentHash.add_defaults options, dir: Scout.var.workflows[self.name].persist
4
+ Persist.persist(name, type, options, &block)
5
+ end
6
+ end
@@ -1,3 +1,4 @@
1
+ require 'time'
1
2
  require 'scout/config'
2
3
  class Step
3
4
  SERIALIZER = Scout::Config.get(:serializer, :step_info, :info, :step, env: "SCOUT_SERIALIZER", default: :json)
@@ -1,5 +1,15 @@
1
1
  class Step
2
2
  def save_inputs(inputs_dir)
3
- self.task.save_inputs(inputs_dir, provided_inputs)
3
+ if clean_name != name
4
+ hash = name[clean_name.length..-1]
5
+ inputs_dir += hash
6
+ Log.medium "Saving job inputs to: #{Log.fingerprint inputs_dir}"
7
+ self.task.save_inputs(inputs_dir, provided_inputs)
8
+ inputs_dir
9
+ else
10
+ Log.medium "Saving no input job: #{Log.fingerprint inputs_dir}"
11
+ Open.touch(inputs_dir)
12
+ inputs_dir
13
+ end
4
14
  end
5
15
  end
@@ -34,6 +34,7 @@ module Task
34
34
  def job(id = nil, provided_inputs = nil)
35
35
 
36
36
  if Hash === provided_inputs
37
+ IndiferentHash.setup provided_inputs
37
38
  memory_inputs = provided_inputs.values_at *self.recursive_inputs.collect{|t| t.first }.uniq
38
39
  memory_inputs += provided_inputs.select{|k,v| k.to_s.include?("#") }.collect{|p| p * "=" }
39
40
  memory_inputs << provided_inputs[:load_inputs]
@@ -41,7 +42,7 @@ module Task
41
42
  memory_inputs = provided_inputs
42
43
  end
43
44
 
44
- Persist.memory("Task job #{self.name} #{id}", other_options: {task: self, id: id, provided_inputs: memory_inputs}) do
45
+ Persist.memory("Task job #{self.name}", repo: Workflow.job_cache, other: {task: self.name, id: id, provided_inputs: memory_inputs}) do
45
46
  provided_inputs, id = id, nil if (provided_inputs.nil? || provided_inputs.empty?) && (Hash === id || Array === id)
46
47
  provided_inputs = {} if provided_inputs.nil?
47
48
  IndiferentHash.setup(provided_inputs)
@@ -9,13 +9,19 @@ require_relative 'workflow/exceptions'
9
9
  require_relative 'workflow/path'
10
10
  require_relative 'workflow/entity'
11
11
  require_relative 'workflow/export'
12
+ require_relative 'workflow/persist'
12
13
 
13
14
  require 'scout/resource'
14
15
  require 'scout/resource/scout'
15
16
 
16
17
  module Workflow
17
18
  class << self
18
- attr_accessor :workflows, :main, :workflow_dir, :autoinstall, :workflow_repo
19
+ attr_accessor :workflows, :main, :workflow_dir, :autoinstall, :workflow_repo, :job_cache
20
+
21
+ def job_cache
22
+ @job_cache ||={}
23
+ end
24
+
19
25
  def workflows
20
26
  @workflows ||= []
21
27
  end
data/scout-gear.gemspec CHANGED
@@ -2,16 +2,16 @@
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.7.5 ruby lib
5
+ # stub: scout-gear 10.7.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-gear".freeze
9
- s.version = "10.7.5".freeze
9
+ s.version = "10.7.6".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]
13
13
  s.authors = ["Miguel Vazquez".freeze]
14
- s.date = "2025-03-19"
14
+ s.date = "2025-04-08"
15
15
  s.description = "Scout gear: workflow, TSVs, persistence, entities, associations, and knowledge_bases.".freeze
16
16
  s.email = "mikisvaz@gmail.com".freeze
17
17
  s.executables = ["scout".freeze]
@@ -45,6 +45,7 @@ Gem::Specification.new do |s|
45
45
  "lib/scout/entity/object.rb",
46
46
  "lib/scout/entity/property.rb",
47
47
  "lib/scout/knowledge_base.rb",
48
+ "lib/scout/knowledge_base/description.rb",
48
49
  "lib/scout/knowledge_base/enrichment.rb",
49
50
  "lib/scout/knowledge_base/entity.rb",
50
51
  "lib/scout/knowledge_base/list.rb",
@@ -98,12 +99,14 @@ Gem::Specification.new do |s|
98
99
  "lib/scout/workflow/definition.rb",
99
100
  "lib/scout/workflow/deployment.rb",
100
101
  "lib/scout/workflow/deployment/orchestrator.rb",
102
+ "lib/scout/workflow/deployment/queue.rb",
101
103
  "lib/scout/workflow/deployment/trace.rb",
102
104
  "lib/scout/workflow/documentation.rb",
103
105
  "lib/scout/workflow/entity.rb",
104
106
  "lib/scout/workflow/exceptions.rb",
105
107
  "lib/scout/workflow/export.rb",
106
108
  "lib/scout/workflow/path.rb",
109
+ "lib/scout/workflow/persist.rb",
107
110
  "lib/scout/workflow/step.rb",
108
111
  "lib/scout/workflow/step/archive.rb",
109
112
  "lib/scout/workflow/step/children.rb",
@@ -142,9 +145,11 @@ Gem::Specification.new do |s|
142
145
  "scout_commands/resource/produce",
143
146
  "scout_commands/template",
144
147
  "scout_commands/update",
148
+ "scout_commands/workflow/cmd",
145
149
  "scout_commands/workflow/info",
146
150
  "scout_commands/workflow/install",
147
151
  "scout_commands/workflow/list",
152
+ "scout_commands/workflow/process",
148
153
  "scout_commands/workflow/prov",
149
154
  "scout_commands/workflow/task",
150
155
  "scout_commands/workflow/trace",
@@ -154,6 +159,7 @@ Gem::Specification.new do |s|
154
159
  "share/software/install_helpers",
155
160
  "share/templates/command",
156
161
  "share/templates/workflow.rb",
162
+ "test/data/person/README.md",
157
163
  "test/data/person/brothers",
158
164
  "test/data/person/identifiers",
159
165
  "test/data/person/marriages",
@@ -166,6 +172,7 @@ Gem::Specification.new do |s|
166
172
  "test/scout/entity/test_named_array.rb",
167
173
  "test/scout/entity/test_object.rb",
168
174
  "test/scout/entity/test_property.rb",
175
+ "test/scout/knowledge_base/test_description.rb",
169
176
  "test/scout/knowledge_base/test_enrichment.rb",
170
177
  "test/scout/knowledge_base/test_entity.rb",
171
178
  "test/scout/knowledge_base/test_list.rb",
@@ -12,6 +12,7 @@ Configure a knowlege base
12
12
  $ #{$0} [<options>] <name> [knowledge_base]
13
13
 
14
14
  -h--help Print this help
15
+ -kb--knowledge_base* Knowlege base name (or :default)
15
16
  -i--identifier_files* Identifier files separated by ','
16
17
  -n--namespace* Namespace
17
18
  EOF
@@ -26,8 +27,10 @@ end
26
27
 
27
28
  knowledge_base_name = ARGV.first
28
29
 
30
+ knowledge_base_name ||= options[:knowledge_base] || :default
29
31
  knowledge_base = KnowledgeBase.load knowledge_base_name || :default
30
32
 
31
33
  knowledge_base.namespace = options[:namespace] if options.include? :namespace
32
34
  knowledge_base.identifier_files += options[:identifier_files].split(",") if options.include? :identifier_files
35
+ knowledge_base.identifier_files.uniq!
33
36
  knowledge_base.save
@@ -12,6 +12,7 @@ Description of the tool
12
12
  $ #{$0} [<options>] <filename> [<other|->]*
13
13
 
14
14
  -h--help Print this help
15
+ -kb--knowledge_base* Knowlege base name (or :default)
15
16
  EOF
16
17
  if options[:help]
17
18
  if defined? scout_usage
@@ -34,7 +34,8 @@ raise MissingParameterException, :name if name.nil?
34
34
  raise MissingParameterException, :entity if entity.nil?
35
35
 
36
36
 
37
- knowledge_base = KnowledgeBase.load options[:knowledge_base] || :default
37
+ knowledge_base = IndiferentHash.process_options options, :knowledge_base
38
+ knowledge_base = KnowledgeBase.load knowledge_base || :default
38
39
 
39
40
  list = IndiferentHash.process_options options, :list
40
41
 
@@ -19,6 +19,7 @@ $ #{$0} [<options>] <name> <filename>
19
19
  -n--namespace* Namespace
20
20
  -i--identifiers* Identifiers
21
21
  -u--undirected
22
+ -d--description* Database description
22
23
  EOF
23
24
  if options.delete :help
24
25
  if defined? scout_usage
@@ -35,7 +36,8 @@ name, file = ARGV
35
36
  raise MissingParameterException, :name if name.nil?
36
37
  raise MissingParameterException, :file if file.nil?
37
38
 
38
- knowledge_base = KnowledgeBase.load options[:knowledge_base] || :default
39
+ knowledge_base = IndiferentHash.process_options options, :knowledge_base
40
+ knowledge_base = KnowledgeBase.load knowledge_base || :default
39
41
 
40
42
  options[:fields] = options[:fields].split(/,\s*/) if options[:fields]
41
43
  file = Scout.identify(File.expand_path(file))
@@ -23,7 +23,8 @@ if options[:help]
23
23
  exit 0
24
24
  end
25
25
 
26
- knowledge_base = KnowledgeBase.load options[:knowledge_base] || :default
26
+ knowledge_base = IndiferentHash.process_options options, :knowledge_base
27
+ knowledge_base = KnowledgeBase.load knowledge_base || :default
27
28
 
28
29
  name = ARGV.first
29
30
 
@@ -31,7 +32,8 @@ if name.nil?
31
32
  puts knowledge_base.all_databases * "\n"
32
33
  else
33
34
 
34
- raise ParameterException "Database #{name} not found Options: #{Log.fingerprint knowledge_base.all_databases}" unless knowledge_base.include? name
35
+ raise ParameterException, "Database #{name} not found Options: #{Log.fingerprint knowledge_base.all_databases}" unless knowledge_base.include? name
35
36
 
37
+ puts knowledge_base.markdown(name)
36
38
  Log.tsv knowledge_base.get_database(name, options)
37
39
  end
@@ -0,0 +1,116 @@
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
+ Run a workflow command
10
+
11
+ $ #{$0} <workflow> <command> [<subcommands>] [<options>] [<arg> ...]
12
+
13
+ -h--help Print this help
14
+ EOF
15
+ if options[:help]
16
+ if defined? scout_usage
17
+ scout_usage
18
+ else
19
+ puts SOPT.doc
20
+ end
21
+ exit 0
22
+ end
23
+
24
+ workflow = ARGV.shift
25
+
26
+ if workflow == '-h'
27
+ if defined? scout_usage
28
+ scout_usage
29
+ else
30
+ puts SOPT.doc
31
+ end
32
+ exit 0
33
+ end
34
+
35
+ raise ParameterException, "No workflow specified" if workflow.nil?
36
+
37
+ require 'scout/workflow'
38
+
39
+ wf = Workflow.require_workflow workflow
40
+ dir = $command_dir = wf.libdir.share.scout_commands.find
41
+
42
+ def prev_dir(prev)
43
+ scout_command_dir = $command_dir
44
+
45
+ prev.each do |previous_command|
46
+ scout_command_dir = scout_command_dir[previous_command]
47
+ end
48
+
49
+ scout_command_dir
50
+ end
51
+
52
+ def commands(prev)
53
+ scout_command_dir = prev_dir(prev)
54
+
55
+ command_file_dirs = scout_command_dir.find_all
56
+ command_files = command_file_dirs.collect{|d| d.glob('*') }.flatten
57
+ command_files.collect{|p| File.basename(p) }.uniq.reject{|p| p =~ /\.desc$/}.sort
58
+ end
59
+
60
+
61
+ prev = []
62
+
63
+ $previous_commands << ' cmd'
64
+ $previous_commands << ' ' << workflow
65
+
66
+ begin
67
+ while ARGV.any?
68
+ command = ARGV.shift
69
+ case
70
+ when File.directory?(dir[command].find)
71
+ prev << command
72
+ $previous_commands << command
73
+ dir = dir[command]
74
+ when File.directory?(dir[command].find)
75
+ prev << command
76
+ dir = dir[command]
77
+ when dir[command].exists?
78
+ load dir[command].find
79
+ exit 0
80
+ else
81
+ if command == 'bootstrap'
82
+ if wf.libdir["test_workflow.rb"].exists?
83
+ Log.info "No bootstrap for #{ workflow }, running test_workflow.rb instead"
84
+ CMD.cmd_log('ruby', wf.libdir["test_workflow.rb"].find)
85
+ else
86
+ Log.info "No bootstrap for #{ workflow }, running examples instead"
87
+ CMD.cmd_log("scout workflow example #{ workflow }")
88
+ exit 0
89
+ end
90
+ end
91
+
92
+ raise ParameterException, "Error: Command not understood: #{command}"
93
+ end
94
+ end
95
+ end
96
+
97
+ puts SOPT.doc
98
+ puts
99
+ puts Log.color :magenta, "## COMMANDS"
100
+ puts
101
+ puts Log.color :magenta, "Command:"
102
+ puts
103
+ puts " scout #{$previous_commands * " "} "
104
+ puts
105
+ puts Log.color :magenta, "Subcommands:"
106
+ puts
107
+
108
+ commands(prev).each do |command|
109
+ directory = File.directory? dir[command].find
110
+ if directory
111
+ puts " " << Log.color(:blue, command)
112
+ else
113
+ puts " " << command
114
+ end
115
+ end
116
+
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+ require 'scout/workflow/deployment/queue'
5
+ require 'scout/workflow/deployment/orchestrator'
6
+
7
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
8
+
9
+ options = SOPT.setup <<EOF
10
+
11
+ Process the queue
12
+
13
+ $ #{$0} [<options>] ([<workflow>] [<task>] [<name>] | <filename>)
14
+
15
+ -h--help Print this help
16
+ -l--list List queue jobs
17
+ --continuous Process continuously
18
+ --produce_timer* Produce timer for sleeping
19
+ --produce_cpus* Cpus to use concurrently producing jobs
20
+ EOF
21
+ if options[:help]
22
+ if defined? scout_usage
23
+ scout_usage
24
+ else
25
+ puts SOPT.doc
26
+ end
27
+ exit 0
28
+ end
29
+ list, continuous = IndiferentHash.process_options options, :list, :continuous
30
+
31
+ queue_dir = Scout.var.queue
32
+
33
+ class TrayAgain < Exception; end
34
+
35
+ begin
36
+ if ARGV.empty?
37
+ files = queue_dir.glob("*/*/*")
38
+ if list
39
+ puts files * "\n"
40
+ exit
41
+ end
42
+ else
43
+ workflow, task, name = ARGV
44
+
45
+ # First deal with fixed files
46
+ if task.nil?
47
+ if Open.exists?(workflow)
48
+ Workflow.unqueue files.first
49
+ exit
50
+
51
+ else
52
+ files = queue_dir.glob("#{workflow}/*/*")
53
+ end
54
+ elsif name.nil?
55
+ files = queue_dir.glob("#{workflow}/#{task}/*")
56
+ else
57
+ files = queue_dir.glob("#{workflow}/#{task}/#{name}*")
58
+ end
59
+ end
60
+
61
+ jobs = files.collect{|file| Workflow.queue_job(file) }
62
+ begin
63
+ options.keys.each do |key|
64
+ options[key.to_sym] = options.delete(key)
65
+ end
66
+ Workflow.produce(jobs, **options)
67
+ rescue Workflow::Orchestrator::NoWork
68
+ end
69
+
70
+ files.each do |f| Open.rm_rf f end
71
+
72
+ Workflow.job_cache.clear
73
+
74
+ if continuous
75
+ Log.debug "Continuous processing"
76
+ sleep 1
77
+ raise Workflow::Orchestrator::NoWork
78
+ end
79
+ rescue Workflow::Orchestrator::NoWork
80
+ retry
81
+ end
82
+
@@ -20,8 +20,9 @@ $ #{$0} [<options>] <workflow> <task>
20
20
  --update Update jobs with newer dependencies
21
21
  --deploy* Deploy mode: serial, local, or SLURM (default 'serial')
22
22
  --fork Fork and return path
23
+ --load_inputs* Directory or file with inputs files to load
24
+ --save_inputs* Directory or tar.gz file path to store inputs
23
25
  -jn--jobname* Name to use as job identifier
24
- -li--load_inputs* Directory with inputs files to load
25
26
  -pf--printpath Print the file path
26
27
  -prov--provenance Print the step provenance
27
28
  -cl--clean Clean the last step
@@ -40,8 +41,8 @@ task = workflow.tasks[task_name.to_sym] if task_name
40
41
 
41
42
  options[:help] = true if task.nil?
42
43
 
43
- help, provenance, clean, recursive_clean, clean_task, load_inputs, jobname, printpath, deploy, override_deps, do_fork = IndiferentHash.process_options options,
44
- :help, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :jobname, :printpath, :deploy, :override_deps, :fork,
44
+ help, provenance, clean, recursive_clean, clean_task, load_inputs, save_inputs, jobname, printpath, deploy, override_deps, do_fork = IndiferentHash.process_options options,
45
+ :help, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :save_inputs, :jobname, :printpath, :deploy, :override_deps, :fork,
45
46
  :deploy => 'serial'
46
47
 
47
48
  if help
@@ -93,12 +94,23 @@ end
93
94
 
94
95
  if provenance
95
96
  puts Step.prov_report(job)
97
+
96
98
  elsif do_fork
97
99
  job.fork
98
100
  puts job.path
99
101
  exit 0
102
+ elsif save_inputs
103
+ puts job.save_inputs(save_inputs)
104
+ exit 0
100
105
  else
106
+
101
107
  case deploy
108
+ when "queue"
109
+ if ! job.done?
110
+ save_inputs = Scout.var.queue[workflow.to_s][task_name][job.clean_name].find
111
+ puts job.save_inputs(save_inputs)
112
+ exit
113
+ end
102
114
  when "serial"
103
115
  job.run(true)
104
116
  when "local"
@@ -0,0 +1,17 @@
1
+ Databases describing people and their relationships.
2
+
3
+ # Brothers
4
+
5
+ Sibling relationships. The first of the pair is the Older
6
+
7
+ # Marriages
8
+
9
+ Marriages between people.
10
+
11
+ Date: Date when the marriage occurred
12
+
13
+ # Parents
14
+
15
+ List parents.
16
+
17
+ Type of parent: father or mother
@@ -0,0 +1,59 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ require 'scout/knowledge_base'
5
+ class TestKnowledgebaseDesc < Test::Unit::TestCase
6
+ def test_brothers_registry
7
+ TmpFile.with_dir do |dir|
8
+ brothers = datafile_test(:person).brothers
9
+ kb = KnowledgeBase.new dir
10
+ kb.register :brothers, brothers, description: "Sibling relationships."
11
+ assert_equal "Sibling relationships.", kb.description(:brothers)
12
+ end
13
+ end
14
+
15
+ def test_brothers_README
16
+ TmpFile.with_dir do |dir|
17
+ brothers = datafile_test(:person).brothers
18
+ kb = KnowledgeBase.new dir
19
+ kb.register :brothers, brothers
20
+ kb.dir['brothers.md'].write "Sibling relationships."
21
+ assert_equal "Sibling relationships.", kb.description(:brothers)
22
+ end
23
+ end
24
+
25
+ def test_broters_kb_README
26
+ TmpFile.with_dir do |dir|
27
+ brothers = datafile_test(:person).brothers
28
+ kb = KnowledgeBase.new dir
29
+ kb.register :brothers, brothers
30
+ kb.dir['README.md'].write <<-EOF
31
+ Databases describing people and their relationships.
32
+
33
+ # Brothers
34
+
35
+ Sibling relationships.
36
+ EOF
37
+ assert_equal "Sibling relationships.", kb.description(:brothers)
38
+ end
39
+ end
40
+
41
+ def test_brothers_kb_source_README
42
+ TmpFile.with_dir do |dir|
43
+ brothers = datafile_test(:person).brothers
44
+ kb = KnowledgeBase.new dir
45
+ kb.register :brothers, brothers
46
+ assert_include kb.description(:brothers), "Sibling relationships."
47
+ end
48
+ end
49
+
50
+ def test_full_description
51
+ TmpFile.with_dir do |dir|
52
+ brothers = datafile_test(:person).brothers
53
+ kb = KnowledgeBase.new dir
54
+ kb.register :brothers, brothers
55
+ assert_include kb.markdown(:brothers), "Older"
56
+ end
57
+ end
58
+ end
59
+
@@ -12,15 +12,15 @@ class TestWorkflowEntity < Test::Unit::TestCase
12
12
  "Mi name is #{self}"
13
13
  end
14
14
 
15
- entity_job hi: :string do
15
+ entity_task hi: :string do
16
16
  "Hi. #{entity.introduction}"
17
17
  end
18
18
 
19
- list_job group_hi: :string do
19
+ list_task group_hi: :string do
20
20
  "Here is the group: " + entity_list.hi * "; "
21
21
  end
22
22
 
23
- list_job bye: :array do
23
+ list_task bye: :array do
24
24
  entity_list.collect do |e|
25
25
  "Bye from #{e}"
26
26
  end
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.7.5
4
+ version: 10.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-19 00:00:00.000000000 Z
10
+ date: 2025-04-08 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: scout-essentials
@@ -114,6 +114,7 @@ files:
114
114
  - lib/scout/entity/object.rb
115
115
  - lib/scout/entity/property.rb
116
116
  - lib/scout/knowledge_base.rb
117
+ - lib/scout/knowledge_base/description.rb
117
118
  - lib/scout/knowledge_base/enrichment.rb
118
119
  - lib/scout/knowledge_base/entity.rb
119
120
  - lib/scout/knowledge_base/list.rb
@@ -167,12 +168,14 @@ files:
167
168
  - lib/scout/workflow/definition.rb
168
169
  - lib/scout/workflow/deployment.rb
169
170
  - lib/scout/workflow/deployment/orchestrator.rb
171
+ - lib/scout/workflow/deployment/queue.rb
170
172
  - lib/scout/workflow/deployment/trace.rb
171
173
  - lib/scout/workflow/documentation.rb
172
174
  - lib/scout/workflow/entity.rb
173
175
  - lib/scout/workflow/exceptions.rb
174
176
  - lib/scout/workflow/export.rb
175
177
  - lib/scout/workflow/path.rb
178
+ - lib/scout/workflow/persist.rb
176
179
  - lib/scout/workflow/step.rb
177
180
  - lib/scout/workflow/step/archive.rb
178
181
  - lib/scout/workflow/step/children.rb
@@ -211,9 +214,11 @@ files:
211
214
  - scout_commands/resource/produce
212
215
  - scout_commands/template
213
216
  - scout_commands/update
217
+ - scout_commands/workflow/cmd
214
218
  - scout_commands/workflow/info
215
219
  - scout_commands/workflow/install
216
220
  - scout_commands/workflow/list
221
+ - scout_commands/workflow/process
217
222
  - scout_commands/workflow/prov
218
223
  - scout_commands/workflow/task
219
224
  - scout_commands/workflow/trace
@@ -223,6 +228,7 @@ files:
223
228
  - share/software/install_helpers
224
229
  - share/templates/command
225
230
  - share/templates/workflow.rb
231
+ - test/data/person/README.md
226
232
  - test/data/person/brothers
227
233
  - test/data/person/identifiers
228
234
  - test/data/person/marriages
@@ -235,6 +241,7 @@ files:
235
241
  - test/scout/entity/test_named_array.rb
236
242
  - test/scout/entity/test_object.rb
237
243
  - test/scout/entity/test_property.rb
244
+ - test/scout/knowledge_base/test_description.rb
238
245
  - test/scout/knowledge_base/test_enrichment.rb
239
246
  - test/scout/knowledge_base/test_entity.rb
240
247
  - test/scout/knowledge_base/test_list.rb