scout-gear 8.0.0 → 8.1.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.
- checksums.yaml +4 -4
- data/.vimproject +26 -9
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/scout +15 -4
- data/doc/lib/scout/path.md +35 -0
- data/doc/lib/scout/workflow/task.md +13 -0
- data/lib/scout/cmd.rb +23 -24
- data/lib/scout/concurrent_stream.rb +36 -19
- data/lib/scout/exceptions.rb +10 -0
- data/lib/scout/log/color.rb +11 -11
- data/lib/scout/log/progress/report.rb +7 -5
- data/lib/scout/log/progress/util.rb +3 -0
- data/lib/scout/log/trap.rb +3 -3
- data/lib/scout/log.rb +64 -36
- data/lib/scout/meta_extension.rb +34 -0
- data/lib/scout/misc/digest.rb +11 -2
- data/lib/scout/misc/format.rb +12 -7
- data/lib/scout/misc/monitor.rb +11 -0
- data/lib/scout/misc/system.rb +48 -0
- data/lib/scout/named_array.rb +8 -0
- data/lib/scout/offsite/ssh.rb +171 -0
- data/lib/scout/offsite/step.rb +83 -0
- data/lib/scout/offsite/sync.rb +55 -0
- data/lib/scout/offsite.rb +3 -0
- data/lib/scout/open/lock.rb +5 -24
- data/lib/scout/open/remote.rb +12 -1
- data/lib/scout/open/stream.rb +110 -122
- data/lib/scout/open/util.rb +9 -0
- data/lib/scout/open.rb +5 -4
- data/lib/scout/path/find.rb +15 -10
- data/lib/scout/path/util.rb +5 -0
- data/lib/scout/persist/serialize.rb +3 -3
- data/lib/scout/persist.rb +1 -1
- data/lib/scout/resource/path.rb +4 -0
- data/lib/scout/resource/util.rb +10 -4
- data/lib/scout/tsv/dumper.rb +2 -0
- data/lib/scout/tsv/index.rb +28 -86
- data/lib/scout/tsv/open.rb +35 -14
- data/lib/scout/tsv/parser.rb +9 -2
- data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
- data/lib/scout/tsv/stream.rb +204 -0
- data/lib/scout/tsv/transformer.rb +11 -0
- data/lib/scout/tsv.rb +9 -2
- data/lib/scout/work_queue/worker.rb +2 -2
- data/lib/scout/work_queue.rb +36 -12
- data/lib/scout/workflow/definition.rb +2 -1
- data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
- data/lib/scout/workflow/deployment.rb +1 -0
- data/lib/scout/workflow/step/dependencies.rb +37 -11
- data/lib/scout/workflow/step/file.rb +5 -0
- data/lib/scout/workflow/step/info.rb +5 -3
- data/lib/scout/workflow/step/load.rb +1 -1
- data/lib/scout/workflow/step/provenance.rb +1 -0
- data/lib/scout/workflow/step/status.rb +6 -8
- data/lib/scout/workflow/step.rb +75 -30
- data/lib/scout/workflow/task/dependencies.rb +114 -0
- data/lib/scout/workflow/task/inputs.rb +27 -13
- data/lib/scout/workflow/task.rb +9 -108
- data/lib/scout/workflow/usage.rb +40 -12
- data/lib/scout/workflow.rb +4 -2
- data/lib/scout-gear.rb +2 -0
- data/lib/scout.rb +6 -0
- data/scout-gear.gemspec +32 -7
- data/scout_commands/doc +37 -0
- data/scout_commands/find +1 -0
- data/scout_commands/offsite +30 -0
- data/scout_commands/update +29 -0
- data/scout_commands/workflow/info +15 -3
- data/scout_commands/workflow/install +102 -0
- data/scout_commands/workflow/task +26 -5
- data/test/scout/offsite/test_ssh.rb +15 -0
- data/test/scout/offsite/test_step.rb +33 -0
- data/test/scout/offsite/test_sync.rb +36 -0
- data/test/scout/offsite/test_task.rb +0 -0
- data/test/scout/resource/test_path.rb +6 -0
- data/test/scout/test_named_array.rb +6 -0
- data/test/scout/test_persist.rb +3 -2
- data/test/scout/test_tsv.rb +17 -0
- data/test/scout/test_work_queue.rb +63 -41
- data/test/scout/tsv/persist/test_adapter.rb +1 -1
- data/test/scout/tsv/test_index.rb +14 -0
- data/test/scout/tsv/test_parser.rb +14 -0
- data/test/scout/tsv/test_stream.rb +200 -0
- data/test/scout/tsv/test_transformer.rb +12 -0
- data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
- data/test/scout/workflow/step/test_dependencies.rb +68 -0
- data/test/scout/workflow/step/test_info.rb +18 -0
- data/test/scout/workflow/step/test_status.rb +0 -1
- data/test/scout/workflow/task/test_dependencies.rb +355 -0
- data/test/scout/workflow/task/test_inputs.rb +53 -0
- data/test/scout/workflow/test_definition.rb +18 -0
- data/test/scout/workflow/test_documentation.rb +24 -0
- data/test/scout/workflow/test_step.rb +109 -0
- data/test/scout/workflow/test_task.rb +0 -287
- data/test/test_scout.rb +9 -0
- metadata +83 -5
- data/scout_commands/workflow/task_old +0 -706
    
        data/lib/scout/open/lock.rb
    CHANGED
    
    | @@ -4,27 +4,13 @@ require_relative '../exceptions' | |
