scout-gear 2.0.0 → 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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +65 -2
  3. data/Rakefile +2 -0
  4. data/VERSION +1 -1
  5. data/bin/scout +233 -24
  6. data/lib/scout/cmd.rb +344 -0
  7. data/lib/scout/concurrent_stream.rb +259 -0
  8. data/lib/scout/exceptions.rb +15 -8
  9. data/lib/scout/indiferent_hash/options.rb +8 -26
  10. data/lib/scout/log/color.rb +2 -2
  11. data/lib/scout/log/fingerprint.rb +11 -1
  12. data/lib/scout/log/progress/report.rb +0 -1
  13. data/lib/scout/log/progress/util.rb +1 -1
  14. data/lib/scout/log/progress.rb +4 -4
  15. data/lib/scout/log.rb +10 -2
  16. data/lib/scout/meta_extension.rb +19 -3
  17. data/lib/scout/misc/digest.rb +56 -0
  18. data/lib/scout/misc/filesystem.rb +26 -0
  19. data/lib/scout/misc/format.rb +17 -6
  20. data/lib/scout/misc/insist.rb +56 -0
  21. data/lib/scout/misc/monitor.rb +23 -0
  22. data/lib/scout/misc.rb +5 -11
  23. data/lib/scout/open/lock.rb +61 -0
  24. data/lib/scout/open/remote.rb +120 -0
  25. data/lib/scout/open/stream.rb +373 -0
  26. data/lib/scout/open/util.rb +225 -0
  27. data/lib/scout/open.rb +169 -0
  28. data/lib/scout/path/find.rb +68 -21
  29. data/lib/scout/path/tmpfile.rb +8 -0
  30. data/lib/scout/path/util.rb +14 -1
  31. data/lib/scout/path.rb +6 -30
  32. data/lib/scout/persist/open.rb +17 -0
  33. data/lib/scout/persist/path.rb +15 -0
  34. data/lib/scout/persist/serialize.rb +151 -0
  35. data/lib/scout/persist.rb +54 -0
  36. data/lib/scout/resource/path.rb +20 -0
  37. data/lib/scout/resource/produce/rake.rb +69 -0
  38. data/lib/scout/resource/produce.rb +246 -0
  39. data/lib/scout/resource/scout.rb +3 -0
  40. data/lib/scout/resource/util.rb +48 -0
  41. data/lib/scout/resource.rb +39 -0
  42. data/lib/scout/simple_opt/accessor.rb +1 -1
  43. data/lib/scout/simple_opt/doc.rb +29 -23
  44. data/lib/scout/simple_opt/parse.rb +4 -3
  45. data/lib/scout/tmpfile.rb +39 -1
  46. data/lib/scout/workflow/definition.rb +78 -0
  47. data/lib/scout/workflow/documentation.rb +83 -0
  48. data/lib/scout/workflow/step/info.rb +77 -0
  49. data/lib/scout/workflow/step/load.rb +18 -0
  50. data/lib/scout/workflow/step.rb +132 -0
  51. data/lib/scout/workflow/task/inputs.rb +114 -0
  52. data/lib/scout/workflow/task.rb +155 -0
  53. data/lib/scout/workflow/usage.rb +314 -0
  54. data/lib/scout/workflow/util.rb +11 -0
  55. data/lib/scout/workflow.rb +40 -0
  56. data/lib/scout-gear.rb +4 -0
  57. data/lib/scout.rb +1 -0
  58. data/lib/workflow-scout.rb +2 -0
  59. data/scout-gear.gemspec +77 -5
  60. data/scout_commands/alias +48 -0
  61. data/scout_commands/find +83 -0
  62. data/scout_commands/glob +0 -0
  63. data/scout_commands/rbbt +23 -0
  64. data/scout_commands/workflow/info +29 -0
  65. data/scout_commands/workflow/list +27 -0
  66. data/scout_commands/workflow/task +58 -0
  67. data/scout_commands/workflow/task_old +706 -0
  68. data/test/scout/indiferent_hash/test_options.rb +11 -1
  69. data/test/scout/misc/test_digest.rb +30 -0
  70. data/test/scout/misc/test_filesystem.rb +30 -0
  71. data/test/scout/misc/test_insist.rb +13 -0
  72. data/test/scout/open/test_lock.rb +52 -0
  73. data/test/scout/open/test_remote.rb +25 -0
  74. data/test/scout/open/test_stream.rb +515 -0
  75. data/test/scout/open/test_util.rb +73 -0
  76. data/test/scout/path/test_find.rb +28 -0
  77. data/test/scout/persist/test_open.rb +37 -0
  78. data/test/scout/persist/test_path.rb +37 -0
  79. data/test/scout/persist/test_serialize.rb +114 -0
  80. data/test/scout/resource/test_path.rb +40 -0
  81. data/test/scout/resource/test_produce.rb +62 -0
  82. data/test/scout/resource/test_util.rb +27 -0
  83. data/test/scout/simple_opt/test_doc.rb +16 -0
  84. data/test/scout/test_cmd.rb +85 -0
  85. data/test/scout/test_concurrent_stream.rb +29 -0
  86. data/test/scout/test_meta_extension.rb +9 -0
  87. data/test/scout/test_misc.rb +0 -7
  88. data/test/scout/test_open.rb +146 -0
  89. data/test/scout/test_path.rb +3 -1
  90. data/test/scout/test_persist.rb +83 -0
  91. data/test/scout/test_resource.rb +26 -0
  92. data/test/scout/test_workflow.rb +87 -0
  93. data/test/scout/workflow/step/test_info.rb +30 -0
  94. data/test/scout/workflow/step/test_load.rb +65 -0
  95. data/test/scout/workflow/task/test_inputs.rb +182 -0
  96. data/test/scout/workflow/test_definition.rb +0 -0
  97. data/test/scout/workflow/test_documentation.rb +30 -0
  98. data/test/scout/workflow/test_step.rb +36 -0
  99. data/test/scout/workflow/test_task.rb +179 -0
  100. data/test/scout/workflow/test_usage.rb +35 -0
  101. data/test/scout/workflow/test_util.rb +17 -0
  102. data/test/test_helper.rb +17 -0
  103. data/test/test_scout-gear.rb +0 -0
  104. metadata +75 -3
