scout-gear 5.1.1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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