scout-gear 5.1.1 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +10 -4
  3. data/Rakefile +2 -0
  4. data/VERSION +1 -1
  5. data/bin/scout +2 -0
  6. data/lib/scout/meta_extension.rb +4 -2
  7. data/lib/scout/misc/format.rb +16 -4
  8. data/lib/scout/misc/monitor.rb +23 -0
  9. data/lib/scout/misc.rb +1 -0
  10. data/lib/scout/open/stream.rb +1 -0
  11. data/lib/scout/path/find.rb +2 -1
  12. data/lib/scout/path.rb +1 -1
  13. data/lib/scout/persist/serialize.rb +15 -4
  14. data/lib/scout/resource/path.rb +5 -0
  15. data/lib/scout/resource/util.rb +48 -0
  16. data/lib/scout/resource.rb +2 -0
  17. data/lib/scout/simple_opt/doc.rb +26 -2
  18. data/lib/scout/workflow/definition.rb +8 -2
  19. data/lib/scout/workflow/documentation.rb +32 -26
  20. data/lib/scout/workflow/step/info.rb +11 -11
  21. data/lib/scout/workflow/step/load.rb +18 -0
  22. data/lib/scout/workflow/step.rb +40 -4
  23. data/lib/scout/workflow/task/inputs.rb +4 -2
  24. data/lib/scout/workflow/task.rb +15 -1
  25. data/lib/scout/workflow/usage.rb +96 -76
  26. data/lib/scout/workflow.rb +1 -0
  27. data/scout-gear.gemspec +14 -3
  28. data/scout_commands/workflow/info +29 -0
  29. data/scout_commands/workflow/list +27 -0
  30. data/scout_commands/workflow/task +32 -681
  31. data/scout_commands/workflow/task_old +706 -0
  32. data/test/scout/resource/test_util.rb +27 -0
  33. data/test/scout/simple_opt/test_doc.rb +16 -0
  34. data/test/scout/test_meta_extension.rb +9 -0
  35. data/test/scout/workflow/step/test_info.rb +17 -15
  36. data/test/scout/workflow/step/test_load.rb +65 -0
  37. data/test/scout/workflow/test_definition.rb +0 -0
  38. data/test/scout/workflow/test_documentation.rb +30 -0
  39. data/test/scout/workflow/test_task.rb +1 -0
  40. data/test/scout/workflow/test_usage.rb +12 -3
  41. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '070801d66b058318a5be03704b424158222038331dac4d7984fab415ca1680ee'
4
- data.tar.gz: e58bcd314c0fa55acb722d12f8e77e69ade25f182501823db9a14691eaf3a887
3
+ metadata.gz: c39189bc9fe8816a3c0494c78966486f28383e8e15bf38ab33fe4dcde6739f3c
4
+ data.tar.gz: 5f2753e6810a68be44589f9392de1eff2f8592dd2704b05a0ccdf866f07f6a1b
5
5
  SHA512:
6
- metadata.gz: 81146847ebd0802456b42f152d2fe6e96d1a4ab434b20111afd2f9bd2bf7e1006d8ce2108ba22db78ae65e23ba7e69d6e4e28543aaa3c55a0482727b2472ed7c
7
- data.tar.gz: 59d1574833255c0336472a5297bb00e21319b044bca684b018512557de65cc8ff34091b2bc9adcd5f4758833793cb0b4a8092927835a328f76170fa8c60be115
6
+ metadata.gz: 820d17306f468e7b206672b717489f78eb6fbfa37c843441202ce124c54cb7b84b89062a951c14a2db65ada47faf073dbc6a1b863294388ce66a8c1f7dd36e9f
7
+ data.tar.gz: c0fe23608355128c0e709db78c5598c5ece26e885eaa8788872878b7d55e29fc50bcb8215d3b4080f9e8d89456630e2739b087ee7d8b4b57498b299df3dc89d2
data/.vimproject CHANGED
@@ -1,16 +1,19 @@
1
1
  scout-gear=/$PWD filter="*.rb *.yaml" {
2
2
  Rakefile
3
- bin=bin filter="*"{
3
+ bin=bin filter="*"{
4
4
  scout
5
- scout_rbbt
6
5
  }
7
6
  scout_commands=scout_commands filter="*"{
7
+ rbbt
8
+ alias
8
9
  find
9
10
  glob
10
11
  workflow=workflow{
12
+ task_old
11
13
  task
14
+ list
15
+ info
12
16
  }
13
- alias
14
17
  }
15
18
  lib=lib {
16
19
  scout-gear.rb
@@ -26,6 +29,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
26
29
  insist.rb
27
30
  digest.rb
28
31
  filesystem.rb
32
+ monitor.rb
29
33
  }
30
34
  indiferent_hash.rb
31
35
  indiferent_hash=indiferent_hash{
@@ -73,8 +77,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
73
77
  produce=produce{
74
78
  rake.rb
75
79
  }
76
- path.rb
77
80
  scout.rb
81
+ util.rb
82
+ path.rb
78
83
  }
79
84
  persist.rb
80
85
  persist=persist{
@@ -88,6 +93,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
88
93
  step.rb
89
94
  step=step{
90
95
  info.rb
96
+ load.rb
91
97
  }
92
98
  task.rb
93
99
  task=task{
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
+ ENV["BRANCH"] = 'main'
4
+
3
5
  require 'rubygems'
4
6
  require 'rake'
5
7
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.1.1
1
+ 5.2.0
data/bin/scout CHANGED
@@ -39,6 +39,8 @@ if dev_dir
39
39
  end
40
40
  end
41
41
 
42
+ Log.nocolor = true if ARGV.include? "--nocolor"
43
+
42
44
  require 'scout/simple_opt'
43
45
 
44
46
  options = SOPT.setup <<EOF
@@ -24,8 +24,10 @@ module MetaExtension
24
24
  return if attrs.nil? || attrs.empty?
25
25
 
26
26
  if rest.length == 1 && Hash === (rlast = rest.last) &&
27
- ! (rlkey = rlast.keys.first).nil? &&
28
- attrs.include?(rlkey.to_sym)
27
+ ((! (rlkey = rlast.keys.first).nil? && attrs.include?(rlkey.to_sym)) ||
28
+ (! attrs.length != 1 ))
29
+
30
+
29
31
 
30
32
  pairs = rlast
31
33
  else
@@ -25,7 +25,14 @@ module Misc
25
25
  str
26
26
  end
27
27
 
28
- def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
28
+
29
+ MAX_WIDTH = 100
30
+ def self.format_paragraph(text, size = nil, indent = nil, offset = nil)
31
+ size ||= Log.tty_size || MAX_WIDTH
32
+ size = MAX_WIDTH if size > MAX_WIDTH
33
+ indent ||= 0
34
+ offset ||= 0
35
+
29
36
  i = 0
30
37
  size = size + offset + indent
31
38
  re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
@@ -55,7 +62,10 @@ module Misc
55
62
  end*""
56
63
  end
57
64
 
58
- def self.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow)
65
+ def self.format_definition_list_item(dt, dd, indent = nil, size = nil, color = :yellow)
66
+ size ||= Log.tty_size || MAX_WIDTH
67
+ size = MAX_WIDTH if size > MAX_WIDTH
68
+ indent ||= size / 3
59
69
  dd = "" if dd.nil?
60
70
  dt = Log.color color, dt if color
61
71
  dt = dt.to_s unless dd.empty?
@@ -73,10 +83,12 @@ module Misc
73
83
  text
74
84
  end
75
85
 
76
- def self.format_definition_list(defs, size = 80, indent = 20, color = :yellow, sep = "\n\n")
86
+ def self.format_definition_list(defs, indent = nil, size = nil, color = :yellow, sep = "\n\n")
87
+ size ||= Log.tty_size || MAX_WIDTH
88
+ indent ||= 30
77
89
  entries = []
78
90
  defs.each do |dt,dd|
79
- text = format_definition_list_item(dt,dd,size,indent,color)
91
+ text = format_definition_list_item(dt,dd,indent, size,color)
80
92
  entries << text
81
93
  end
82
94
  entries * sep
@@ -0,0 +1,23 @@
1
+ module Misc
2
+ def self.benchmark(repeats = 1, message = nil)
3
+ require 'benchmark'
4
+ res = nil
5
+ begin
6
+ measure = Benchmark.measure do
7
+ repeats.times do
8
+ res = yield
9
+ end
10
+ end
11
+ if message
12
+ puts "#{message }: #{ repeats } repeats"
13
+ else
14
+ puts "Benchmark for #{ repeats } repeats"
15
+ end
16
+ puts measure
17
+ rescue Exception
18
+ puts "Benchmark aborted"
19
+ raise $!
20
+ end
21
+ res
22
+ end
23
+ end
data/lib/scout/misc.rb CHANGED
@@ -2,6 +2,7 @@ require_relative 'misc/format'
2
2
  require_relative 'misc/insist'
3
3
  require_relative 'misc/digest'
4
4
  require_relative 'misc/filesystem'
5
+ require_relative 'misc/monitor'
5
6
 
6
7
  module Misc
7
8
  end
@@ -68,6 +68,7 @@ module Open
68
68
  block.call if block_given?
69
69
 
70
70
  Log.high "Done consuming stream #{Log.fingerprint io} into #{into_path || into}"
71
+ c
71
72
  rescue Aborted
72
73
  Log.high "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
73
74
  io.abort $! if io.respond_to? :abort
@@ -123,7 +123,7 @@ module Path
123
123
 
124
124
  def follow(map_name = :default, annotate = true)
125
125
  IndiferentHash.setup(path_maps)
126
- map = path_maps[map_name]
126
+ map = path_maps[map_name] || Path.path_maps[map_name]
127
127
  raise "Map not found #{Log.fingerprint map_name} not in #{Log.fingerprint path_maps.keys}" if map.nil?
128
128
  while Symbol === map
129
129
  map_name = map
@@ -163,4 +163,5 @@ module Path
163
163
  .collect{|where| find(where) }
164
164
  .select{|file| file.exist? }.uniq
165
165
  end
166
+
166
167
  end
data/lib/scout/path.rb CHANGED
@@ -24,7 +24,7 @@ module Path
24
24
  end
25
25
 
26
26
  def path_maps
27
- @path_maps ||= Path.path_maps
27
+ @path_maps ||= Path.path_maps.dup
28
28
  end
29
29
 
30
30
  def join(subpath, prevpath = nil)
@@ -3,6 +3,7 @@ require_relative 'open'
3
3
 
4
4
  module Persist
5
5
  TRUE_STRINGS = Set.new ["true", "True", "TRUE", "t", "T", "1", "yes", "Yes", "YES", "y", "Y", "ON", "on"] unless defined? TRUE_STRINGS
6
+ SERIALIZER = :json
6
7
 
7
8
  class << self
8
9
  attr_accessor :save_drivers, :load_drivers
@@ -15,6 +16,8 @@ module Persist
15
16
  end
16
17
 
17
18
  def self.serialize(content, type)
19
+ type = type.to_sym if String === type
20
+ type = SERIALIZER if type == :serializer
18
21
  case type
19
22
  when nil, :string, :integer, :float, :boolean, :file, :path
20
23
  if IO === content || StringIO === content
@@ -28,7 +31,7 @@ module Persist
28
31
  content.to_yaml
29
32
  when :json
30
33
  content.to_json
31
- when :marshal, :serializer
34
+ when :marshal
32
35
  Marshal.dump(content)
33
36
  else
34
37
  if m = type.to_s.match(/(.*)_array/)
@@ -41,6 +44,8 @@ module Persist
41
44
  end
42
45
 
43
46
  def self.deserialize(serialized, type)
47
+ type = type.to_sym if String === type
48
+ type = SERIALIZER if type == :serializer
44
49
  case type
45
50
  when nil, :string, :file, :stream
46
51
  serialized
@@ -58,7 +63,7 @@ module Persist
58
63
  YAML.parse(serialized)
59
64
  when :json
60
65
  JSON.parse(serialized)
61
- when :marshal, :serializer
66
+ when :marshal
62
67
  Marshal.load(serialized)
63
68
  else
64
69
  if m = type.to_s.match(/(.*)_array/)
@@ -73,6 +78,10 @@ module Persist
73
78
 
74
79
  MEMORY = {}
75
80
  def self.save(content, file, type = :serializer)
81
+ type = :serializer if type.nil?
82
+ type = type.to_sym if String === type
83
+ type = SERIALIZER if type == :serializer
84
+ type = MEMORY if type == :memory
76
85
  return if content.nil?
77
86
  type = MEMORY if type == :memory
78
87
  type = :serializer if type.nil?
@@ -97,16 +106,18 @@ module Persist
97
106
  ConcurrentStream.setup copy, :threads => t, :filename => file, :autojoin => true
98
107
  else
99
108
  serialized = serialize(content, type)
100
- Open.sensible_write(file, serialized)
109
+ Open.sensible_write(file, serialized, :force => true)
101
110
  content
102
111
  end
103
112
  end
104
113
 
105
114
  def self.load(file, type = :serializer)
106
115
  file = file.find if Path === file
116
+ type = :serializer if type.nil?
117
+ type = type.to_sym if String === type
118
+ type = SERIALIZER if type == :serializer
107
119
  type = MEMORY if type == :memory
108
120
  return unless Hash === type || Open.exist?(file)
109
- type = :serializer if type.nil?
110
121
 
111
122
  Log.debug "Load #{Log.fingerprint type} on #{file}"
112
123
  if load_drivers[type]
@@ -1,4 +1,9 @@
1
1
  module Path
2
+ def relocate
3
+ return self if Open.exists?(self)
4
+ Resource.relocate(self)
5
+ end
6
+
2
7
  def open(*args, &block)
3
8
  produce
4
9
  Open.open(self, *args, &block)
@@ -0,0 +1,48 @@
1
+ module Resource
2
+ def identify(path)
3
+ return path unless path.start_with?("/")
4
+ path_maps = path.path_maps || self.path_maps || Path.path_maps
5
+ path = File.expand_path(path)
6
+ path += "/" if File.directory?(path)
7
+
8
+ map_order ||= (path_maps.keys & Path.basic_map_order) + (path_maps.keys - Path.basic_map_order)
9
+ map_order -= [:current, "current"]
10
+ map_order << :current
11
+
12
+ choices = []
13
+ map_order.uniq.each do |name|
14
+ pattern = path_maps[name]
15
+ pattern = path_maps[pattern] while Symbol === pattern
16
+ next if pattern.nil?
17
+
18
+ pattern = pattern.sub('{PWD}', Dir.pwd)
19
+ if String === pattern and pattern.include?('{')
20
+ regexp = "^" + pattern
21
+ .gsub(/{(TOPLEVEL)}/,'(?<\1>[^/]+)')
22
+ .gsub(/{([^}]+)}/,'(?<\1>[^/]+)?') +
23
+ "(?:/(?<REST>.*))?/?$"
24
+ if m = path.match(regexp)
25
+ if ! m.named_captures.include?("PKGDIR") || m["PKGDIR"] == self.pkgdir
26
+ unlocated = %w(TOPLEVEL SUBPATH PATH REST).collect{|c|
27
+ m.named_captures.include?(c) ? m[c] : nil
28
+ }.compact * "/"
29
+ unlocated.gsub!(/\/+/,'/')
30
+ unlocated[self.subdir] = "" if self.subdir
31
+ choices << self.annotate(unlocated)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ Path.setup(choices.sort_by{|s| s.length }.first, self, nil, path_maps)
38
+ end
39
+
40
+ def self.relocate(path)
41
+ return path if Open.exists?(path)
42
+ resource = path.pkgdir if Path === path
43
+ resource = Scout unless Resource === resource
44
+ unlocated = resource.identify path
45
+ unlocated.find
46
+ end
47
+ end
48
+
@@ -1,6 +1,8 @@
1
1
  require_relative 'log'
2
2
  require_relative 'path'
3
3
  require_relative 'resource/produce'
4
+ require_relative 'resource/path'
5
+ require_relative 'resource/util'
4
6
 
5
7
  module Resource
6
8
  extend MetaExtension
@@ -42,10 +42,33 @@ module SOPT
42
42
  "=<#{ type }>"
43
43
  end
44
44
  #extra << " (default: #{Array === default ? (default.length > 3 ? default[0..2]*", " + ', ...' : default*", " ): default})" if default != nil
45
- extra << " (default: #{Misc.fingerprint(default)})" if default != nil
45
+ extra << " (default: #{Log.fingerprint(default)})" if default != nil
46
46
  input_str << Log.color(:green, extra)
47
47
  end
48
48
 
49
+ def self.input_array_doc(input_array)
50
+ input_array.collect do |name,type,description,default,options|
51
+ type = :string if type.nil?
52
+
53
+ name = name.to_s
54
+ shortcut, options = options, nil if String === options || Symbol === options
55
+
56
+ case options && options[:shortcut]
57
+ when FalseClass
58
+ shortcut = nil
59
+ when TrueClass, nil
60
+ shortcut = fix_shortcut(name[0], name)
61
+ else
62
+ shortcut = options[:shortcut]
63
+ end unless shortcut
64
+
65
+ shortcut = fix_shortcut(shortcut, name)
66
+ register(shortcut, name, type, description) unless self.inputs.include? name
67
+ name = SOPT.input_format(name, type.to_sym, default, shortcut )
68
+ Misc.format_definition_list_item(name, description)
69
+ end * "\n"
70
+ end
71
+
49
72
  def self.input_doc(inputs, input_types = nil, input_descriptions = nil, input_defaults = nil, input_shortcuts = nil)
50
73
  type = description = default = nil
51
74
  shortcut = ""
@@ -73,10 +96,11 @@ module SOPT
73
96
  register(shortcut, name, type, description) unless self.inputs.include? name
74
97
 
75
98
  name = SOPT.input_format(name, type.to_sym, default, shortcut)
76
- Misc.format_definition_list_item(name, description, 80, 31, nil)
99
+ Misc.format_definition_list_item(name, description)
77
100
  end * "\n"
78
101
  end
79
102
 
103
+
80
104
  def self.doc
81
105
  doc =<<-EOF
82
106
  #{Log.color :magenta}#{command}(1) -- #{summary}
@@ -33,6 +33,11 @@ module Workflow
33
33
  @annotate_next_task[type] << obj
34
34
  end
35
35
 
36
+ def annotate_next_task_single(type, obj)
37
+ @annotate_next_task ||= {}
38
+ @annotate_next_task[type] = obj
39
+ end
40
+
36
41
  def dep(*args, &block)
37
42
  case args.length
38
43
  when 3
@@ -60,13 +65,14 @@ module Workflow
60
65
  @tasks ||= IndiferentHash.setup({})
61
66
  begin
62
67
  @annotate_next_task ||= {}
63
- @tasks[name] = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name]))
68
+ task = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name]))
69
+ @tasks[name] = task
64
70
  ensure