@@ -0,0 +1,69 @@
1
+ require_relative '../../misc'
2
+ require_relative '../../path'
3
+ require 'rake'
4
+
5
+ class Rake::FileTask
6
+ class << self
7
+ alias_method :old_define_task, :define_task
8
+ end
9
+
10
+ def self.define_task(file, *args, &block)
11
+ @@files ||= []
12
+ @@files << file
13
+ old_define_task(file, *args, &block)
14
+ end
15
+
16
+ def self.files
17
+ @@files
18
+ end
19
+
20
+ def self.clear_files
21
+ @@files = []
22
+ end
23
+ end
24
+
25
+ module ScoutRake
26
+ class TaskNotFound < StandardError; end
27
+ def self.run(rakefile, dir, task, &block)
28
+ old_pwd = FileUtils.pwd
29
+
30
+ Rake::Task.clear
31
+ Rake::FileTask.clear_files
32
+
33
+ t = nil
34
+ pid = Process.fork{
35
+ if block_given?
36
+ TOPLEVEL_BINDING.receiver.instance_exec &block
37
+ else
38
+ if Path.is_filename? rakefile
39
+ rakefile = rakefile.produce.find
40
+ load rakefile
41
+ else
42
+ TmpFile.with_file(rakefile) do |tmpfile|
43
+ load tmpfile
44
+ end
45
+ end
46
+ end
47
+
48
+ raise TaskNotFound if Rake::Task[task].nil?
49
+
50
+ #Misc.pre_fork
51
+ begin
52
+ Misc.in_dir(dir) do
53
+ Rake::Task[task].invoke
54
+
55
+ Rake::Task.clear
56
+ Rake::FileTask.clear_files
57
+ end
58
+ rescue Exception
59
+ Log.error "Error in rake: #{$!.message}"
60
+ Log.exception $!
61
+ Kernel.exit! -1
62
+ end
63
+ Kernel.exit! 0
64
+ }
65
+ Process.waitpid(pid)
66
+ raise "Rake failed" unless $?.success?
67
+
68
+ end
69
+ end
@@ -0,0 +1,246 @@
1
+ require_relative '../open'
2
+ require_relative '../tmpfile'
3
+ require_relative 'produce/rake'
4
+
5
+ module Resource
6
+ def claim(path, type, content = nil, &block)
7
+ if type == :rake
8
+ @rake_dirs ||= {}
9
+ @rake_dirs[path] = content || block
10
+ else
11
+ @resources ||= {}
12
+ @resources[path] = [type, content || block]
13
+ end
14
+ end
15
+
16
+ def rake_for(path)
17
+ @rake_dirs ||= {}
18
+ @rake_dirs.select{|dir, content|
19
+ Misc.path_relative_to(dir, path)
20
+ }.sort_by{|dir, content|
21
+ dir.length
22
+ }.last
23
+ end
24
+
25
+ def has_rake(path)
26
+ !! rake_for(path)
27
+ end
28
+
29
+ def run_rake(path, rakefile, rake_dir)
30
+ task = Misc.path_relative_to rake_dir, path
31
+ rakefile = rakefile.produce if rakefile.respond_to? :produce
32
+ rakefile = rakefile.find if rakefile.respond_to? :find
33
+
34
+ rake_dir = rake_dir.find(:user) if rake_dir.respond_to? :find
35
+
36
+ begin
37
+ if Proc === rakefile
38
+ ScoutRake.run(nil, rake_dir, task, &rakefile)
39
+ else
40
+ ScoutRake.run(rakefile, rake_dir, task)
41
+ end
42
+ rescue Rake::TaskNotFound
43
+ if rake_dir.nil? or rake_dir.empty? or rake_dir == "/" or rake_dir == "./"
44
+ raise $!
45
+ end
46
+ task = File.join(File.basename(rake_dir), task)
47
+ rake_dir = File.dirname(rake_dir)
48
+ retry
49
+ end
50
+ end
51
+
52
+ def produce(path, force = false)
53
+ case
54
+ when @resources.include?(path)
55
+ type, content = @resources[path]
56
+ when (Path === path && @resources.include?(path.original))
57
+ type, content = @resources[path.original]
58
+ when has_rake(path)
59
+ type = :rake
60
+ rake_dir, content = rake_for(path)
61
+ rake_dir = Path.setup(rake_dir.dup, self.pkgdir, self)
62
+ else
63
+ if path !~ /\.(gz|bgz)$/
64
+ begin
65
+ produce(path.annotate(path + '.gz'), force)
66
+ rescue ResourceNotFound
67
+ begin
68
+ produce(path.annotate(path + '.bgz'), force)
69
+ rescue ResourceNotFound
70
+ raise ResourceNotFound, "Resource is missing and does not seem to be claimed: #{ self } -- #{ path } "
71
+ end
72
+ end
73
+ else
74
+ raise ResourceNotFound, "Resource is missing and does not seem to be claimed: #{ self } -- #{ path } "
75
+ end
76
+ end
77
+
78
+ if path.respond_to?(:find)
79
+ final_path = force ? path.find(:default) : path.find
80
+ else
81
+ final_path = path
82
+ end
83
+
84
+ if type and not File.exist?(final_path) or force
85
+ Log.medium "Producing: (#{self.to_s}) #{ final_path }"
86
+ lock_filename = TmpFile.tmp_for_file(final_path, :dir => lock_dir)
87
+
88
+ Open.lock lock_filename do
89
+ FileUtils.rm_rf final_path if force and File.exist? final_path
90
+
91
+ if ! File.exist?(final_path) || force
92
+
93
+ begin
94
+ case type
95
+ when :string
96
+ Open.sensible_write(final_path, content)
97
+ when :csv
98
+ raise "TSV/CSV Not implemented yet"
99
+ #require 'rbbt/tsv/csv'
100
+ #tsv = TSV.csv Open.open(content)
101
+ #Open.sensible_write(final_path, tsv.to_s)
102
+ when :url
103
+ options = {}
104
+ options[:noz] = true if Open.gzip?(final_path) || Open.bgzip?(final_path) || Open.zip?(final_path)
105
+ Open.sensible_write(final_path, Open.open(content, options))
106
+ when :proc
107
+ data = case content.arity
108
+ when 0
109
+ content.call
110
+ when 1
111
+ content.call final_path
112
+ end
113
+ case data
114
+ when String, IO, StringIO
115
+ Open.sensible_write(final_path, data)
116
+ when Array
117
+ Open.sensible_write(final_path, data * "\n")
118
+ when TSV
119
+ Open.sensible_write(final_path, data.dumper_stream)
120
+ when TSV::Dumper
121
+ Open.sensible_write(final_path, data.stream)
122
+ when nil
123
+ else
124
+ raise "Unkown object produced: #{Log.fingerprint data}"
125
+ end
126
+ when :rake
127
+ run_rake(path, content, rake_dir)
128
+ when :install
129
+ Log.debug "Installing software: #{path}"
130
+
131
+ $set_software_env = false unless File.exist? path
132
+
133
+ software_dir = path.resource.root.software.find :user
134
+ helper_file = File.expand_path(Rbbt.share.install.software.lib.install_helpers.find(:lib, caller_lib_dir(__FILE__)))
135
+ #helper_file = File.expand_path(Rbbt.share.install.software.lib.install_helpers.find)
136
+
137
+ preamble = <<-EOF
138
+ #!/bin/bash
139
+
140
+ RBBT_SOFTWARE_DIR="#{software_dir}"
141
+
142
+ INSTALL_HELPER_FILE="#{helper_file}"
143
+ source "$INSTALL_HELPER_FILE"
144
+ EOF
145
+
146
+ content = content.call if Proc === content
147
+
148
+ content = if content =~ /git:|\.git$/
149
+ {:git => content}
150
+ else
151
+ {:src => content}
152
+ end if String === content and Open.remote?(content)
153
+
154
+ script_text = case content
155
+ when nil
156
+ raise "No way to install #{path}"
157
+ when Path
158
+ Open.read(content)
159
+ when String
160
+ if Path.is_filename?(content) and Open.exists?(content)
161
+ Open.read(content)
162
+ else
163
+ content
164
+ end
165
+ when Hash
166
+ name = content[:name] || File.basename(path)
167
+ git = content[:git]
168
+ src = content[:src]
169
+ url = content[:url]
170
+ jar = content[:jar]
171
+ extra = content[:extra]
172
+ commands = content[:commands]
173
+ if git
174
+ <<-EOF
175
+
176
+ name='#{name}'
177
+ url='#{git}'
178
+
179
+ install_git "$name" "$url" #{extra}
180
+
181
+ #{commands}
182
+ EOF
183
+ elsif src
184
+ <<-EOF
185
+
186
+ name='#{name}'
187
+ url='#{src}'
188
+
189
+ install_src "$name" "$url" #{extra}
190
+
191
+ #{commands}
192
+ EOF
193
+ elsif jar
194
+ <<-EOF
195
+
196
+ name='#{name}'
197
+ url='#{jar}'
198
+
199
+ install_jar "$name" "$url" #{extra}
200
+
201
+ #{commands}
202
+ EOF
203
+ else
204
+ <<-EOF
205
+
206
+ name='#{name}'
207
+ url='#{url}'
208
+
209
+ #{commands}
210
+ EOF
211
+ end
212
+ end
213
+
214
+ script = preamble + "\n" + script_text
215
+ Log.debug "Installing software with script:\n" << script
216
+ CMD.cmd_log('bash', :in => script)
217
+
218
+ set_software_env(software_dir) unless $set_software_env
219
+ $set_software_env = true
220
+ else
221
+ raise "Could not produce #{ resource }. (#{ type }, #{ content })"
222
+ end
223
+ rescue
224
+ FileUtils.rm_rf final_path if File.exist? final_path
225
+ raise $!
226
+ end
227
+ end
228
+ end
229
+ end
230
+
231
+ # After producing a file, make sure we recheck all locations, the file
232
+ # might have appeared with '.gz' extension for instance
233
+ path.instance_variable_set("@path", {})
234
+
235
+ path
236
+ end
237
+
238
+ end
239
+
240
+ module Path
241
+ def produce(force = false)
242
+ return self if ! force && Open.exist?(self)
243
+ self.pkgdir.produce self if Resource === self.pkgdir
244
+ return self
245
+ end
246
+ end
@@ -0,0 +1,3 @@
1
+ module Scout
2
+ extend Resource
3
+ end
@@ -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
+
@@ -0,0 +1,39 @@
1
+ require_relative 'log'
2
+ require_relative 'path'
3
+ require_relative 'resource/produce'
4
+ require_relative 'resource/path'
5
+ require_relative 'resource/util'
6
+
7
+ module Resource
8
+ extend MetaExtension
9
+ extension_attr :pkgdir, :libdir, :subdir, :resources, :rake_dirs, :path_maps, :lock_dir
10
+
11
+ def self.default_lock_dir
12
+ Path.setup('tmp/produce_locks').find
13
+ end
14
+
15
+ def subdir
16
+ @subdir ||= ""
17
+ end
18
+
19
+ def lock_dir
20
+ @lock_dir ||= Resource.default_lock_dir
21
+ end
22
+
23
+ def pkgdir
24
+ @pkgdir ||= Path.default_pkgdir
25
+ end
26
+
27
+ def root
28
+ Path.setup(subdir, self, self.libdir, @path_maps)
29
+ end
30
+
31
+ def method_missing(name, prev = nil, *args)
32
+ if prev.nil?
33
+ root.send(name, *args)
34
+ else
35
+ root.send(name, prev, *args)
36
+ end
37
+ end
38
+ end
39
+
@@ -1,6 +1,6 @@
1
1
  module SOPT