| 4 4 | 
             
            require_relative 'lock/lockfile'
         | 
| 5 5 |  | 
| 6 6 | 
             
            module Open
         | 
| 7 | 
            -
              def self. | 
| 8 | 
            -
                 | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
              def self.unlock_thread(t, exception = nil)
         | 
| 12 | 
            -
                while t.alive? && t.backtrace.select{|l| l.include?("lockfile") }.any?
         | 
| 13 | 
            -
                  iii :UNLOCK
         | 
| 14 | 
            -
                  t.raise(exception)
         | 
| 15 | 
            -
                  Log.stack t.backtrace
         | 
| 16 | 
            -
                  locks = t["locks"]
         | 
| 17 | 
            -
                  return if locks.nil? || locks.empty?
         | 
| 18 | 
            -
                  locks.each do |lock|
         | 
| 19 | 
            -
                    lock.unlock if lock.locked?
         | 
| 20 | 
            -
                    Open.rm(lock.path)
         | 
| 21 | 
            -
                  end
         | 
| 22 | 
            -
                  iii Thread.current
         | 
| 23 | 
            -
                  Thread.list.each{|t| iii [t, t["locks"]]; Log.stack t.backtrace }
         | 
| 24 | 
            -
                  Log.stack t.backtrace
         | 
| 25 | 
            -
                end
         | 
| 7 | 
            +
              def self.init_lock
         | 
| 8 | 
            +
                Lockfile.refresh = 2 
         | 
| 9 | 
            +
                Lockfile.max_age = 30
         | 
| 10 | 
            +
                Lockfile.suspend = 4
         | 
| 26 11 | 
             
              end
         | 
| 27 12 |  | 
| 13 | 
            +
              self.init_lock 
         | 
| 28 14 |  | 
| 29 15 | 
             
              def self.lock(file, unlock = true, options = {})
         | 
| 30 16 | 
             
                unlock, options = true, unlock if Hash === unlock
         | 
| @@ -57,9 +43,6 @@ module Open | |
| 57 43 | 
             
                  raise LockInterrupted
         | 
| 58 44 | 
             
                end
         | 
| 59 45 |  | 
| 60 | 
            -
                iii Thread.current["lock_exception"] if Thread.current["lock_exception"]
         | 
| 61 | 
            -
                raise Thread.current["lock_exception"] if Thread.current["lock_exception"]
         | 
| 62 | 
            -
             | 
| 63 46 | 
             
                res = nil
         | 
| 64 47 |  | 
| 65 48 | 
             
                begin
         | 
| @@ -73,8 +56,6 @@ module Open | |
| 73 56 | 
             
                      if lockfile.locked?
         | 
| 74 57 | 
             
                        lockfile.unlock 
         | 
| 75 58 | 
             
                      end
         | 
| 76 | 
            -
                      iii Thread.current["lock_exception"] if Thread.current["lock_exception"]
         | 
| 77 | 
            -
                      raise Thread.current["lock_exception"] if Thread.current["lock_exception"]
         | 
| 78 59 | 
             
                    rescue Exception
         | 
| 79 60 | 
             
                      Log.warn "Exception unlocking: #{lockfile.path}"
         | 
| 80 61 | 
             
                      Log.exception $!
         | 
    
        data/lib/scout/open/remote.rb
    CHANGED
    
    | @@ -23,7 +23,11 @@ module Open | |
| 23 23 | 
             
                m = file.match(/ssh:\/\/([^:]+):(.*)/)
         | 
| 24 24 | 
             
                server = m[1]
         | 
| 25 25 | 
             
                file = m[2]
         | 
| 26 | 
            -
                 | 
| 26 | 
            +
                if server == 'localhost'
         | 
| 27 | 
            +
                  Open.open(file)
         | 
| 28 | 
            +
                else
         | 
| 29 | 
            +
                  CMD.cmd("ssh '#{server}' cat '#{file}'", :pipe => true, :autojoin => true)
         | 
| 30 | 
            +
                end
         | 
| 27 31 | 
             
              end
         | 
| 28 32 |  | 
| 29 33 | 
             
              def self.wget(url, options = {})
         | 
| @@ -121,4 +125,11 @@ module Open | |
| 121 125 | 
             
                filename = cache_file(url, options)
         | 
| 122 126 | 
             
                Open.open(filename)
         | 
| 123 127 | 
             
              end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
              def self.scp(source_file, target_file, target: nil, source: nil)
         | 
| 130 | 
            +
                CMD.cmd_log("ssh #{target} mkdir -p #{File.dirname(target_file)}")
         | 
| 131 | 
            +
                target_file = [target, target_file] * ":" if target && ! target_file.start_with?(target+":")
         | 
| 132 | 
            +
                source_file = [source, source_file] * ":" if source && ! source_file.start_with?(source+":")
         | 
| 133 | 
            +
                CMD.cmd_log("scp -r '#{ source_file }' #{target_file}")
         | 
| 134 | 
            +
              end
         | 
| 124 135 | 
             
            end
         | 
    
        data/lib/scout/open/stream.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ module Open | |
| 3 3 |  | 
| 4 4 | 
             
              class << self
         | 
| 5 5 | 
             
                attr_accessor :sensible_write_lock_dir
         | 
| 6 | 
            -
             | 
| 6 | 
            +
             | 
| 7 7 | 
             
                def sensible_write_lock_dir
         | 
| 8 8 | 
             
                  @sensible_write_lock_dir ||= Path.setup("tmp/sensible_write_locks").find
         | 