65
71
  @annotate_next_task = {}
66
72
  end
67
73
  end
68
74
 
69
75
  def desc(description)
70
- annotate_next_task(:desc, description)
76
+ annotate_next_task_single(:description, description)
71
77
  end
72
78
  end
@@ -1,4 +1,5 @@
1
1
  module Workflow
2
+ attr_accessor :title, :description
2
3
 
3
4
  def self.doc_parse_first_line(str)
4
5
  if str.match(/^([^\n]*)\n\n(.*)/sm)
@@ -45,33 +46,38 @@ module Workflow
45
46
  end
46
47
  end
47
48
 
48
- def load_documentation
49
- return if @documentation
50
- @documentation ||= Workflow.parse_workflow_doc documentation_markdown
51
- @documentation[:tasks].each do |task, description|
52
- if task.include? "#"
53
- workflow, task = task.split("#")
54
- workflow = begin
55
- Kernel.const_get workflow
56
- rescue
57
- next
58
- end
59
- else
60
- workflow = self
61
- end
62
-
63
- task = task.to_sym
64
- if workflow.tasks.include? task
65
- workflow.tasks[task].description = description
66
- else
67
- Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
68
- end
69
- end
70
- end
71
-
72
49
  attr_accessor :documentation
73
50
  def documentation
74
- load_documentation if @documentation.nil?
75
- @documentation
51
+ @documentation ||= begin
52
+ documentation = Workflow.parse_workflow_doc documentation_markdown
53
+
54
+ if @description && (documentation[:description].nil? || documentation[:description].empty?)
55
+ documentation[:description] = @description
56
+ end
57
+
58
+ if @title && (documentation[:title].nil? || documentation[:title].empty?)
59
+ documentation[:title] = @title
60
+ end
61
+ documentation[:tasks].each do |task, description|
62
+ if task.include? "#"
63
+ workflow, task = task.split("#")
64
+ workflow = begin
65
+ Kernel.const_get workflow
66
+ rescue
67
+ next
68
+ end
69
+ else
70
+ workflow = self
71
+ end
72
+
73
+ task = task.to_sym
74
+ if workflow.tasks.include? task
75
+ workflow.tasks[task].description = description
76
+ else
77
+ Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
78
+ end
79
+ end
80
+ documentation
81
+ end
76
82
  end