2
2
  class << self
3
- attr_accessor :inputs, :input_shortcuts, :input_types, :input_descriptions, :input_defaults
3
+ attr_writer :inputs, :input_shortcuts, :input_types, :input_descriptions, :input_defaults
4
4
  end
5
5
 
6
6
  def self.all
@@ -2,7 +2,7 @@ require_relative '../log'
2
2
  module SOPT
3
3
 
4
4
  class << self
5
- attr_accessor :command, :summary, :synopsys, :description
5
+ attr_writer :command, :summary, :synopsys, :description
6
6
  end
7
7
 
8
8
  def self.command
@@ -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,32 +96,13 @@ 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
- description
77
- Misc.format_definition_list_item(name, description, 80, 31, nil)
99
+ Misc.format_definition_list_item(name, description)
78
100
  end * "\n"
79
101
  end
80
102
 
81
- def self.doc
82
- doc = <<-EOF
83
- #{Log.color :magenta}#{command}(1) -- #{summary}
84
- #{"=" * (command.length + summary.length + 7)}#{Log.color :reset}
85
-
86
- #{ Log.color :magenta, "## SYNOPSYS"}
87
-
88
- #{Log.color :blue, synopsys}
89
-
90
- #{ Log.color :magenta, "## DESCRIPTION"}
91
-
92
- #{Misc.format_paragraph description}
93
-
94
- #{ Log.color :magenta, "## OPTIONS"}
95
-
96
- #{input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)}
97
- EOF
98
- end
99
103
 