| 9 9 | 
             
                end
         | 
| @@ -18,7 +18,7 @@ module Open | |
| 18 18 |  | 
| 19 19 | 
             
              def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
         | 
| 20 20 | 
             
                return if Path === io
         | 
| 21 | 
            -
                return unless io.respond_to? :read | 
| 21 | 
            +
                return unless io.respond_to? :read
         | 
| 22 22 |  | 
| 23 23 | 
             
                if io.respond_to? :closed? and io.closed?
         | 
| 24 24 | 
             
                  io.join if io.respond_to? :join
         | 
| @@ -46,12 +46,12 @@ module Open | |
| 46 46 | 
             
                  begin
         | 
| 47 47 | 
             
                    into = into.find if Path === into
         | 
| 48 48 |  | 
| 49 | 
            -
                    if String === into | 
| 49 | 
            +
                    if String === into
         | 
| 50 50 | 
             
                      dir = File.dirname(into)
         | 
| 51 51 | 
             
                      Open.mkdir dir unless File.exist?(dir)
         | 
| 52 | 
            -
                      into_path, into = into, File.open(into, 'w') | 
| 52 | 
            +
                      into_path, into = into, File.open(into, 'w')
         | 
| 53 53 | 
             
                    end
         | 
| 54 | 
            -
             | 
| 54 | 
            +
             | 
| 55 55 | 
             
                    into_close = false unless into.respond_to? :close
         | 
| 56 56 |  | 
| 57 57 | 
             
                    while c = io.read(BLOCK_SIZE)
         | 
| @@ -66,6 +66,7 @@ module Open | |
| 66 66 | 
             
                    into.close if into and into_close and not into.closed?
         | 
| 67 67 | 
             
                    block.call if block_given?
         | 
| 68 68 |  | 
| 69 | 
            +
                    Log.debug "Consume stream done #{Log.fingerprint io} -> #{Log.fingerprint(into_path ||into)}"
         | 
| 69 70 | 
             
                    last_c
         | 
| 70 71 | 
             
                  rescue Aborted
         | 
| 71 72 | 
             
                    Thread.current["exception"] = true
         | 
| @@ -81,7 +82,7 @@ module Open | |
| 81 82 | 
             
                    into.close if into.respond_to?(:closed?) && ! into.closed?
         | 
| 82 83 | 
             
                    into_path = into if into_path.nil? && String === into
         | 
| 83 84 | 
             
                    if into_path and File.exist?(into_path)
         | 
| 84 | 
            -
                      FileUtils.rm into_path | 
| 85 | 
            +
                      FileUtils.rm into_path
         | 
| 85 86 | 
             
                    end
         | 
| 86 87 | 
             
                    raise exception
         | 
| 87 88 | 
             
                  end
         | 
| @@ -92,7 +93,7 @@ module Open | |
| 92 93 | 
             
                force = IndiferentHash.process_options options, :force
         | 
| 93 94 |  | 
| 94 95 | 
             
                if File.exist?(path) and not force
         | 
| 95 | 
            -
                  Open.consume_stream content | 
| 96 | 
            +
                  Open.consume_stream content
         | 
| 96 97 | 
             
                  return
         | 
| 97 98 | 
             
                end
         | 
| 98 99 |  | 
| @@ -107,10 +108,11 @@ module Open | |
| 107 108 |  | 
| 108 109 | 
             
                  if File.exist? path and not force
         | 
| 109 110 | 
             
                    Log.warn "Path exists in sensible_write, not forcing update: #{ path }"
         | 
| 110 | 
            -
                    Open.consume_stream content | 
| 111 | 
            +
                    Open.consume_stream content
         | 
| 111 112 | 
             
                  else
         | 
| 112 113 | 
             
                    FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory?(File.dirname(tmp_path))
         | 
| 113 114 | 
             
                    FileUtils.rm_f tmp_path if File.exist? tmp_path
         | 
| 115 | 
            +
                    Log.low "Sensible write stream #{Log.fingerprint content} -> #{Log.fingerprint path}" if IO === content
         | 
| 114 116 | 
             
                    begin
         | 
| 115 117 | 
             
                      case
         | 
| 116 118 | 
             
                      when block_given?
         | 
| @@ -122,7 +124,7 @@ module Open | |
| 122 124 | 
             
                          while block = content.read(BLOCK_SIZE)
         | 
| 123 125 | 
             
                            f.write block
         | 
| 124 126 | 
             
                            break if content.closed?
         | 
| 125 | 
            -
                          end | 
| 127 | 
            +
                          end
         | 
| 126 128 | 
             
                        end
         | 
| 127 129 | 
             
                      else
         | 
| 128 130 | 
             
                        File.open(tmp_path, 'wb') do |f|  end
         | 
| @@ -139,8 +141,7 @@ module Open | |
| 139 141 | 
             
                      Open.touch path if File.exist? path
         | 
| 140 142 | 
             
                      content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
         | 
| 141 143 |  | 
| 142 | 
            -
                      Open.notify_write(path) | 
| 143 | 
            -
                      Log.debug "Done sensible write: [#{Process.pid}] -- #{ path }"
         | 
| 144 | 
            +
                      Open.notify_write(path)
         | 
| 144 145 | 
             
                    rescue Aborted
         | 
| 145 146 | 
             
                      Log.low "Aborted sensible_write -- #{ Log.reset << path }"
         | 
| 146 147 | 
             
                      content.abort if content.respond_to? :abort
         | 