77
83
  end
@@ -1,15 +1,21 @@
1
1
  class Step
2
+ SERIALIZER = :json
2
3
  def info_file
3
- @info_file ||= @path + ".info"
4
+ @info_file ||= begin
5
+ info_file = @path + ".info"
6
+ @path.annotate info_file if Path === @path
7
+ info_file
8
+ end
4
9
  end
5
10
 
6
11
  def load_info
7
- @info = Persist.load(info_file, :marshal) || {}
12
+ @info = Persist.load(info_file, SERIALIZER) || {}
13
+ IndiferentHash.setup(@info)
8
14
  @info_load_time = Time.now
9
15
  end
10
16
 
11
- def save_info
12
- Persist.save(@info, info_file, :marshal)
17
+ def save_info(info = nil)
18
+ Persist.save(info, info_file, SERIALIZER)
13
19
  @info_load_time = Time.now
14
20
  end
15
21
 
@@ -40,19 +46,13 @@ class Step
40
46
  info[key] = value
41
47
  end
42
48
  end
43
- save_info
49
+ save_info(info)
44
50
  end
45
51
 
46
52
  def set_info(key, value)
47
53
  merge_info(key => value)
48
54
  end
49
55
 
50
- def init_info
51
- @info = {
52
- :status => :waiting
53
- }
54
- end
55
-
56
56
  def report_status(status, message = nil)