100
104
  def self.doc
101
- doc = <<-EOF
105
+ doc =<<-EOF
102
106
  #{Log.color :magenta}#{command}(1) -- #{summary}
103
107
  #{"=" * (command.length + summary.length + 7)}#{Log.color :reset}
104
108
 
@@ -116,5 +120,7 @@ module SOPT
116
120
 
117
121
  doc << Log.color(:magenta, "## OPTIONS") << "\n\n"
118
122
  doc << input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)
123
+
124
+ doc
119
125
  end
120
126
  end
@@ -44,23 +44,24 @@ module SOPT
44
44
  end
45
45
 
46
46
  def self.parse(opt_str)
47
- info = {}
48
-
49
47
  inputs = []
48
+
50
49
  if opt_str.include? "\n"
51
50
  re = /\n+/
52
51
  else
53
52
  re = /:/
54
53
  end
54
+
55
55
  opt_str.split(re).each do |entry|
56
56
  entry.strip!
57
57
  next if entry.empty?
58
- names, _sep, description = entry.partition /\s+/
58
+ names, _sep, description = entry.partition(/\s+/)
59
59
  short, long, asterisk = names.match(/\s*(?:-(.+))?(?:--(.+?))([*])?$/).values_at 1,2,3
60
60
 
61
61
  inputs << long
