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
@@ -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,21 +2,22 @@
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.3 ruby lib
5
+ # stub: scout-gear 10.9.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-gear".freeze
9
- s.version = "10.8.3".freeze
9
+ s.version = "10.9.0".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-06-13"
14
+ s.date = "1980-01-02"
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]
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",
@@ -51,6 +59,7 @@ Gem::Specification.new do |s|
51
59
  "lib/scout/knowledge_base/query.rb",
52
60
  "lib/scout/knowledge_base/registry.rb",
53
61
  "lib/scout/knowledge_base/traverse.rb",
62
+ "lib/scout/monitor.rb",
54
63
  "lib/scout/persist/engine.rb",
55
64
  "lib/scout/persist/engine/fix_width_table.rb",
56
65
  "lib/scout/persist/engine/packed_index.rb",
@@ -129,7 +138,9 @@ Gem::Specification.new do |s|
129
138
  "scout_commands/alias",
130
139
  "scout_commands/batch/clean",
131
140
  "scout_commands/batch/list",
141
+ "scout_commands/cat",
132
142
  "scout_commands/doc",
143
+ "scout_commands/entity",
133
144
  "scout_commands/find",
134
145
  "scout_commands/glob",
135
146
  "scout_commands/kb/config",
@@ -143,6 +154,8 @@ Gem::Specification.new do |s|
143
154
  "scout_commands/rbbt",
144
155
  "scout_commands/resource/produce",
145
156
  "scout_commands/resource/sync",
157
+ "scout_commands/system/clean",
158
+ "scout_commands/system/status",
146
159
  "scout_commands/template",
147
160
  "scout_commands/update",
148
161
  "scout_commands/workflow/cmd",
@@ -250,7 +263,7 @@ Gem::Specification.new do |s|
250
263
  ]
251
264
  s.homepage = "http://github.com/mikisvaz/scout-gear".freeze
252
265
  s.licenses = ["MIT".freeze]
253
- s.rubygems_version = "3.6.6".freeze
266
+ s.rubygems_version = "3.7.0.dev".freeze
254
267
  s.summary = "basic gear for scouts".freeze
255
268
 
256
269
  s.specification_version = 4
@@ -259,6 +272,7 @@ Gem::Specification.new do |s|
259
272
  s.add_runtime_dependency(%q<net-ssh>.freeze, [">= 0".freeze])
260
273
  s.add_runtime_dependency(%q<matrix>.freeze, [">= 0".freeze])
261
274
  s.add_runtime_dependency(%q<RubyInline>.freeze, [">= 0".freeze])
275
+ s.add_runtime_dependency(%q<csv>.freeze, [">= 0".freeze])
262
276
  s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.1.0".freeze])
263
277
  end
264
278
 
@@ -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
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+ require 'scout/monitor'
5
+
6
+ $0 = "scout #{$previous_commands*""} #{ File.basename(__FILE__) }" if $previous_commands
7
+
8
+ options = SOPT.setup <<EOF
9
+
10
+ Clean orphaned files
11
+
12
+ $ rbbt system clean <workflow> <task>
13
+
14
+ Specify workflow '.' and no task to examine the jobs of the current directory (usefull for web-server cache).
15
+
16
+ -a--all Apply to all jobs, not only uncompleted
17
+ -o--older* Clean jobs not access in some time
18
+ -f--force Remove locks and files regardless of been active
19
+ -q--quick Quick check
20
+ -d--dirty Clean dirty jobs
21
+ -h--help Print this help
22
+ EOF
23
+
24
+ scout_usage and exit 0 if options[:help]
25
+
26
+ workflow, task = ARGV
27
+
28
+ workflow = workflow.split "," if workflow
29
+ task = task.split "," if task
30
+
31
+ all = options.delete :all
32
+ force = options.delete :force
33
+ dirty = options.delete :dirty
34
+ time = options.delete :older
35
+
36
+ ENV["SCOUT_DEBUG_CLEAN"] = 'false'
37
+ ENV["SCOUT_UPDATE"] = 'true' if dirty
38
+
39
+ time = Misc.timespan time, 'd' if time
40
+
41
+ puts Log.color(:magenta, "# System clean")
42
+
43
+ locks = Scout.lock_info
44
+ if locks.any?
45
+ puts
46
+ puts Log.color(:magenta, "Locks:")
47
+ locks.each do |file,info|
48
+ if force or (info[:pid] && ! Misc.pid_alive?(info[:pid]))
49
+ puts " Removing #{ file }"
50
+ File.unlink file
51
+ end
52
+ end
53
+ end
54
+
55
+ persists = Scout.persist_info
56
+ if persists.any?
57
+ puts
58
+ puts Log.color(:magenta, "Persist:")
59
+ persists.each do |file,info|
60
+ if force or (info[:pid] and Misc.pid_alive? info[:pid])
61
+ puts " Removing #{ file }"
62
+ File.unlink file
63
+ end
64
+ end
65
+ end
66
+
67
+ sensiblewrites = Scout.sensiblewrite_info
68
+ if sensiblewrites.any?
69
+ puts
70
+ puts Log.color(:magenta, "Writes:")
71
+ sensiblewrites.each do |file,info|
72
+ if force or (info[:pid] and Misc.pid_alive? info[:pid])
73
+ puts " Removing #{ file }"
74
+ File.unlink file
75
+ end
76
+ end
77
+ end
78
+
79
+ exit 0 if workflow.nil?
80
+ workflow = nil if workflow == ["all"]
81
+
82
+ puts
83
+ puts Log.color(:magenta, "# Workflow clean")
84
+ puts
85
+
86
+ if workflow === ['.']
87
+ jobs = Scout.job_info ["all"], task, ['.']
88
+ else
89
+ jobs = Scout.job_info workflow, task
90
+ end
91
+
92
+ workflows = {}
93
+
94
+ TSV.traverse jobs do |file,i|
95
+ if options[:quick] and i[:done]
96
+ status = 'done'
97
+ else
98
+ info = begin
99
+ Open.open(i[:info_file]) do |f|
100
+ Step.load_info(f)
101
+ end
102
+ rescue
103
+ {:status => :noinfo}
104
+ end
105
+
106
+ done = Open.exists?(file) && ! Open.broken_link?(file)
107
+ pid = info[:pid] || (Open.exists?(file + '.pid') && Open.read(file + '.pid')) unless done
108
+
109
+ status = info[:status].to_s
110
+ if status != "noinfo"
111
+ status = :missing if status == "done" and not done
112
+ status = :nopid if status != "done" and pid.nil?
113
+ status = :dead if status != "done" and pid and not Misc.pid_alive?(pid)
114
+ status = :sync if status != "done" and done
115
+ end
116
+
117
+ status = :dirty if info[:status].to_s == "done" and dirty and Workflow.load_step(file).dirty?
118
+ if info[:status] == :error
119
+ begin
120
+ exception = info[:exception][:class]
121
+ Kernel.const_get exception
122
+ status = :non_recoverable if exception.superclass === ScoutException
123
+ rescue
124
+ end
125
+ end
126
+
127
+ status = status.to_s
128
+ end
129
+
130
+ if time and Open.exists?(file)
131
+ old = Time.now - Open.atime(file)
132
+ if old > time
133
+ status = 'old'
134
+ end
135
+ end
136
+
137
+ if (force && status !~ /done/) or
138
+ status =~ /\b(old|dirty|nopid|error|missing|aborted|dead|sync|waiting)$/ or
139
+ (status == "noinfo" and not done) or
140
+ status == ""
141
+
142
+ puts " Removing #{ file } - #{status}"
143
+ Step.clean(file)
144
+ end
145
+ end
146
+