57
57
  if message.nil?
58
58
  Log.info Log.color(:green, status.to_s) + " " + Log.color(:blue, path)
@@ -0,0 +1,18 @@
1
+ class Step
2
+ def self.relocate(path)
3
+ return path if Open.exists?(path)
4
+ Path.setup(path) unless Path === path
5
+ relocated = path.relocate
6
+ return relocated if Open.exists?(relocated)
7
+ subpath = path.split("/")[-3..-1] * "/"
8
+ relocated = Path.setup("var/jobs")[subpath]
9
+ return relocated if Open.exists?(relocated)
10
+ path
11
+ end
12
+
13
+ def self.load(path)
14
+ path = relocate(path) unless Open.exists?(path)
15
+ raise "Could not load #{path}" unless Open.exists?(path)
16
+ s = Step.new path
17
+ end
18
+ end
@@ -1,20 +1,43 @@
1
1
  require_relative '../path'
2
2
  require_relative '../persist'
3
3
  require_relative 'step/info'
4
+ require_relative 'step/load'
4
5
 
5
6
  class Step
6
7
 
7
8
  attr_accessor :path, :inputs, :dependencies, :task
8
- def initialize(path, inputs = nil, dependencies = [], &task)
9
+ def initialize(path, inputs = nil, dependencies = nil, &task)
9
10
  @path = path
