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 +4 -4
- data/.vimproject +7 -0
- data/VERSION +1 -1
- data/lib/scout/association/index.rb +2 -2
- data/lib/scout/knowledge_base/description.rb +108 -0
- data/lib/scout/knowledge_base/entity.rb +6 -1
- data/lib/scout/knowledge_base/registry.rb +43 -15
- data/lib/scout/knowledge_base.rb +3 -2
- data/lib/scout/tsv/change_id/translate.rb +1 -0
- data/lib/scout/tsv/open.rb +8 -0
- data/lib/scout/tsv/parser.rb +14 -3
- data/lib/scout/workflow/deployment/orchestrator.rb +9 -1
- data/lib/scout/workflow/deployment/queue.rb +26 -0
- data/lib/scout/workflow/export.rb +6 -0
- data/lib/scout/workflow/persist.rb +6 -0
- data/lib/scout/workflow/step/info.rb +1 -0
- data/lib/scout/workflow/step/inputs.rb +11 -1
- data/lib/scout/workflow/task.rb +2 -1
- data/lib/scout/workflow.rb +7 -1
- data/scout-gear.gemspec +10 -3
- data/scout_commands/kb/config +3 -0
- data/scout_commands/kb/list +1 -0
- data/scout_commands/kb/query +2 -1
- data/scout_commands/kb/register +3 -1
- data/scout_commands/kb/show +4 -2
- data/scout_commands/workflow/cmd +116 -0
- data/scout_commands/workflow/process +82 -0
- data/scout_commands/workflow/task +15 -3
- data/test/data/person/README.md +17 -0
- data/test/scout/knowledge_base/test_description.rb +59 -0
- data/test/scout/workflow/test_entity.rb +3 -3
- metadata +9 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f346d283c182fbb5a090329100ad4bd32a50e7e84c058c156014ca1fd2e64772
         | 
| 4 | 
            +
              data.tar.gz: d4457afe22a81e426232ee94ddc798921fc69dfcf35a628c8ecafa39fb3a271b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 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. | 
| 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  | 
| 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  | 
| 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  | 
| 33 | 
            -
                @ | 
| 34 | 
            -
                @ | 
| 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 | 
            -
                 | 
| 58 | 
            +
                pair(name)[0]
         | 
| 39 59 | 
             
              end
         | 
| 40 60 |  | 
| 41 61 | 
             
              def target(name)
         | 
| 42 | 
            -
                 | 
| 62 | 
            +
                pair(name)[1]
         | 
| 43 63 | 
             
              end
         | 
| 44 64 |  | 
| 45 65 | 
             
              def undirected(name)
         | 
| 46 | 
            -
                 | 
| 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 | 
            -
             | 
| 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 | 
            -
                                 | 
| 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 | 
            -
                                 | 
| 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 | 
            -
             | 
| 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 |  | 
    
        data/lib/scout/knowledge_base.rb
    CHANGED
    
    | @@ -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 | 
            -
                 | 
| 27 | 
            +
                pairs          ||= IndiferentHash.setup({})
         | 
| 27 28 | 
             
                @indices        ||= IndiferentHash.setup({})
         | 
| 28 29 | 
             
              end
         | 
| 29 30 |  | 
| 30 31 | 
             
              def config_file(name)
         | 
| 31 | 
            -
                @dir | 
| 32 | 
            +
                @dir['config'][name.to_s]
         | 
| 32 33 | 
             
              end
         | 
| 33 34 |  | 
| 34 35 | 
             
              def save_variable(name)
         | 
    
        data/lib/scout/tsv/open.rb
    CHANGED
    
    | @@ -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])
         | 
    
        data/lib/scout/tsv/parser.rb
    CHANGED
    
    | @@ -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 | 
            -
                      ( | 
| 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
         | 
| @@ -1,5 +1,15 @@ | |
| 1 1 | 
             
            class Step
         | 
| 2 2 | 
             
              def save_inputs(inputs_dir)
         | 
| 3 | 
            -
                 | 
| 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
         | 
    
        data/lib/scout/workflow/task.rb
    CHANGED
    
    | @@ -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} | 
| 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)
         | 
    
        data/lib/scout/workflow.rb
    CHANGED
    
    | @@ -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 | 
            +
            # 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. | 
| 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- | 
| 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",
         | 
    
        data/scout_commands/kb/config
    CHANGED
    
    | @@ -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
         | 
    
        data/scout_commands/kb/list
    CHANGED
    
    
    
        data/scout_commands/kb/query
    CHANGED
    
    | @@ -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 =  | 
| 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 |  | 
    
        data/scout_commands/kb/register
    CHANGED
    
    | @@ -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 =  | 
| 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))
         | 
    
        data/scout_commands/kb/show
    CHANGED
    
    | @@ -23,7 +23,8 @@ if options[:help] | |
| 23 23 | 
             
              exit 0
         | 
| 24 24 | 
             
            end
         | 
| 25 25 |  | 
| 26 | 
            -
            knowledge_base =  | 
| 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 | 
            -
                   | 
| 15 | 
            +
                  entity_task hi: :string do
         | 
| 16 16 | 
             
                    "Hi. #{entity.introduction}"
         | 
| 17 17 | 
             
                  end
         | 
| 18 18 |  | 
| 19 | 
            -
                   | 
| 19 | 
            +
                  list_task group_hi: :string do
         | 
| 20 20 | 
             
                    "Here is the group: " + entity_list.hi * "; "
         | 
| 21 21 | 
             
                  end
         | 
| 22 22 |  | 
| 23 | 
            -
                   | 
| 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. | 
| 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- | 
| 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
         |