scout-gear 10.8.3 → 10.9.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 +17 -0
- data/README.md +352 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/doc/Association.md +288 -0
- data/doc/Entity.md +296 -0
- data/doc/KnowledgeBase.md +433 -0
- data/doc/Persist.md +356 -0
- data/doc/Semaphore.md +171 -0
- data/doc/TSV.md +449 -0
- data/doc/WorkQueue.md +359 -0
- data/doc/Workflow.md +586 -0
- data/lib/scout/association.rb +4 -2
- data/lib/scout/entity/identifiers.rb +1 -1
- data/lib/scout/entity/object.rb +1 -1
- data/lib/scout/entity/property.rb +5 -5
- data/lib/scout/entity.rb +1 -1
- data/lib/scout/knowledge_base/description.rb +1 -1
- data/lib/scout/knowledge_base/list.rb +7 -2
- data/lib/scout/knowledge_base/registry.rb +2 -2
- data/lib/scout/knowledge_base.rb +20 -2
- data/lib/scout/monitor.rb +300 -0
- data/lib/scout/persist/engine/packed_index.rb +2 -2
- data/lib/scout/persist/engine/sharder.rb +1 -1
- data/lib/scout/persist/tsv.rb +1 -0
- data/lib/scout/semaphore.rb +1 -1
- data/lib/scout/tsv/dumper.rb +3 -3
- data/lib/scout/tsv/open.rb +1 -0
- data/lib/scout/tsv/parser.rb +1 -1
- data/lib/scout/tsv/transformer.rb +1 -0
- data/lib/scout/tsv/util.rb +2 -2
- data/lib/scout/work_queue/socket.rb +1 -1
- data/lib/scout/work_queue/worker.rb +7 -5
- data/lib/scout/workflow/documentation.rb +1 -1
- data/lib/scout/workflow/entity.rb +22 -1
- data/lib/scout/workflow/step/config.rb +3 -3
- data/lib/scout/workflow/step/file.rb +4 -0
- data/lib/scout/workflow/step/info.rb +8 -2
- data/lib/scout/workflow/step.rb +10 -5
- data/lib/scout/workflow/task/inputs.rb +1 -1
- data/lib/scout/workflow/usage.rb +3 -2
- data/lib/scout/workflow/util.rb +22 -0
- data/scout-gear.gemspec +20 -6
- data/scout_commands/cat +86 -0
- data/scout_commands/doc +3 -1
- data/scout_commands/entity +151 -0
- data/scout_commands/system/clean +146 -0
- data/scout_commands/system/status +238 -0
- data/scout_commands/workflow/info +23 -10
- data/scout_commands/workflow/install +1 -1
- data/scout_commands/workflow/task +1 -1
- data/test/scout/entity/test_property.rb +1 -1
- data/test/scout/knowledge_base/test_registry.rb +19 -0
- data/test/scout/test_work_queue.rb +1 -1
- data/test/scout/work_queue/test_worker.rb +12 -10
- metadata +32 -5
- data/doc/lib/scout/path.md +0 -35
- data/doc/lib/scout/workflow/task.md +0 -13
|
@@ -12,7 +12,7 @@ class KnowledgeBase
|
|
|
12
12
|
if entity_type.to_s == "simple"
|
|
13
13
|
path = dir.lists[entity_type.to_s][id]
|
|
14
14
|
else
|
|
15
|
-
path = dir.lists[entity_type.to_s][id
|
|
15
|
+
path = dir.lists[entity_type.to_s][id].find_with_extension("tsv")
|
|
16
16
|
end
|
|
17
17
|
else
|
|
18
18
|
path = dir.lists.glob("*/#{id}").first
|
|
@@ -33,6 +33,7 @@ class KnowledgeBase
|
|
|
33
33
|
Open.lock path do
|
|
34
34
|
begin
|
|
35
35
|
if AnnotatedArray === list
|
|
36
|
+
path = path.set_extension('tsv')
|
|
36
37
|
Open.write(path, Annotation.tsv(list, :all).to_s)
|
|
37
38
|
else
|
|
38
39
|
Open.write(path, list * "\n")
|
|
@@ -60,7 +61,11 @@ class KnowledgeBase
|
|
|
60
61
|
list.extend AnnotatedArray
|
|
61
62
|
list
|
|
62
63
|
else
|
|
63
|
-
path.list
|
|
64
|
+
list = path.list
|
|
65
|
+
if entity_type
|
|
66
|
+
Entity.prepare_entity(list, entity_type)
|
|
67
|
+
end
|
|
68
|
+
list
|
|
64
69
|
end
|
|
65
70
|
rescue
|
|
66
71
|
Log.exception $!
|
|
@@ -84,7 +84,7 @@ class KnowledgeBase
|
|
|
84
84
|
key = name.to_s + "_" + fp
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
Persist.memory("Index:"
|
|
87
|
+
Persist.memory("Index:" + [key, dir] * "@") do
|
|
88
88
|
options = options.dup
|
|
89
89
|
|
|
90
90
|
persist_dir = dir
|
|
@@ -148,7 +148,7 @@ class KnowledgeBase
|
|
|
148
148
|
options[:namespace] ||= self.namespace unless self.namespace.nil?
|
|
149
149
|
|
|
150
150
|
key += '.database'
|
|
151
|
-
Persist.memory("Database:"
|
|
151
|
+
Persist.memory("Database:" + [key, dir] * "@") do
|
|
152
152
|
options = options.dup
|
|
153
153
|
|
|
154
154
|
persist_dir = dir
|
data/lib/scout/knowledge_base.rb
CHANGED
|
@@ -59,8 +59,26 @@ class KnowledgeBase
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def self.load(dir)
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
kb = case dir
|
|
63
|
+
when Path
|
|
64
|
+
KnowledgeBase.new dir
|
|
65
|
+
when Symbol
|
|
66
|
+
dir = Path.setup("var").knowledge_base[dir.to_s] if Symbol === dir
|
|
67
|
+
kb = KnowledgeBase.new dir
|
|
68
|
+
when Workflow
|
|
69
|
+
raise if dir.knowledge_base.nil?
|
|
70
|
+
kb = dir.knowledge_base
|
|
71
|
+
when String
|
|
72
|
+
if Workflow.list.include? dir
|
|
73
|
+
workflow = Workflow.require_workflow dir
|
|
74
|
+
kb = workflow.knowledge_base
|
|
75
|
+
elsif dir =~ /^\w+$/
|
|
76
|
+
load(dir.to_sym)
|
|
77
|
+
else
|
|
78
|
+
kb = KnowledgeBase.new dir
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
64
82
|
kb.load
|
|
65
83
|
kb
|
|
66
84
|
end
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
require 'scout'
|
|
2
|
+
|
|
3
|
+
module Scout
|
|
4
|
+
|
|
5
|
+
SENSIBLE_WRITE_DIRS = Open.sensible_write_dir.find_all
|
|
6
|
+
|
|
7
|
+
LOCK_DIRS = Path.setup('tmp/tsv_open_locks').find_all +
|
|
8
|
+
Path.setup('tmp/tsv_locks').find_all +
|
|
9
|
+
Path.setup('tmp/persist_locks').find_all +
|
|
10
|
+
Path.setup('tmp/sensible_write_locks').find_all +
|
|
11
|
+
Path.setup('tmp/produce_locks').find_all +
|
|
12
|
+
Path.setup('tmp/step_info_locks').find_all
|
|
13
|
+
|
|
14
|
+
PERSIST_DIRS = Path.setup('share').find_all + Path.setup('var/cache/persistence').find_all
|
|
15
|
+
|
|
16
|
+
JOB_DIRS = Path.setup('var/jobs').find_all
|
|
17
|
+
|
|
18
|
+
MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new
|
|
19
|
+
|
|
20
|
+
def self.dump_memory(file, obj = nil)
|
|
21
|
+
Log.info "Dumping #{obj} objects into #{ file }"
|
|
22
|
+
Thread.new do
|
|
23
|
+
while true
|
|
24
|
+
Open.write(file) do |f|
|
|
25
|
+
MUTEX_FOR_THREAD_EXCLUSIVE.synchronize do
|
|
26
|
+
GC.start
|
|
27
|
+
ObjectSpace.each_object(obj) do |o|
|
|
28
|
+
f.puts "---"
|
|
29
|
+
f.puts(String === o ? o : o.inspect)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
FileUtils.cp file, file + '.save'
|
|
34
|
+
sleep 3
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.file_time(file)
|
|
40
|
+
info = {}
|
|
41
|
+
begin
|
|
42
|
+
info[:ctime] = File.ctime file
|
|
43
|
+
info[:atime] = File.atime file
|
|
44
|
+
info[:elapsed] = Time.now - info[:ctime]
|
|
45
|
+
rescue Exception
|
|
46
|
+
end
|
|
47
|
+
info[:ctime] = Time.now - 999
|
|
48
|
+
info
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#{{{ LOCKS
|
|
52
|
+
|
|
53
|
+
def self.locks(dirs = LOCK_DIRS)
|
|
54
|
+
dirs.collect do |dir|
|
|
55
|
+
next unless Open.exists? dir
|
|
56
|
+
`find -L "#{ dir }" -name "*.lock" 2>/dev/null`.split "\n"
|
|
57
|
+
end.compact.flatten
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.lock_info(dirs = LOCK_DIRS)
|
|
61
|
+
lock_info = {}
|
|
62
|
+
locks(dirs).each do |f|
|
|
63
|
+
lock_info[f] = {}
|
|
64
|
+
begin
|
|
65
|
+
lock_info[f].merge!(file_time(f))
|
|
66
|
+
if File.size(f) > 0
|
|
67
|
+
info = Open.open(f) do |s|
|
|
68
|
+
Open.yaml(s)
|
|
69
|
+
end
|
|
70
|
+
IndiferentHash.setup(info)
|
|
71
|
+
lock_info[f][:pid] = info[:pid]
|
|
72
|
+
lock_info[f][:ppid] = info[:ppid]
|
|
73
|
+
end
|
|
74
|
+
rescue Exception
|
|
75
|
+
Log.warn $!.message
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
lock_info
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
#{{{ SENSIBLE WRITES
|
|
82
|
+
|
|
83
|
+
def self.sensiblewrites(dirs = SENSIBLE_WRITE_DIRS)
|
|
84
|
+
dirs.collect do |dir|
|
|
85
|
+
next unless Open.exists? dir
|
|
86
|
+
`find -L "#{ dir }" -not -name "*.lock" -not -type d 2>/dev/null`.split "\n"
|
|
87
|
+
end.compact.flatten
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.sensiblewrite_info(dirs = SENSIBLE_WRITE_DIRS)
|
|
91
|
+
info = {}
|
|
92
|
+
sensiblewrites(dirs).each do |f|
|
|
93
|
+
begin
|
|
94
|
+
i = file_time(f)
|
|
95
|
+
info[f] = i
|
|
96
|
+
rescue
|
|
97
|
+
Log.exception $!
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
info
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# PERSISTS
|
|
104
|
+
|
|
105
|
+
def self.persists(dirs = PERSIST_DIRS)
|
|
106
|
+
dirs.collect do |dir|
|
|
107
|
+
next unless Open.exists? dir
|
|
108
|
+
`find -L "#{ dir }" -name "*.persist" 2>/dev/null`.split "\n"
|
|
109
|
+
end.compact.flatten
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.persist_info(dirs = PERSIST_DIRS)
|
|
113
|
+
info = {}
|
|
114
|
+
persists(dirs).each do |f|
|
|
115
|
+
begin
|
|
116
|
+
i = file_time(f)
|
|
117
|
+
info[f] = i
|
|
118
|
+
rescue
|
|
119
|
+
Log.exception $!
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
info
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# PERSISTS
|
|
126
|
+
|
|
127
|
+
def self.job_info(workflows = nil, tasks = nil, dirs = JOB_DIRS)
|
|
128
|
+
require 'rbbt/workflow/step'
|
|
129
|
+
|
|
130
|
+
workflows = [workflows] if workflows and not Array === workflows
|
|
131
|
+
workflows = workflows.collect{|w| w.to_s} if workflows
|
|
132
|
+
|
|
133
|
+
tasks = [tasks] if tasks and not Array === tasks
|
|
134
|
+
tasks = tasks.collect{|w| w.to_s} if tasks
|
|
135
|
+
|
|
136
|
+
jobs = {}
|
|
137
|
+
seen = Set.new
|
|
138
|
+
_files = Set.new
|
|
139
|
+
dirs.collect do |dir|
|
|
140
|
+
next unless Open.exists? dir
|
|
141
|
+
|
|
142
|
+
task_dir_workflows = {}
|
|
143
|
+
tasks_dirs = if dir == '.'
|
|
144
|
+
["."]
|
|
145
|
+
else
|
|
146
|
+
#workflowdirs = if (dir_sub_path = Open.find_repo_dir(workflowdir))
|
|
147
|
+
# repo_dir, sub_path = dir_sub_path
|
|
148
|
+
# Open.list_repo_files(*dir_sub_path).collect{|f| f.split("/").first}.uniq.collect{|f| File.join(repo_dir, f)}.uniq
|
|
149
|
+
# else
|
|
150
|
+
# dir.glob("*")
|
|
151
|
+
# end
|
|
152
|
+
|
|
153
|
+
workflowdirs = dir.glob("*")
|
|
154
|
+
|
|
155
|
+
workflowdirs.collect do |workflowdir|
|
|
156
|
+
workflow = File.basename(workflowdir)
|
|
157
|
+
next if workflows and not workflows.include? workflow
|
|
158
|
+
|
|
159
|
+
#task_dirs = if (dir_sub_path = Open.find_repo_dir(workflowdir))
|
|
160
|
+
# repo_dir, sub_path = dir_sub_path
|
|
161
|
+
# Open.list_repo_files(*dir_sub_path).collect{|f| f.split("/").first}.uniq.collect{|f| File.join(repo_dir, f)}.uniq
|
|
162
|
+
# else
|
|
163
|
+
# workflowdir.glob("*")
|
|
164
|
+
# end
|
|
165
|
+
|
|
166
|
+
task_dirs = workflowdir.glob("*")
|
|
167
|
+
|
|
168
|
+
task_dirs.each do |tasks_dir|
|
|
169
|
+
task_dir_workflows[tasks_dir] = workflow
|
|
170
|
+
end
|
|
171
|
+
end.compact.flatten
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
tasks_dirs.collect do |taskdir|
|
|
175
|
+
task = File.basename(taskdir)
|
|
176
|
+
next if tasks and not tasks.include? task
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
#files = if (dir_sub_path = Open.find_repo_dir(taskdir))
|
|
180
|
+
# repo_dir, sub_path = dir_sub_path
|
|
181
|
+
# Open.list_repo_files(*dir_sub_path).reject do |f|
|
|
182
|
+
# f.include?("/.info/") ||
|
|
183
|
+
# f.include?(".files/") ||
|
|
184
|
+
# f.include?(".pid/") ||
|
|
185
|
+
# File.directory?(f)
|
|
186
|
+
# end.collect do |f|
|
|
187
|
+
# File.join(repo_dir, f)
|
|
188
|
+
# end
|
|
189
|
+
# else
|
|
190
|
+
# #cmd = "find -L '#{ taskdir }/' -not \\( -path \"#{taskdir}/*.files/*\" -prune \\) -not -name '*.pid' -not -name '*.notify' -not -name '\\.*' 2>/dev/null"
|
|
191
|
+
# cmd = "find -L '#{ taskdir }/' -not \\( -path \"#{taskdir}/.info/*\" -prune \\) -not \\( -path \"#{taskdir}/*.files/*\" -prune \\) -not -name '*.pid' -not -name '*.md5' -not -name '*.notify' -not -name '\\.*' \\( -not -type d -o -name '*.files' \\) 2>/dev/null"
|
|
192
|
+
|
|
193
|
+
# CMD.cmd(cmd, :pipe => true).read.split("\n")
|
|
194
|
+
# end
|
|
195
|
+
|
|
196
|
+
files = begin
|
|
197
|
+
cmd = "find -L '#{ taskdir }/' -not \\( -path \"#{taskdir}/.info/*\" -prune \\) -not \\( -path \"#{taskdir}/*.files/*\" -prune \\) -not -name '*.pid' -not -name '*.md5' -not -name '*.notify' -not -name '\\.*' \\( -not -type d -o -name '*.files' \\) 2>/dev/null"
|
|
198
|
+
|
|
199
|
+
CMD.cmd(cmd, :pipe => true).read.split("\n")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
files = files.sort_by{|f| Open.mtime(f) || Time.now}
|
|
203
|
+
workflow = task_dir_workflows[taskdir]
|
|
204
|
+
TSV.traverse files, :type => :array, :into => jobs, :_bar => "Finding jobs in #{ taskdir }" do |file|
|
|
205
|
+
_files << file
|
|
206
|
+
if m = file.match(/(.*)\.(info|pid|files)$/)
|
|
207
|
+
file = m[1]
|
|
208
|
+
end
|
|
209
|
+
next if seen.include? file
|
|
210
|
+
seen << file
|
|
211
|
+
|
|
212
|
+
name = file[taskdir.length+1..-1]
|
|
213
|
+
info_file = file + '.info'
|
|
214
|
+
|
|
215
|
+
info = {}
|
|
216
|
+
|
|
217
|
+
info[:workflow] = workflow
|
|
218
|
+
info[:task] = task
|
|
219
|
+
info[:name] = name
|
|
220
|
+
|
|
221
|
+
if Open.exists? file
|
|
222
|
+
info = info.merge(file_time(file))
|
|
223
|
+
info[:done] = true
|
|
224
|
+
info[:info_file] = Open.exist?(info_file) ? info_file : nil
|
|
225
|
+
else
|
|
226
|
+
info = info.merge({:info_file => info_file, :done => false})
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
[file, info]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
end.compact.flatten
|
|
233
|
+
end.compact.flatten
|
|
234
|
+
jobs
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# REST
|
|
238
|
+
|
|
239
|
+
def self.__jobs(dirs = JOB_DIRS)
|
|
240
|
+
job_files = {}
|
|
241
|
+
dirs.each do |dir|
|
|
242
|
+
workflow_dirs = dir.glob("*").each do |wdir|
|
|
243
|
+
workflow = File.basename(wdir)
|
|
244
|
+
job_files[workflow] = {}
|
|
245
|
+
task_dirs = wdir.glob('*')
|
|
246
|
+
task_dirs.each do |tdir|
|
|
247
|
+
task = File.basename(tdir)
|
|
248
|
+
job_files[workflow][task] = tdir.glob('*')
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
jobs = {}
|
|
253
|
+
job_files.each do |workflow,task_jobs|
|
|
254
|
+
jobs[workflow] ||= {}
|
|
255
|
+
task_jobs.each do |task, files|
|
|
256
|
+
jobs[workflow][task] ||= {}
|
|
257
|
+
files.each do |f|
|
|
258
|
+
next if f =~ /\.lock$/
|
|
259
|
+
job = f.sub(/\.(info|files)/,'')
|
|
260
|
+
|
|
261
|
+
jobs[workflow][task][job] ||= {}
|
|
262
|
+
if jobs[workflow][task][job][:status].nil?
|
|
263
|
+
status = nil
|
|
264
|
+
status = :done if Open.exists? job
|
|
265
|
+
if status.nil? and f=~/\.info/
|
|
266
|
+
info = begin
|
|
267
|
+
Step::INFO_SERIALIZER.load(Open.read(f, :mode => 'rb'))
|
|
268
|
+
rescue
|
|
269
|
+
{}
|
|
270
|
+
end
|
|
271
|
+
status = info[:status]
|
|
272
|
+
pid = info[:pid]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
jobs[workflow][task][job][:pid] = pid if pid
|
|
276
|
+
jobs[workflow][task][job][:status] = status if status
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
jobs
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def self.load_lock(lock)
|
|
285
|
+
begin
|
|
286
|
+
info = Misc.insist 3 do
|
|
287
|
+
Open.yaml(lock)
|
|
288
|
+
end
|
|
289
|
+
info.values_at "pid", "ppid", "time"
|
|
290
|
+
rescue Exception
|
|
291
|
+
time = begin
|
|
292
|
+
File.atime(lock)
|
|
293
|
+
rescue Exception
|
|
294
|
+
Time.now
|
|
295
|
+
end
|
|
296
|
+
[nil, nil, time]
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
end
|
|
@@ -9,7 +9,7 @@ class PackedIndex
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
def self.process_mask(mask)
|
|
12
|
-
str = ""
|
|
12
|
+
str = "".dup
|
|
13
13
|
size = 0
|
|
14
14
|
mask.each do |e|
|
|
15
15
|
if ELEMS.include? e
|
|
@@ -50,7 +50,7 @@ class PackedIndex
|
|
|
50
50
|
@mask = @stream.read(mask_length)
|
|
51
51
|
@offset = @mask.length + 8
|
|
52
52
|
end
|
|
53
|
-
@nil_string = "NIL"
|
|
53
|
+
@nil_string = "NIL" + ("-" * (@item_size - 3))
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def file
|
|
@@ -37,7 +37,7 @@ class Sharder
|
|
|
37
37
|
databases[shard]
|
|
38
38
|
else
|
|
39
39
|
database = databases[shard] ||= begin
|
|
40
|
-
path = File.join(persistence_path, 'shard-'
|
|
40
|
+
path = File.join(persistence_path, 'shard-' + shard.to_s)
|
|
41
41
|
(writable or File.exist?(path)) ? Persist.open_database(path, (File.exist?(path) ? false : writable), :clean, db_type, @persist_options) : nil
|
|
42
42
|
end
|
|
43
43
|
Log.warn "Database #{ path } missing" if database.nil?
|
data/lib/scout/persist/tsv.rb
CHANGED
data/lib/scout/semaphore.rb
CHANGED
|
@@ -75,7 +75,7 @@ if continue
|
|
|
75
75
|
|
|
76
76
|
def self.with_semaphore(size, file = nil)
|
|
77
77
|
if file.nil?
|
|
78
|
-
file = "/scout-"
|
|
78
|
+
file = "/scout-" + Misc.digest(rand(100000000000).to_s)[0..10] if file.nil?
|
|
79
79
|
else
|
|
80
80
|
file = file.gsub('/', '_') if file
|
|
81
81
|
end
|
data/lib/scout/tsv/dumper.rb
CHANGED
|
@@ -16,7 +16,7 @@ module TSV
|
|
|
16
16
|
if String === preamble
|
|
17
17
|
preamble_str = preamble
|
|
18
18
|
elsif preamble && options.values.compact.any?
|
|
19
|
-
preamble_str = "#: "
|
|
19
|
+
preamble_str = "#: " + IndiferentHash.hash2string(options.merge(serializer: nil))
|
|
20
20
|
else
|
|
21
21
|
preamble_str = nil
|
|
22
22
|
end
|
|
@@ -81,7 +81,7 @@ module TSV
|
|
|
81
81
|
header = Dumper.header(@options.merge(type: @type, sep: @sep, preamble: preamble))
|
|
82
82
|
@mutex.synchronize do
|
|
83
83
|
@initialized = true
|
|
84
|
-
@sin << header
|
|
84
|
+
@sin << header + "\n" if header and ! header.empty?
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
@@ -134,7 +134,7 @@ module TSV
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
def fingerprint
|
|
137
|
-
"Dumper:{"
|
|
137
|
+
"Dumper:{" + Log.fingerprint(self.all_fields|| []) << "}"
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def digest_str
|
data/lib/scout/tsv/open.rb
CHANGED
data/lib/scout/tsv/parser.rb
CHANGED
data/lib/scout/tsv/util.rb
CHANGED
|
@@ -165,11 +165,11 @@ Example:
|
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
def fingerprint
|
|
168
|
-
"TSV:{"
|
|
168
|
+
"TSV:{" + Log.fingerprint(self.all_fields|| []) << ";" << Log.fingerprint(self.keys) << "}"
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
def digest_str
|
|
172
|
-
"TSV:{"
|
|
172
|
+
"TSV:{" + Log.fingerprint(self.all_fields|| []) << ";" << Log.fingerprint(self.keys) << ";" << Log.fingerprint(self.values) << "}"
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
def inspect
|
|
@@ -9,7 +9,7 @@ class WorkQueue
|
|
|
9
9
|
|
|
10
10
|
@serializer = serializer || Marshal
|
|
11
11
|
|
|
12
|
-
@key = "/"
|
|
12
|
+
@key = "/" + rand(1000000000).to_s << '.' << Process.pid.to_s;
|
|
13
13
|
@write_sem = @key + '.in'
|
|
14
14
|
@read_sem = @key + '.out'
|
|
15
15
|
Log.debug "Creating socket semaphores: #{@key}"
|
|
@@ -27,9 +27,9 @@ class WorkQueue
|
|
|
27
27
|
run do
|
|
28
28
|
begin
|
|
29
29
|
if output
|
|
30
|
-
Open.purge_pipes(output.swrite)
|
|
30
|
+
Open.purge_pipes(input.sread, output.swrite)
|
|
31
31
|
else
|
|
32
|
-
Open.purge_pipes
|
|
32
|
+
Open.purge_pipes(input.sread)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
while obj = input.read
|
|
@@ -43,9 +43,11 @@ class WorkQueue
|
|
|
43
43
|
rescue DoneProcessing
|
|
44
44
|
rescue Interrupt
|
|
45
45
|
rescue Exception
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
begin
|
|
47
|
+
output.write WorkerException.new($!, Process.pid)
|
|
48
|
+
ensure
|
|
49
|
+
exit -1
|
|
50
|
+
end
|
|
49
51
|
end
|
|
50
52
|
exit 0
|
|
51
53
|
end
|
|
@@ -71,10 +71,31 @@ module EntityWorkflow
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
property_name = task_name.to_s.sub(/^(#{entity_name}_list|#{entity_name}|list)_/, '')
|
|
74
|
+
property_job_name = property_name + '_job'
|
|
75
|
+
|
|
76
|
+
property property_job_name => property_type do |*args|
|
|
77
|
+
job(task_name, *args)
|
|
78
|
+
end
|
|
79
|
+
|
|
74
80
|
property property_name => property_type do |*args|
|
|
75
|
-
job =
|
|
81
|
+
job = self.send(property_job_name)
|
|
82
|
+
|
|
83
|
+
job.join if job.running?
|
|
84
|
+
|
|
85
|
+
if job.error?
|
|
86
|
+
if job.recoverable_error?
|
|
87
|
+
job.clean
|
|
88
|
+
else
|
|
89
|
+
raise job.exception
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
job.run unless job.done?
|
|
94
|
+
|
|
95
|
+
job.load
|
|
76
96
|
Array === job ? job.collect(&:run) : job.run
|
|
77
97
|
end
|
|
98
|
+
|
|
78
99
|
end
|
|
79
100
|
|
|
80
101
|
def entity_task(task_name, *args, &block)
|
|
@@ -8,10 +8,10 @@ class Step
|
|
|
8
8
|
new_tokens = []
|
|
9
9
|
if workflow
|
|
10
10
|
workflow_name = workflow.name
|
|
11
|
-
new_tokens << ("workflow:"
|
|
12
|
-
new_tokens << ("task:"
|
|
11
|
+
new_tokens << ("workflow:" + workflow_name)
|
|
12
|
+
new_tokens << ("task:" + workflow_name << "#" << task_name.to_s)
|
|
13
13
|
end
|
|
14
|
-
new_tokens << ("task:"
|
|
14
|
+
new_tokens << ("task:" + task_name.to_s)
|
|
15
15
|
|
|
16
16
|
Scout::Config.get(key, tokens + new_tokens, options)
|
|
17
17
|
end
|
|
@@ -120,7 +120,7 @@ class Step
|
|
|
120
120
|
if info.include?(key)
|
|
121
121
|
case info[key]
|
|
122
122
|
when Array
|
|
123
|
-
info[key].concat
|
|
123
|
+
info[key].concat(Array === value ? value : [value])
|
|
124
124
|
when Hash
|
|
125
125
|
info[key].merge! value
|
|
126
126
|
else
|
|
@@ -201,7 +201,13 @@ class Step
|
|
|
201
201
|
end
|
|
202
202
|
|
|
203
203
|
def exception
|
|
204
|
-
info[:exception]
|
|
204
|
+
return nil unless info[:exception]
|
|
205
|
+
begin
|
|
206
|
+
Marshal.load(Base64.decode64(info[:exception]))
|
|
207
|
+
rescue
|
|
208
|
+
Log.exception $!
|
|
209
|
+
nil
|
|
210
|
+
end
|
|
205
211
|
end
|
|
206
212
|
|
|
207
213
|
# Marshal Step
|
data/lib/scout/workflow/step.rb
CHANGED
|
@@ -16,7 +16,7 @@ require_relative 'step/archive'
|
|
|
16
16
|
class Step
|
|
17
17
|
|
|
18
18
|
attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs, :provided_inputs, :compute, :overriden_task, :overriden_workflow, :workflow, :exec_context, :overriden
|
|
19
|
-
def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context
|
|
19
|
+
def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context: nil, &task)
|
|
20
20
|
@path = path
|
|
21
21
|
@inputs = inputs
|
|
22
22
|
@dependencies = dependencies
|
|
@@ -112,17 +112,22 @@ class Step
|
|
|
112
112
|
|
|
113
113
|
def exec
|
|
114
114
|
|
|
115
|
-
if inputs
|
|
115
|
+
if inputs
|
|
116
116
|
if Task === task
|
|
117
117
|
types = task.inputs.collect{|name,type| type }
|
|
118
|
-
new_inputs = inputs.zip(types).collect{|input,info|
|
|
118
|
+
new_inputs = inputs.zip(types).collect{|input,info|
|
|
119
119
|
type, desc, default, options = info
|
|
120
120
|
next input unless Step === input
|
|
121
121
|
input.join if input.streaming?
|
|
122
122
|
Task.format_input(input.join.path, type, options)
|
|
123
123
|
}
|
|
124
124
|
else
|
|
125
|
-
|
|
125
|
+
if Hash === inputs
|
|
126
|
+
new_inputs = inputs.values
|
|
127
|
+
else
|
|
128
|
+
new_inputs = inputs
|
|
129
|
+
end
|
|
130
|
+
new_inputs = new_inputs.collect{|input|
|
|
126
131
|
Step === input ? input.load : input
|
|
127
132
|
}
|
|
128
133
|
end
|
|
@@ -218,7 +223,7 @@ class Step
|
|
|
218
223
|
|
|
219
224
|
@result
|
|
220
225
|
rescue Exception => e
|
|
221
|
-
merge_info :status => :error, :exception => e, :end => Time.now, :backtrace => e.backtrace, :message => "#{e.class}: #{e.message}"
|
|
226
|
+
merge_info :status => :error, :exception => Base64.encode64(Marshal.dump(e)), :end => Time.now, :backtrace => e.backtrace, :message => "#{e.class}: #{e.message}"
|
|
222
227
|
begin
|
|
223
228
|
abort_dependencies
|
|
224
229
|
ensure
|
|
@@ -169,7 +169,7 @@ module Task
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
def load_inputs(directory)
|
|
172
|
-
if Open.exists?(directory) && ! Open.directory?(directory)
|
|
172
|
+
if Open.exists?(directory) && ! Open.directory?(directory) && ! Open.size(directory) == 0
|
|
173
173
|
TmpFile.with_file do |tmp_directory|
|
|
174
174
|
Misc.in_dir tmp_directory do
|
|
175
175
|
CMD.cmd("tar xvfz '#{directory}'")
|