10
11
  @inputs = inputs
11
12
  @dependencies = dependencies
12
13
  @task = task
13
14
  end
14
15
 
16
+ def inputs
17
+ @inputs ||= begin
18
+ if Open.exists?(info_file)
19
+ info[:inputs]
20
+ else
21
+ []
22
+ end
23
+ end
24
+ end
25
+
26
+ def dependencies
27
+ @dependencies ||= begin
28
+ if Open.exists?(info_file)
29
+ info[:dependencies].collect do |path|
30
+ Step.load(path)
31
+ end
32
+ else
33
+ []
34
+ end
35
+ end
36
+ end
37
+
15
38
  attr_accessor :type
16
39
  def type
17
- @type ||= @task.respond_to?(:type) ? @task.type : nil
40
+ @type ||= @task.respond_to?(:type) ? @task.type : info[:type]
18
41
  end
19
42
 
20
43
  def name
@@ -31,14 +54,15 @@ class Step
31
54
 
32
55
  attr_reader :result
33
56
  def run
57
+ return @result || self.load if done?
58
+ dependencies.each{|dep| dep.run }
34
59
  @result = Persist.persist(name, type, :path => path) do
35
60
  begin
36
61
  merge_info :status => :start, :start => Time.now,
37
62
  :pid => Process.pid, :pid_hostname => ENV["HOSTNAME"],