| @@ -174,7 +175,7 @@ module Open | |
| 174 175 |  | 
| 175 176 | 
             
                  [sout, sin]
         | 
| 176 177 | 
             
                end
         | 
| 177 | 
            -
                Log. | 
| 178 | 
            +
                Log.low{"Creating pipe #{[Log.fingerprint(res.last), Log.fingerprint(res.first)] * " -> "}"}
         | 
| 178 179 | 
             
                res
         | 
| 179 180 | 
             
              end
         | 
| 180 181 |  | 
| @@ -214,14 +215,13 @@ module Open | |
| 214 215 |  | 
| 215 216 | 
             
                if do_fork
         | 
| 216 217 |  | 
| 217 | 
            -
                  #parent_pid = Process.pid
         | 
| 218 218 | 
             
                  pid = Process.fork {
         | 
| 219 219 | 
             
                    begin
         | 
| 220 220 | 
             
                      purge_pipes(sin)
         | 
| 221 221 | 
             
                      sout.close
         | 
| 222 222 |  | 
| 223 223 | 
             
                      yield sin
         | 
| 224 | 
            -
                      sin.close if close and not sin.closed? | 
| 224 | 
            +
                      sin.close if close and not sin.closed?
         | 
| 225 225 |  | 
| 226 226 | 
             
                    rescue Exception
         | 
| 227 227 | 
             
                      Log.exception $!
         | 
| @@ -237,34 +237,20 @@ module Open | |
| 237 237 | 
             
                  ConcurrentStream.setup sin, :pair => sout
         | 
| 238 238 | 
             
                  ConcurrentStream.setup sout, :pair => sin
         | 
| 239 239 |  | 
| 240 | 
            -
                  thread = Thread.new do | 
| 240 | 
            +
                  thread = Thread.new do
         | 
| 241 241 | 
             
                    begin
         | 
| 242 | 
            -
                       | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 245 | 
            -
                      yield sin
         | 
| 242 | 
            +
                      ConcurrentStream.process_stream(sin, :message => "Open pipe") do
         | 
| 243 | 
            +
                        Thread.current.report_on_exception = false
         | 
| 244 | 
            +
                        Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
         | 
| 246 245 |  | 
| 247 | 
            -
             | 
| 248 | 
            -
                    rescue Aborted
         | 
| 249 | 
            -
                      Log.low "Aborted open_pipe: #{$!.message}"
         | 
| 250 | 
            -
                      raise $!
         | 
| 251 | 
            -
                    rescue Exception
         | 
| 252 | 
            -
                      Log.low "Exception in open_pipe: #{$!.message}"
         | 
| 253 | 
            -
                      begin
         | 
| 254 | 
            -
                        sout.threads.delete(Thread.current)
         | 
| 255 | 
            -
                        sout.pair = []
         | 
| 256 | 
            -
                        sout.abort($!) if sout.respond_to?(:abort)
         | 
| 257 | 
            -
                        sin.threads.delete(Thread.current)
         | 
| 258 | 
            -
                        sin.pair = []
         | 
| 259 | 
            -
                        sin.abort($!) if sin.respond_to?(:abort)
         | 
| 260 | 
            -
                      ensure
         | 
| 261 | 
            -
                        raise $!
         | 
| 246 | 
            +
                        yield sin
         | 
| 262 247 | 
             
                      end
         | 
| 263 248 | 
             
                    end
         | 
| 264 249 | 
             
                  end
         | 
| 265 250 |  | 
| 266 251 | 
             
                  sin.threads = [thread]
         | 
| 267 252 | 
             
                  sout.threads = [thread]
         | 
| 253 | 
            +
             | 
| 268 254 | 
             
                  Thread.pass until thread["name"]
         | 
| 269 255 | 
             
                end
         | 
| 270 256 |  | 
| @@ -274,12 +260,14 @@ module Open | |
| 274 260 | 
             
              def self.tee_stream_thread_multiple(stream, num = 2)
         | 
| 275 261 | 
             
                in_pipes = []
         | 
| 276 262 | 
             
                out_pipes = []
         | 
| 277 | 
            -
                num.times do | 
| 263 | 
            +
                num.times do
         | 
| 278 264 | 
             
                  sout, sin = Open.pipe
         | 
| 279 265 | 
             
                  in_pipes << sin
         | 
| 280 266 | 
             
                  out_pipes << sout
         | 
| 281 267 | 
             
                end
         | 
| 282 268 |  | 
| 269 | 
            +
                Log.low("Tee stream #{Log.fingerprint stream} -> #{Log.fingerprint out_pipes}")
         | 
| 270 | 
            +
             | 
| 283 271 | 
             
                filename = stream.filename if stream.respond_to? :filename
         | 
| 284 272 |  | 
| 285 273 | 
             
                splitter_thread = Thread.new(Thread.current) do |parent|
         | 
| @@ -291,7 +279,7 @@ module Open | |
| 291 279 | 
             
                    while block = stream.read(BLOCK_SIZE)
         | 
| 292 280 |  | 
| 293 281 | 
             
                      in_pipes.each_with_index do |sin,i|
         | 
| 294 | 
            -
                        begin | 
| 282 | 
            +
                        begin
         | 
| 295 283 | 
             
                          sin.write block
         | 
| 296 284 | 
             
                        rescue IOError
         | 
| 297 285 | 
             
                          Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
         | 
| @@ -299,13 +287,12 @@ module Open | |
| 299 287 | 
             
                        rescue
         | 
| 300 288 | 
             
                          Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
         | 
| 301 289 | 
             
                          raise $!
         | 
| 302 | 
            -
                        end unless skip[i] | 
| 290 | 
            +
                        end unless skip[i]
         | 
| 303 291 | 
             
                      end
         | 
| 304 292 | 
             
                      break if stream.closed?
         | 
| 305 293 | 
             
                    end
         | 
| 306 294 |  | 
| 307 295 | 
             
                    stream.join if stream.respond_to? :join
         | 
| 308 | 
            -
                    stream.close unless stream.closed?
         | 
| 309 296 | 
             
                    in_pipes.first.close unless in_pipes.first.closed?
         | 
| 310 297 | 
             
                  rescue Aborted, Interrupt
         | 
| 311 298 | 
             
                    stream.abort if stream.respond_to?(:abort) && ! stream.aborted?
         | 
| @@ -348,18 +335,32 @@ module Open | |
| 348 335 | 
             
                  end
         | 
| 349 336 | 
             
                end
         | 
| 350 337 |  | 
| 351 | 
            -
                out_pipes.each do |sout|
         | 
| 352 | 
            -
                  ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :pair => stream
         | 
| 353 | 
            -
                end
         | 
| 354 338 | 
             
                Thread.pass until splitter_thread["name"]
         | 
| 355 339 |  | 
| 356 340 | 
             
                main_pipe = out_pipes.first
         | 
| 357 | 
            -
                main_pipe.autojoin = true
         | 
| 358 341 |  | 
| 359 | 
            -
                main_pipe | 
| 360 | 
            -
             | 
| 361 | 
            -
             | 
| 362 | 
            -
             | 
| 342 | 
            +
                ConcurrentStream.setup(main_pipe, :threads => [splitter_thread], :filename => filename, :autojoin => true)
         | 
| 343 | 
            +
             | 
| 344 | 
            +
                out_pipes[1..-1].each do |sout|
         | 
| 345 | 
            +
                  ConcurrentStream.setup sout, :filename => filename, :threads => [splitter_thread]
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                main_pipe.callback = proc do
         | 
| 349 | 
            +
                  begin
         | 
| 350 | 
            +
                    stream.join if stream.respond_to?(:join) && ! stream.joined?
         | 
| 351 | 
            +
                    in_pipes[1..-1].each do |sin|
         | 
| 352 | 
            +
                      sin.close unless sin.closed?
         | 
| 353 | 
            +
                    end
         | 
| 354 | 
            +
                  rescue
         | 
| 355 | 
            +
                    main_pipe.abort_callback.call($!)
         | 
| 356 | 
            +
                    raise $!
         | 
| 357 | 
            +
                  end
         | 
| 358 | 
            +
                end
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                main_pipe.abort_callback = proc do |exception|
         | 
| 361 | 
            +
                  stream.abort(exception)
         | 
| 362 | 
            +
                  out_pipes[1..-1].each do |sout|
         | 
| 363 | 
            +
                    sout.abort(exception)
         | 
| 363 364 | 
             
                  end
         | 
| 364 365 | 
             
                end
         | 
| 365 366 |  | 
| @@ -378,7 +379,7 @@ module Open | |
| 378 379 | 
             
                str = nil
         | 
| 379 380 | 
             
                Thread.pass while IO.select([stream],nil,nil,1).nil?
         | 
| 380 381 | 
             
                while not str = stream.read(size)
         | 
| 381 | 
            -
                  IO.select([stream],nil,nil,1) | 
| 382 | 
            +
                  IO.select([stream],nil,nil,1)
         | 
| 382 383 | 
             
                  Thread.pass
         | 
| 383 384 | 
             
                  raise ClosedStream if stream.eof?
         | 
| 384 385 | 
             
                end
         | 
| @@ -403,102 +404,89 @@ module Open | |
| 403 404 | 
             
                str
         | 
| 404 405 | 
             
              end
         | 
| 405 406 |  | 
| 406 | 
            -
              def self.sort_stream(stream, header_hash  | 
| 407 | 
            -
                Open.open_pipe do |sin|
         | 
| 408 | 
            -
                   | 
| 409 | 
            -
                  while line =~ /^#{header_hash}/ do
         | 
| 410 | 
            -
                    sin.puts line
         | 
| 407 | 
            +
              def self.sort_stream(stream, header_hash: "#", cmd_args: "-u", memory: false)
         | 
| 408 | 
            +
                sout = Open.open_pipe do |sin|
         | 
| 409 | 
            +
                  ConcurrentStream.process_stream(stream) do
         | 
| 411 410 | 
             
                    line = stream.gets
         | 
| 412 | 
            -
             | 
| 411 | 
            +
                    while line && line.start_with?(header_hash) do
         | 
| 412 | 
            +
                      sin.puts line
         | 
| 413 | 
            +
                      line = stream.gets
         | 
| 414 | 
            +
                    end
         | 
| 413 415 |  | 
| 414 | 
            -
             | 
| 415 | 
            -
             | 
| 416 | 
            -
                    begin
         | 
| 416 | 
            +
                    line_stream = Open.open_pipe do |line_stream_in|
         | 
| 417 | 
            +
                      line_stream_in.puts line if line
         | 
| 417 418 | 
             
                      Open.consume_stream(stream, false, line_stream_in)
         | 
| 418 | 
            -
                    rescue
         | 
| 419 | 
            -
                      raise $!
         | 
| 420 419 | 
             
                    end
         | 
| 421 | 
            -
             | 
| 420 | 
            +
                    Log.low "Sub-sort stream #{Log.fingerprint stream} -> #{Log.fingerprint line_stream}"
         | 
| 422 421 |  | 
| 423 | 
            -
             | 
| 424 | 
            -
             | 
| 425 | 
            -
             | 
| 426 | 
            -
             | 
| 427 | 
            -
             | 
| 428 | 
            -
             | 
| 429 | 
            -
             | 
| 430 | 
            -
                      sorted.raise($!) if sorted.respond_to? :raise
         | 
| 431 | 
            -
                      stream.raise($!) if stream.respond_to? :raise
         | 
| 432 | 
            -
                    ensure
         | 
| 433 | 
            -
                      raise $!
         | 
| 422 | 
            +
                    if memory
         | 
| 423 | 
            +
                      line_stream.read.split("\n").sort.each do |line|
         | 
| 424 | 
            +
                        sin.puts line
         | 
| 425 | 
            +
                      end
         | 
| 426 | 
            +
                    else
         | 
| 427 | 
            +
                      io = CMD.cmd("env LC_ALL=C sort #{cmd_args || ""}", :in => line_stream, :pipe => true)
         | 
| 428 | 
            +
                      Open.consume_stream(io, false, sin)
         | 
| 434 429 | 
             
                    end
         | 
| 435 430 | 
             
                  end
         | 
| 436 431 | 
             
                end
         | 
| 432 | 
            +
                Log.low "Sort #{Log.fingerprint stream} -> #{Log.fingerprint sout}"
         | 
| 433 | 
            +
                sout
         | 
| 437 434 | 
             
              end
         | 
| 438 435 |  | 
| 439 | 
            -
              def self. | 
| 440 | 
            -
             | 
| 441 | 
            -
             | 
| 442 | 
            -
                  s.close if s.respond_to?(:close) && ! s.closed?
         | 
| 443 | 
            -
                  s.join if s.respond_to?(:join)
         | 
| 444 | 
            -
                rescue
         | 
| 445 | 
            -
                  s.abort($!) if s.respond_to? :abort
         | 
| 446 | 
            -
                  raise $!
         | 
| 447 | 
            -
                end
         | 
| 448 | 
            -
              end
         | 
| 449 | 
            -
             | 
| 436 | 
            +
              #def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
         | 
| 437 | 
            +
              #  StringIO.new stream.read.split("\n").sort.uniq * "\n"
         | 
| 438 | 
            +
              #end
         | 
| 450 439 |  | 
| 451 440 | 
             
              def self.collapse_stream(s, line: nil, sep: "\t", header: nil, &block)
         | 
| 452 441 | 
             
                sep ||= "\t"
         | 
| 453 442 | 
             
                Open.open_pipe do |sin|
         | 
| 443 | 
            +
             | 
| 454 444 | 
             
                  sin.puts header if header
         | 
| 455 | 
            -
                  process_stream(s) do |s|
         | 
| 456 | 
            -
                    line ||= s.gets
         | 
| 457 445 |  | 
| 458 | 
            -
             | 
| 459 | 
            -
             | 
| 460 | 
            -
             | 
| 461 | 
            -
             | 
| 462 | 
            -
             | 
| 463 | 
            -
             | 
| 464 | 
            -
             | 
| 465 | 
            -
             | 
| 466 | 
            -
                       | 
| 467 | 
            -
             | 
| 468 | 
            -
             | 
| 469 | 
            -
             | 
| 470 | 
            -
             | 
| 471 | 
            -
             | 
| 472 | 
            -
             | 
| 446 | 
            +
                  line ||= s.gets
         | 
| 447 | 
            +
             | 
| 448 | 
            +
                  current_parts = []
         | 
| 449 | 
            +
                  while line
         | 
| 450 | 
            +
                    key, *parts = line.chomp.split(sep, -1)
         | 
| 451 | 
            +
                    case
         | 
| 452 | 
            +
                    when key.nil?
         | 
| 453 | 
            +
                    when current_parts.nil?
         | 
| 454 | 
            +
                      current_parts = parts
         | 
| 455 | 
            +
                      current_key = key
         | 
| 456 | 
            +
                    when current_key == key
         | 
| 457 | 
            +
                      parts.each_with_index do |part,i|
         | 
| 458 | 
            +
                        if current_parts[i].nil?
         | 
| 459 | 
            +
                          current_parts[i] = "|" << part
         | 
| 460 | 
            +
                        else
         | 
| 461 | 
            +
                          current_parts[i] = current_parts[i] << "|" << part
         | 
| 473 462 | 
             
                        end
         | 
| 463 | 
            +
                      end
         | 
| 474 464 |  | 
| 475 | 
            -
             | 
| 476 | 
            -
             | 
| 477 | 
            -
                        end
         | 
| 478 | 
            -
                      when current_key.nil?
         | 
| 479 | 
            -
                        current_key = key
         | 
| 480 | 
            -
                        current_parts = parts
         | 
| 481 | 
            -
                      when current_key != key
         | 
| 482 | 
            -
                        if block_given?
         | 
| 483 | 
            -
                          res = block.call(current_parts)
         | 
| 484 | 
            -
                          sin.puts [current_key, res] * sep
         | 
| 485 | 
            -
                        else
         | 
| 486 | 
            -
                          sin.puts [current_key, current_parts].flatten * sep
         | 
| 487 | 
            -
                        end 
         | 
| 488 | 
            -
                        current_key = key
         | 
| 489 | 
            -
                        current_parts = parts
         | 
| 465 | 
            +
                      (parts.length..current_parts.length-1).to_a.each do |pos|
         | 
| 466 | 
            +
                        current_parts[pos] = current_parts[pos] << "|" << ""
         | 
| 490 467 | 
             
                      end
         | 
| 491 | 
            -
             | 
| 468 | 
            +
                    when current_key.nil?
         | 
| 469 | 
            +
                      current_key = key
         | 
| 470 | 
            +
                      current_parts = parts
         | 
| 471 | 
            +
                    when current_key != key
         | 
| 472 | 
            +
                      if block_given?
         | 
| 473 | 
            +
                        res = block.call(current_parts)
         | 
| 474 | 
            +
                        sin.puts [current_key, res] * sep
         | 
| 475 | 
            +
                      else
         | 
| 476 | 
            +
                        sin.puts [current_key, current_parts].flatten * sep
         | 
| 477 | 
            +
                      end
         | 
| 478 | 
            +
                      current_key = key
         | 
| 479 | 
            +
                      current_parts = parts
         | 
| 492 480 | 
             
                    end
         | 
| 493 | 
            -
             | 
| 494 | 
            -
                    if block_given?
         | 
| 495 | 
            -
                      res = block.call(current_parts)
         | 
| 496 | 
            -
                      sin.puts [current_key, res] * sep
         | 
| 497 | 
            -
                    else
         | 
| 498 | 
            -
                      sin.puts [current_key, current_parts].flatten * sep
         | 
| 499 | 
            -
                    end unless current_key.nil?
         | 
| 481 | 
            +
                    line = s.gets
         | 
| 500 482 | 
             
                  end
         | 
| 483 | 
            +
             | 
| 484 | 
            +
                  if block_given?
         | 
| 485 | 
            +
                    res = block.call(current_parts)
         | 
| 486 | 
            +
                    sin.puts [current_key, res] * sep
         | 
| 487 | 
            +
                  else
         | 
| 488 | 
            +
                    sin.puts [current_key, current_parts].flatten * sep
         | 
| 489 | 
            +
                  end unless current_key.nil?
         | 
| 501 490 | 
             
                end
         | 
| 502 491 | 
             
              end
         | 
| 503 | 
            -
             | 
| 504 492 | 
             
            end
         | 
    
        data/lib/scout/open/util.rb
    CHANGED
    
    | @@ -68,6 +68,15 @@ module Open | |
| 68 68 | 
             
                !! (file =~ /\.zip$/)
         | 
| 69 69 | 
             
              end
         | 
| 70 70 |  | 
| 71 | 
            +
              def self.is_stream?(obj)
         | 
| 72 | 
            +
                IO === obj || StringIO === obj
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def self.has_stream?(obj)
         | 
| 76 | 
            +
                obj.respond_to?(:stream)
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
             | 
| 71 80 | 
             
              def self.notify_write(file)
         | 
| 72 81 | 
             
                begin
         | 
| 73 82 | 
             
                  notification_file = file + '.notify'
         | 
    
        data/lib/scout/open.rb
    CHANGED
    
    | @@ -21,6 +21,8 @@ module Open | |
| 21 21 | 
             
              end
         | 
| 22 22 |  | 
| 23 23 | 
             
              def self.get_stream(file, mode = 'r')
         | 
| 24 | 
            +
                return file if Open.is_stream?(file)
         | 
| 25 | 
            +
                return file.stream if Open.has_stream?(file)
         | 
| 24 26 | 
             
                file = file.find if Path === file
         | 
| 25 27 |  | 
| 26 28 | 
             
                return Open.ssh(file) if Open.ssh?(file)
         | 
| @@ -56,11 +58,11 @@ module Open | |
| 56 58 | 
             
              def self.open(file, options = {})
         | 
| 57 59 | 
             
                if IO === file || StringIO === file
         | 
| 58 60 | 
             
                  if block_given?
         | 
| 59 | 
            -
                    res = yield file | 
| 61 | 
            +
                    res = yield file
         | 
| 60 62 | 
             
                    file.close
         | 
| 61 63 | 
             
                    return res
         | 
| 62 64 | 
             
                  else
         | 
| 63 | 
            -
                    return file | 
| 65 | 
            +
                    return file
         | 
| 64 66 | 
             
                  end
         | 
| 65 67 | 
             
                end
         | 
| 66 68 |  | 
| @@ -163,7 +165,6 @@ module Open | |
| 163 165 | 
             
                  raise "Content unknown #{Log.fingerprint content}"
         | 
| 164 166 | 
             
                end
         | 
| 165 167 |  | 
| 166 | 
            -
                notify_write(file) | 
| 168 | 
            +
                notify_write(file)
         | 
| 167 169 | 
             
              end
         | 
| 168 | 
            -
             | 
| 169 170 | 
             
            end
         | 
    
        data/lib/scout/path/find.rb
    CHANGED
    
    | @@ -34,6 +34,7 @@ module Path | |
| 34 34 |  | 
| 35 35 | 
             
              def self.follow(path, map, map_name = nil)
         | 
| 36 36 | 
             
                file = map.sub('{PKGDIR}', path.pkgdir.respond_to?(:pkgdir) ? path.pkgdir.pkgdir || Path.default_pkgdir : path.pkgdir || Path.default_pkgdir).
         | 
| 37 | 
            +
                  sub('{HOME}', ENV["HOME"]).
         | 
| 37 38 | 
             
                  sub('{RESOURCE}', path.pkgdir.to_s).
         | 
| 38 39 | 
             
                  sub('{PWD}', FileUtils.pwd).
         | 
| 39 40 | 
             
                  sub('{TOPLEVEL}', path._toplevel).
         | 
| @@ -59,16 +60,17 @@ module Path | |
| 59 60 |  | 
| 60 61 | 
             
              def self.path_maps
         | 
| 61 62 | 
             
                @@path_maps ||= IndiferentHash.setup({
         | 
| 62 | 
            -
                  :current =>  | 
| 63 | 
            -
                  :user    =>  | 
| 64 | 
            -
                  :global  =>  | 
| 65 | 
            -
                  :usr     =>  | 
| 66 | 
            -
                  :local   =>  | 
| 67 | 
            -
                  :fast    =>  | 
| 68 | 
            -
                  :cache   =>  | 
| 69 | 
            -
                  :bulk    =>  | 
| 70 | 
            -
                  :lib     =>  | 
| 71 | 
            -
                  : | 
| 63 | 
            +
                  :current => "{PWD}/{TOPLEVEL}/{SUBPATH}",
         | 
| 64 | 
            +
                  :user    => "{HOME}/.{PKGDIR}/{TOPLEVEL}/{SUBPATH}",
         | 
| 65 | 
            +
                  :global  => '/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 66 | 
            +
                  :usr     => '/usr/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 67 | 
            +
                  :local   => '/usr/local/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 68 | 
            +
                  :fast    => '/fast/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 69 | 
            +
                  :cache   => '/cache/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 70 | 
            +
                  :bulk    => '/bulk/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
         | 
| 71 | 
            +
                  :lib     => '{LIBDIR}/{TOPLEVEL}/{SUBPATH}',
         | 
| 72 | 
            +
                  :scout_gear => File.join(Path.caller_lib_dir(__FILE__), "{TOPLEVEL}/{SUBPATH}"),
         | 
| 73 | 
            +
                  :tmp     => '/tmp/{PKGDIR}/{TOPLEVEL}/{SUBPATH}',
         | 
| 72 74 | 
             
                  :default => :user
         | 
| 73 75 | 
             
                })
         | 
| 74 76 | 
             
              end
         | 
| @@ -127,6 +129,9 @@ module Path | |
| 127 129 | 
             
              def follow(map_name = :default, annotate = true)
         | 
| 128 130 | 
             
                IndiferentHash.setup(path_maps)
         | 
| 129 131 | 
             
                map = path_maps[map_name] || Path.path_maps[map_name]
         | 
| 132 | 
            +
                if map.nil? && String === map_name
         | 
| 133 | 
            +
                  map = File.join(map_name, '{TOPLEVEL}/{SUBPATH}')
         | 
| 134 | 
            +
                end
         | 
| 130 135 | 
             
                raise "Map not found #{Log.fingerprint map_name} not in #{Log.fingerprint path_maps.keys}" if map.nil?
         | 
| 131 136 | 
             
                while Symbol === map
         | 
| 132 137 | 
             
                  map_name = map
         | 
    
        data/lib/scout/path/util.rb
    CHANGED
    
    | @@ -82,6 +82,11 @@ module Path | |
| 82 82 | 
             
                self.annotate(self + ".#{extension}")
         | 
| 83 83 | 
             
              end
         | 
| 84 84 |  | 
| 85 | 
            +
              def unset_extension
         | 
| 86 | 
            +
                self.annotate(self.split(".")[0..-2] * ".")
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
             | 
| 85 90 | 
             
              # Is 'file' newer than 'path'? return non-true if path is newer than file
         | 
| 86 91 | 
             
              def self.newer?(path, file, by_link = false)
         | 
| 87 92 | 
             
                return true if not Open.exists?(file)
         | 
| @@ -20,7 +20,7 @@ module Persist | |
| 20 20 | 
             
                type = type.to_sym if String === type
         | 
| 21 21 | 
             
                type = SERIALIZER if type == :serializer
         | 
| 22 22 | 
             
                case type
         | 
| 23 | 
            -
                when nil, :string, :integer, :float, :boolean, :file, :path, :select, :folder
         | 
| 23 | 
            +
                when nil, :string, :text, :integer, :float, :boolean, :file, :path, :select, :folder, :binary
         | 
| 24 24 | 
             
                  if IO === content || StringIO === content
         | 
| 25 25 | 
             
                    content.read
         | 
| 26 26 | 
             
                  else
         | 
| @@ -49,7 +49,7 @@ module Persist | |
| 49 49 | 
             
                type = SERIALIZER if type == :serializer
         | 
| 50 50 |  | 
| 51 51 | 
             
                case type
         | 
| 52 | 
            -
                when nil, :string, :file, :stream, :select, :folder
         | 
| 52 | 
            +
                when nil, :string, :text, :file, :stream, :select, :folder
         | 
| 53 53 | 
             
                  serialized
         | 
| 54 54 | 
             
                when :path
         | 
| 55 55 | 
             
                  Path.setup(serialized)
         | 
| @@ -58,7 +58,7 @@ module Persist | |
| 58 58 | 
             
                when :float
         | 
| 59 59 | 
             
                  serialized.to_f
         | 
| 60 60 | 
             
                when :boolean
         | 
| 61 | 
            -
                  TRUE_STRINGS.include? serialized
         | 
| 61 | 
            +
                  TRUE_STRINGS.include? serialized.strip
         | 
| 62 62 | 
             
                when :array
         | 
| 63 63 | 
             
                  serialized.split("\n")
         | 
| 64 64 | 
             
                when :yaml
         | 
    
        data/lib/scout/persist.rb
    CHANGED