62
62
  register short, long, asterisk, description
63
63
  end
64
+
64
65
  inputs
65
66
  end
66
67
  end
data/lib/scout/tmpfile.rb CHANGED
@@ -1,7 +1,10 @@
1
- require 'fileutils'
2
1
  require_relative 'misc'
2
+ require_relative 'log'
3
+ require 'fileutils'
3
4
 
4
5
  module TmpFile
6
+ MAX_FILE_LENGTH = 150
7
+
5
8
  def self.user_tmp(subdir = nil)
6
9
  if subdir
7
10
  File.join(ENV["HOME"],"/tmp/scout", subdir)
@@ -89,4 +92,39 @@ module TmpFile
89
92
  end
90
93
  end
91
94
  end
95
+
96
+ def self.tmp_for_file(file, tmp_options = {}, other_options = {})
97
+ tmp_for_file = IndiferentHash.process_options tmp_options, :file
98
+ return tmp_for_file unless tmp_for_file.nil?
99
+
100
+ prefix = IndiferentHash.process_options tmp_options, :prefix
101
+
102
+ if prefix.nil?
103
+ perfile = file.to_s.gsub(/\//, '>')
104
+ else
105
+ perfile = prefix.to_s + ":" + file.to_s.gsub(/\//, '>')
106
+ end
107
+
108
+ perfile.sub!(/\.b?gz$/,'')
109
+
110
+ if other_options.include? :filters
111
+ other_options[:filters].each do |match,value|
112
+ perfile = perfile + "&F[#{match}=#{Misc.digest(value)}]"
113
+ end
114
+ end
115
+
116
+ persistence_dir = IndiferentHash.process_options(tmp_options, :dir) || TmpFile.tmpdir
117
+ Path.setup(persistence_dir) unless Path === persistence_dir
118
+
119
+ filename = perfile.gsub(/\s/,'_').gsub(/\//,'>')
120
+ clean_options = other_options.dup
121
+ clean_options.delete :unnamed
122
+ clean_options.delete "unnamed"
123
+
124
+ filename = filename[0..MAX_FILE_LENGTH] << Misc.digest(filename[MAX_FILE_LENGTH+1..-1]) if filename.length > MAX_FILE_LENGTH + 10
125
+
126
+ filename += ":" << Misc.digest(clean_options) unless clean_options.empty?
127
+
128
+ persistence_dir[filename]
129
+ end
92
130
  end
@@ -0,0 +1,78 @@
1
+ require_relative '../meta_extension'
2
+
3
+ module Workflow
4
+ extend MetaExtension
5
+ extension_attr :name, :tasks
6
+
7
+ class << self
8
+ attr_accessor :directory
9
+
10
+ def directory
11
+ @directory ||= Path.setup('var/jobs')
12
+ end
13
+
14
+ end
15
+
16
+ def name
17
+ @name ||= self.to_s
18
+ end
19
+
20
+ attr_accessor :directory
21
+ def directory
22
+ @directory ||= Workflow.directory[name]
23
+ end
24
+
25
+ def directory=(directory)
26
+ @directory = directory
27
+ @tasks.each{|name,d| d.directory = directory[name] } if @tasks
28
+ end
29
+
30
+ def annotate_next_task(type, obj)
31
+ @annotate_next_task ||= {}
32
+ @annotate_next_task[type] ||= []
33
+ @annotate_next_task[type] << obj
34
+ end
35
+
36
+ def annotate_next_task_single(type, obj)
37
+ @annotate_next_task ||= {}
38
+ @annotate_next_task[type] = obj
39
+ end
40
+
41
+ def dep(*args, &block)
42
+ case args.length
43
+ when 3
44
+ workflow, task, options = args
45
+ when 2
46
+ if Hash === args.last
47
+ task, options = args
48
+ else
49
+ workflow, task = args
50
+ end
51
+ when 1
52
+ task = args.first
53
+ end
54
+ workflow = self if workflow.nil?
55
+ options = {} if options.nil?
56
+ annotate_next_task :deps, [workflow, task, options, block, args]
57
+ end
58
+
59
+ def input(*args)
60
+ annotate_next_task(:inputs, args)
61
+ end
62
+
63
+ def task(name_and_type, &block)
64
+ name, type = name_and_type.collect.first
65
+ @tasks ||= IndiferentHash.setup({})
66
+ begin
67
+ @annotate_next_task ||= {}
68
+ task = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name]))
69
+ @tasks[name] = task
70
+ ensure
71
+ @annotate_next_task = {}
72
+ end
73
+ end
74
+
75
+ def desc(description)
76
+ annotate_next_task_single(:description, description)
77
+ end
78
+ end