38
- :inputs => inputs,
63
+ :inputs => inputs, :type => type,
39
64
  :dependencies => dependencies.collect{|d| d.path }
40
65
 
41
- dependencies.each{|dep| dep.run }
42
66
  @result = exec
43
67
  ensure
44
68
  if streaming?
@@ -61,6 +85,11 @@ class Step
61
85
  IO === @result || StringIO === @result
62
86
  end
63
87
 
88
+ def stream
89
+ join
90
+ streaming? ? @result : Open.open(path)
91
+ end
92
+
64
93
  def join
65
94
  if streaming?
66
95
  Open.consume_stream(@result, false)
@@ -83,6 +112,13 @@ class Step
83
112
  FileUtils.rm path.find if path.exist?
84
113
  end
85
114
 
115
+ def recursive_clean
116
+ dependencies.each do |dep|
117
+ dep.recursive_clean
118
+ end
119
+ clean
120
+ end
121
+
86
122
  def step(task_name)
87
123
  dependencies.each do |dep|
88
124
  return dep if dep.task_name == task_name
@@ -22,7 +22,7 @@ module Task
22
22
  end
23
23
 
24
24
  def assign_inputs(provided_inputs = {})
25
- if self.inputs.nil?
25
+ if self.inputs.nil? || (self.inputs.empty? && Array === provided_inputs)
26
26
  case provided_inputs
27
27
  when Array
28
28
  return [provided_inputs, provided_inputs]
@@ -31,6 +31,8 @@ module Task
31
31
  end
32
32
  end
33
33
 
34
+ IndiferentHash.setup(provided_inputs) if Hash === provided_inputs
35
+
34
36
  input_array = []
35
37
  non_default_inputs = []
36
38
  self.inputs.each_with_index do |p,i|
@@ -58,7 +60,7 @@ module Task
58
60
  end
59
61
 
60
62
  def process_inputs(provided_inputs = {})
61
- input_array, non_default_inputs = assign_inputs(provided_inputs)
63
+ input_array, non_default_inputs = assign_inputs provided_inputs
62
64
  digest = Misc.digest(input_array)
63
65
  [input_array, non_default_inputs, digest]
64
66
  end