libis-workflow 2.0.24 → 2.0.25
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/.coveralls.yml +1 -1
- data/.gitignore +36 -36
- data/.travis.yml +32 -32
- data/Gemfile +4 -4
- data/LICENSE +20 -20
- data/README.md +380 -380
- data/Rakefile +6 -6
- data/lib/libis/exceptions.rb +6 -6
- data/lib/libis/workflow.rb +41 -41
- data/lib/libis/workflow/action.rb +24 -24
- data/lib/libis/workflow/base/dir_item.rb +13 -13
- data/lib/libis/workflow/base/file_item.rb +80 -80
- data/lib/libis/workflow/base/job.rb +83 -83
- data/lib/libis/workflow/base/logging.rb +66 -66
- data/lib/libis/workflow/base/run.rb +95 -95
- data/lib/libis/workflow/base/work_item.rb +173 -173
- data/lib/libis/workflow/base/workflow.rb +149 -149
- data/lib/libis/workflow/config.rb +22 -22
- data/lib/libis/workflow/dir_item.rb +10 -10
- data/lib/libis/workflow/file_item.rb +15 -15
- data/lib/libis/workflow/job.rb +28 -28
- data/lib/libis/workflow/message_registry.rb +30 -30
- data/lib/libis/workflow/run.rb +34 -34
- data/lib/libis/workflow/status.rb +133 -133
- data/lib/libis/workflow/task.rb +316 -316
- data/lib/libis/workflow/task_group.rb +71 -71
- data/lib/libis/workflow/task_runner.rb +34 -34
- data/lib/libis/workflow/version.rb +5 -5
- data/lib/libis/workflow/work_item.rb +37 -37
- data/lib/libis/workflow/worker.rb +42 -42
- data/lib/libis/workflow/workflow.rb +20 -20
- data/libis-workflow.gemspec +38 -38
- data/spec/items.rb +2 -2
- data/spec/items/test_dir_item.rb +13 -13
- data/spec/items/test_file_item.rb +16 -16
- data/spec/items/test_run.rb +8 -8
- data/spec/spec_helper.rb +8 -8
- data/spec/task_spec.rb +15 -15
- data/spec/tasks/camelize_name.rb +12 -12
- data/spec/tasks/checksum_tester.rb +32 -32
- data/spec/tasks/collect_files.rb +47 -47
- data/spec/workflow_spec.rb +154 -154
- metadata +3 -3
@@ -1,67 +1,67 @@
|
|
1
|
-
module Libis
|
2
|
-
module Workflow
|
3
|
-
module Base
|
4
|
-
module Logging
|
5
|
-
|
6
|
-
# Add a structured message to the log history. The message text can be submitted as an integer or text. If an
|
7
|
-
# integer is submitted, it will be used to look up the text in the MessageRegistry. The message text will be
|
8
|
-
# passed to the % operator with the args parameter. If that failes (e.g. because the format string is not correct)
|
9
|
-
# the args value is appended to the message.
|
10
|
-
#
|
11
|
-
# @param [Symbol] severity
|
12
|
-
# @param [Hash] msg should contain message text as :id or :text and the hierarchical name of the task as :task
|
13
|
-
# @param [Array] args string format values
|
14
|
-
def log_message(severity, msg, *args)
|
15
|
-
# Prepare info from msg struct for use with string substitution
|
16
|
-
message_id, message_text = if msg[:id]
|
17
|
-
[msg[:id], MessageRegistry.instance.get_message(msg[:id])]
|
18
|
-
elsif msg[:text]
|
19
|
-
[0, msg[:text]]
|
20
|
-
else
|
21
|
-
[0, '']
|
22
|
-
end
|
23
|
-
task = msg[:task] || ''
|
24
|
-
message_text = (message_text % args rescue "#{message_text} - #{args}")
|
25
|
-
|
26
|
-
run_id = self.get_run.id rescue nil
|
27
|
-
|
28
|
-
self.add_log severity: severity, id: message_id.to_i, text: message_text, task: task, run_id: run_id
|
29
|
-
end
|
30
|
-
|
31
|
-
# Helper function for the WorkItems to add a log entry to the log_history.
|
32
|
-
#
|
33
|
-
# The supplied message structure is expected to contain the following fields:
|
34
|
-
# - :severity : ::Logger::Severity value
|
35
|
-
# - :id : optional message id
|
36
|
-
# - :text : message text
|
37
|
-
# - :task : list of tasks names (task hierarchy) that submits the message
|
38
|
-
#
|
39
|
-
# @param [Hash] message
|
40
|
-
def add_log(message = {})
|
41
|
-
msg = message_struct(message)
|
42
|
-
add_log_entry(msg)
|
43
|
-
self.save!
|
44
|
-
end
|
45
|
-
|
46
|
-
def <=(message = {})
|
47
|
-
self.add_log(message)
|
48
|
-
end
|
49
|
-
|
50
|
-
protected
|
51
|
-
|
52
|
-
# create and return a proper message structure
|
53
|
-
# @param [Hash] opts
|
54
|
-
def message_struct(opts = {})
|
55
|
-
opts.reverse_merge!(severity: :info, code: nil, text: '')
|
56
|
-
{
|
57
|
-
severity: ::Logging::levelify(opts[:severity]).upcase,
|
58
|
-
task: opts[:task],
|
59
|
-
code: opts[:code],
|
60
|
-
message: opts[:text]
|
61
|
-
}.cleanup
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
1
|
+
module Libis
|
2
|
+
module Workflow
|
3
|
+
module Base
|
4
|
+
module Logging
|
5
|
+
|
6
|
+
# Add a structured message to the log history. The message text can be submitted as an integer or text. If an
|
7
|
+
# integer is submitted, it will be used to look up the text in the MessageRegistry. The message text will be
|
8
|
+
# passed to the % operator with the args parameter. If that failes (e.g. because the format string is not correct)
|
9
|
+
# the args value is appended to the message.
|
10
|
+
#
|
11
|
+
# @param [Symbol] severity
|
12
|
+
# @param [Hash] msg should contain message text as :id or :text and the hierarchical name of the task as :task
|
13
|
+
# @param [Array] args string format values
|
14
|
+
def log_message(severity, msg, *args)
|
15
|
+
# Prepare info from msg struct for use with string substitution
|
16
|
+
message_id, message_text = if msg[:id]
|
17
|
+
[msg[:id], MessageRegistry.instance.get_message(msg[:id])]
|
18
|
+
elsif msg[:text]
|
19
|
+
[0, msg[:text]]
|
20
|
+
else
|
21
|
+
[0, '']
|
22
|
+
end
|
23
|
+
task = msg[:task] || ''
|
24
|
+
message_text = (message_text % args rescue "#{message_text} - #{args}")
|
25
|
+
|
26
|
+
run_id = self.get_run.id rescue nil
|
27
|
+
|
28
|
+
self.add_log severity: severity, id: message_id.to_i, text: message_text, task: task, run_id: run_id
|
29
|
+
end
|
30
|
+
|
31
|
+
# Helper function for the WorkItems to add a log entry to the log_history.
|
32
|
+
#
|
33
|
+
# The supplied message structure is expected to contain the following fields:
|
34
|
+
# - :severity : ::Logger::Severity value
|
35
|
+
# - :id : optional message id
|
36
|
+
# - :text : message text
|
37
|
+
# - :task : list of tasks names (task hierarchy) that submits the message
|
38
|
+
#
|
39
|
+
# @param [Hash] message
|
40
|
+
def add_log(message = {})
|
41
|
+
msg = message_struct(message)
|
42
|
+
add_log_entry(msg)
|
43
|
+
self.save!
|
44
|
+
end
|
45
|
+
|
46
|
+
def <=(message = {})
|
47
|
+
self.add_log(message)
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# create and return a proper message structure
|
53
|
+
# @param [Hash] opts
|
54
|
+
def message_struct(opts = {})
|
55
|
+
opts.reverse_merge!(severity: :info, code: nil, text: '')
|
56
|
+
{
|
57
|
+
severity: ::Logging::levelify(opts[:severity]).upcase,
|
58
|
+
task: opts[:task],
|
59
|
+
code: opts[:code],
|
60
|
+
message: opts[:text]
|
61
|
+
}.cleanup
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
67
|
end
|
@@ -1,95 +1,95 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
require 'libis/workflow/base/work_item'
|
4
|
-
require 'libis/workflow/task_runner'
|
5
|
-
|
6
|
-
module Libis
|
7
|
-
module Workflow
|
8
|
-
module Base
|
9
|
-
|
10
|
-
# Base module for all workflow runs. It is created by an associated workflow when the workflow is executed.
|
11
|
-
#
|
12
|
-
# This module lacks the implementation for the data attributes. It functions as an interface that describes the
|
13
|
-
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
14
|
-
#
|
15
|
-
# - start_date: [Time] the timestamp of the execution of the run
|
16
|
-
# - job: [Object] a reference to the Job this Run belongs to
|
17
|
-
# - id: [String] (Optional) a unique run number
|
18
|
-
#
|
19
|
-
# Note that ::Libis::Workflow::Base::WorkItem is a parent module and therefore requires implementation of the
|
20
|
-
# attributes of that module too.
|
21
|
-
#
|
22
|
-
# A simple in-memory implementation can be found in ::Libis::Workflow::Run
|
23
|
-
module Run
|
24
|
-
include ::Libis::Workflow::Base::WorkItem
|
25
|
-
|
26
|
-
attr_accessor :tasks, :action
|
27
|
-
|
28
|
-
def work_dir
|
29
|
-
# noinspection RubyResolve
|
30
|
-
dir = File.join(Libis::Workflow::Config.workdir, self.name)
|
31
|
-
FileUtils.mkpath dir unless Dir.exist?(dir)
|
32
|
-
dir
|
33
|
-
end
|
34
|
-
|
35
|
-
def name
|
36
|
-
self.job.run_name(self.start_date)
|
37
|
-
end
|
38
|
-
|
39
|
-
def names
|
40
|
-
Array.new
|
41
|
-
end
|
42
|
-
|
43
|
-
def namepath
|
44
|
-
self.name
|
45
|
-
end
|
46
|
-
|
47
|
-
def workflow
|
48
|
-
self.job.workflow
|
49
|
-
end
|
50
|
-
|
51
|
-
def logger
|
52
|
-
self.properties['logger'] || self.job.logger rescue ::Libis::Workflow::Config.logger
|
53
|
-
end
|
54
|
-
|
55
|
-
# Execute the workflow.
|
56
|
-
#
|
57
|
-
# The action parameter defines how the execution of the tasks will behave:
|
58
|
-
# - With the default :run action each task will be executed regardsless how the task performed on the item
|
59
|
-
# previously.
|
60
|
-
# - When using the :retry action a task will not perform on an item if it was successful the last time. This
|
61
|
-
# allows you to retry a run when an temporary error (e.g. asynchronous wait or halt) occured.
|
62
|
-
#
|
63
|
-
# @param [Symbol] action the type of action to take during this run. :run or :retry
|
64
|
-
def run(action = :run)
|
65
|
-
self.action = action
|
66
|
-
|
67
|
-
self.start_date = Time.now unless action == :retry
|
68
|
-
|
69
|
-
self.options = workflow.prepare_input(self.options)
|
70
|
-
|
71
|
-
self.tasks = workflow.tasks
|
72
|
-
configure_tasks self.options
|
73
|
-
|
74
|
-
self.save!
|
75
|
-
|
76
|
-
runner = Libis::Workflow::TaskRunner.new nil
|
77
|
-
|
78
|
-
self.tasks.each do |task|
|
79
|
-
runner << task
|
80
|
-
end
|
81
|
-
|
82
|
-
runner.run self
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def configure_tasks(opts)
|
89
|
-
self.tasks.each { |task| task.apply_options opts }
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'libis/workflow/base/work_item'
|
4
|
+
require 'libis/workflow/task_runner'
|
5
|
+
|
6
|
+
module Libis
|
7
|
+
module Workflow
|
8
|
+
module Base
|
9
|
+
|
10
|
+
# Base module for all workflow runs. It is created by an associated workflow when the workflow is executed.
|
11
|
+
#
|
12
|
+
# This module lacks the implementation for the data attributes. It functions as an interface that describes the
|
13
|
+
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
14
|
+
#
|
15
|
+
# - start_date: [Time] the timestamp of the execution of the run
|
16
|
+
# - job: [Object] a reference to the Job this Run belongs to
|
17
|
+
# - id: [String] (Optional) a unique run number
|
18
|
+
#
|
19
|
+
# Note that ::Libis::Workflow::Base::WorkItem is a parent module and therefore requires implementation of the
|
20
|
+
# attributes of that module too.
|
21
|
+
#
|
22
|
+
# A simple in-memory implementation can be found in ::Libis::Workflow::Run
|
23
|
+
module Run
|
24
|
+
include ::Libis::Workflow::Base::WorkItem
|
25
|
+
|
26
|
+
attr_accessor :tasks, :action
|
27
|
+
|
28
|
+
def work_dir
|
29
|
+
# noinspection RubyResolve
|
30
|
+
dir = File.join(Libis::Workflow::Config.workdir, self.name)
|
31
|
+
FileUtils.mkpath dir unless Dir.exist?(dir)
|
32
|
+
dir
|
33
|
+
end
|
34
|
+
|
35
|
+
def name
|
36
|
+
self.job.run_name(self.start_date)
|
37
|
+
end
|
38
|
+
|
39
|
+
def names
|
40
|
+
Array.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def namepath
|
44
|
+
self.name
|
45
|
+
end
|
46
|
+
|
47
|
+
def workflow
|
48
|
+
self.job.workflow
|
49
|
+
end
|
50
|
+
|
51
|
+
def logger
|
52
|
+
self.properties['logger'] || self.job.logger rescue ::Libis::Workflow::Config.logger
|
53
|
+
end
|
54
|
+
|
55
|
+
# Execute the workflow.
|
56
|
+
#
|
57
|
+
# The action parameter defines how the execution of the tasks will behave:
|
58
|
+
# - With the default :run action each task will be executed regardsless how the task performed on the item
|
59
|
+
# previously.
|
60
|
+
# - When using the :retry action a task will not perform on an item if it was successful the last time. This
|
61
|
+
# allows you to retry a run when an temporary error (e.g. asynchronous wait or halt) occured.
|
62
|
+
#
|
63
|
+
# @param [Symbol] action the type of action to take during this run. :run or :retry
|
64
|
+
def run(action = :run)
|
65
|
+
self.action = action
|
66
|
+
|
67
|
+
self.start_date = Time.now unless action == :retry
|
68
|
+
|
69
|
+
self.options = workflow.prepare_input(self.options)
|
70
|
+
|
71
|
+
self.tasks = workflow.tasks
|
72
|
+
configure_tasks self.options
|
73
|
+
|
74
|
+
self.save!
|
75
|
+
|
76
|
+
runner = Libis::Workflow::TaskRunner.new nil
|
77
|
+
|
78
|
+
self.tasks.each do |task|
|
79
|
+
runner << task
|
80
|
+
end
|
81
|
+
|
82
|
+
runner.run self
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def configure_tasks(opts)
|
89
|
+
self.tasks.each { |task| task.apply_options opts }
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,173 +1,173 @@
|
|
1
|
-
require 'backports/rails/hash'
|
2
|
-
require 'libis/tools/extend/hash'
|
3
|
-
|
4
|
-
require 'libis/workflow/config'
|
5
|
-
require 'libis/workflow/status'
|
6
|
-
require_relative 'logging'
|
7
|
-
|
8
|
-
module Libis
|
9
|
-
module Workflow
|
10
|
-
module Base
|
11
|
-
|
12
|
-
# Base module for all work items.
|
13
|
-
#
|
14
|
-
# This module lacks the implementation for the data attributes. It functions as an interface that describes the
|
15
|
-
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
16
|
-
#
|
17
|
-
# - parent: [Object|nil] a link to a parent work item. Work items can be organized in any hierarchy you think is
|
18
|
-
# relevant for your workflow (e.g. directory[/directory...]/file/line or library/section/book/page). Of course
|
19
|
-
# hierarchies are not mandatory.
|
20
|
-
# - items: [Array] a list of child work items. see above.
|
21
|
-
# - options: [Hash] a set of options for the task chain on how to deal with this work item. This attribute can be
|
22
|
-
# used to fine-tune the behaviour of tasks for a particular work item.
|
23
|
-
# - properties: [Hash] a set of properties, typically collected during the workflow processing and used to store
|
24
|
-
# final or intermediate resulst of tasks. The ::Lias::Ingester::FileItem module uses this attribute to store the
|
25
|
-
# properties (e.g. size, checksum, ...) of the file it represents.
|
26
|
-
# - status_log: [Array] a list of all status changes the work item went through.
|
27
|
-
# - summary: [Hash] collected statistics about the ingest for the work item and its children. This structure will
|
28
|
-
# be filled in by the included task ::Lias::Ingester::Tasks::Analyzer wich is appended to the workflow by default.
|
29
|
-
#
|
30
|
-
# The module is created so that it is possible to implement an ActiveRecord/Datamapper/... implementation easily.
|
31
|
-
# A simple in-memory implementation would require:
|
32
|
-
#
|
33
|
-
# attr_accessor :parent
|
34
|
-
# attr_accessor :items
|
35
|
-
# attr_accessor :options, :properties
|
36
|
-
# attr_accessor :status_log
|
37
|
-
# attr_accessor :summary
|
38
|
-
#
|
39
|
-
# def initialize
|
40
|
-
# self.parent = nil
|
41
|
-
# self.items = []
|
42
|
-
# self.options = {}
|
43
|
-
# self.properties = {}
|
44
|
-
# self.status_log = []
|
45
|
-
# self.summary = {}
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# protected
|
49
|
-
#
|
50
|
-
# ## Method below should be adapted to match the implementation of the status array
|
51
|
-
#
|
52
|
-
# def add_status_log(info)
|
53
|
-
# self.status_log << info
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
#
|
57
|
-
module WorkItem
|
58
|
-
include Enumerable
|
59
|
-
include Libis::Workflow::Status
|
60
|
-
include Libis::Workflow::Base::Logging
|
61
|
-
|
62
|
-
# String representation of the identity of the work item.
|
63
|
-
#
|
64
|
-
# You may want to overwrite this method as it tries the :name property or whatever #inspect returns if that
|
65
|
-
# failes. Typically this should return the key value, file name or id number. If that's what your :name property
|
66
|
-
# contains, you're fine.
|
67
|
-
#
|
68
|
-
# @return [String] string identification for this work item.
|
69
|
-
def name
|
70
|
-
# noinspection RubyResolve
|
71
|
-
self.properties['name'] || self.inspect
|
72
|
-
end
|
73
|
-
|
74
|
-
def to_s;
|
75
|
-
self.name;
|
76
|
-
end
|
77
|
-
|
78
|
-
def names
|
79
|
-
(self.parent.names rescue Array.new).push(name).compact
|
80
|
-
end
|
81
|
-
|
82
|
-
def namepath;
|
83
|
-
self.names.join('/');
|
84
|
-
end
|
85
|
-
|
86
|
-
# File name safe version of the to_s output.
|
87
|
-
#
|
88
|
-
# The output should be safe to use as a file name to store work item
|
89
|
-
# data. Typical use is when extra file items are created by a task and need to be stored on disk. The default
|
90
|
-
# implementation URL-encodes (%xx) all characters except alphanumeric, '.' and '-'.
|
91
|
-
#
|
92
|
-
# @return [String] file name
|
93
|
-
def to_filename
|
94
|
-
self.to_s.gsub(/[^\w.-]/) { |s| '%%%02x' % s.ord }
|
95
|
-
end
|
96
|
-
|
97
|
-
# Iterates over the work item clients and invokes code on each of them.
|
98
|
-
def each(&block)
|
99
|
-
self.items.each(&block)
|
100
|
-
end
|
101
|
-
|
102
|
-
def size
|
103
|
-
self.items.size
|
104
|
-
end
|
105
|
-
|
106
|
-
alias_method :count, :size
|
107
|
-
|
108
|
-
# Add a child work item
|
109
|
-
#
|
110
|
-
# @param [WorkItem] item to be added to the child list :items
|
111
|
-
def add_item(item)
|
112
|
-
return self unless item and item.is_a?(Libis::Workflow::Base::WorkItem)
|
113
|
-
self.items << item
|
114
|
-
item.parent = self
|
115
|
-
self.save!
|
116
|
-
item.save!
|
117
|
-
self
|
118
|
-
end
|
119
|
-
|
120
|
-
alias_method :<<, :add_item
|
121
|
-
|
122
|
-
# Get list of items.
|
123
|
-
#
|
124
|
-
# This method should return a list of items that can be accessed during long processing times.
|
125
|
-
def get_items
|
126
|
-
self.items
|
127
|
-
end
|
128
|
-
|
129
|
-
# Get list of items.
|
130
|
-
#
|
131
|
-
# This method should return a list of items that is safe to iterate over while it is being altered.
|
132
|
-
def get_item_list
|
133
|
-
self.items.dup
|
134
|
-
end
|
135
|
-
|
136
|
-
# Return item's parent
|
137
|
-
# @return [Libis::Workflow::Base::WorkItem]
|
138
|
-
def get_parent
|
139
|
-
self.parent
|
140
|
-
end
|
141
|
-
|
142
|
-
# go up the hierarchy and return the topmost work item
|
143
|
-
#
|
144
|
-
# @return [Libis::Workflow::Base::WorkItem]
|
145
|
-
def get_root
|
146
|
-
self.get_parent && self.get_parent.is_a?(Libis::Workflow::Base::WorkItem) && self.get_parent.get_root || self
|
147
|
-
end
|
148
|
-
|
149
|
-
# Get the top
|
150
|
-
#
|
151
|
-
# @return [Libis::Workflow::Base::Run]
|
152
|
-
def get_run
|
153
|
-
return self if self.is_a?(Libis::Workflow::Base::Run)
|
154
|
-
self.get_parent && self.get_parent.get_run || nil
|
155
|
-
end
|
156
|
-
|
157
|
-
# Dummy method. It is a placeholder for DB backed implementations. Wherever appropriate WorkItem#save will be
|
158
|
-
# called to save the current item's state. If state needs to persisted, you should override this method or make
|
159
|
-
# sure your persistence layer implements it in your class.
|
160
|
-
def save
|
161
|
-
end
|
162
|
-
|
163
|
-
# Dummy method. It is a placeholder for DB backed implementations. Wherever appropriate WorkItem#save will be
|
164
|
-
# called to save the current item's state. If state needs to persisted, you should override this method or make
|
165
|
-
# sure your persistence layer implements it in your class.
|
166
|
-
def save!
|
167
|
-
end
|
168
|
-
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
1
|
+
require 'backports/rails/hash'
|
2
|
+
require 'libis/tools/extend/hash'
|
3
|
+
|
4
|
+
require 'libis/workflow/config'
|
5
|
+
require 'libis/workflow/status'
|
6
|
+
require_relative 'logging'
|
7
|
+
|
8
|
+
module Libis
|
9
|
+
module Workflow
|
10
|
+
module Base
|
11
|
+
|
12
|
+
# Base module for all work items.
|
13
|
+
#
|
14
|
+
# This module lacks the implementation for the data attributes. It functions as an interface that describes the
|
15
|
+
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
16
|
+
#
|
17
|
+
# - parent: [Object|nil] a link to a parent work item. Work items can be organized in any hierarchy you think is
|
18
|
+
# relevant for your workflow (e.g. directory[/directory...]/file/line or library/section/book/page). Of course
|
19
|
+
# hierarchies are not mandatory.
|
20
|
+
# - items: [Array] a list of child work items. see above.
|
21
|
+
# - options: [Hash] a set of options for the task chain on how to deal with this work item. This attribute can be
|
22
|
+
# used to fine-tune the behaviour of tasks for a particular work item.
|
23
|
+
# - properties: [Hash] a set of properties, typically collected during the workflow processing and used to store
|
24
|
+
# final or intermediate resulst of tasks. The ::Lias::Ingester::FileItem module uses this attribute to store the
|
25
|
+
# properties (e.g. size, checksum, ...) of the file it represents.
|
26
|
+
# - status_log: [Array] a list of all status changes the work item went through.
|
27
|
+
# - summary: [Hash] collected statistics about the ingest for the work item and its children. This structure will
|
28
|
+
# be filled in by the included task ::Lias::Ingester::Tasks::Analyzer wich is appended to the workflow by default.
|
29
|
+
#
|
30
|
+
# The module is created so that it is possible to implement an ActiveRecord/Datamapper/... implementation easily.
|
31
|
+
# A simple in-memory implementation would require:
|
32
|
+
#
|
33
|
+
# attr_accessor :parent
|
34
|
+
# attr_accessor :items
|
35
|
+
# attr_accessor :options, :properties
|
36
|
+
# attr_accessor :status_log
|
37
|
+
# attr_accessor :summary
|
38
|
+
#
|
39
|
+
# def initialize
|
40
|
+
# self.parent = nil
|
41
|
+
# self.items = []
|
42
|
+
# self.options = {}
|
43
|
+
# self.properties = {}
|
44
|
+
# self.status_log = []
|
45
|
+
# self.summary = {}
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# protected
|
49
|
+
#
|
50
|
+
# ## Method below should be adapted to match the implementation of the status array
|
51
|
+
#
|
52
|
+
# def add_status_log(info)
|
53
|
+
# self.status_log << info
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
#
|
57
|
+
module WorkItem
|
58
|
+
include Enumerable
|
59
|
+
include Libis::Workflow::Status
|
60
|
+
include Libis::Workflow::Base::Logging
|
61
|
+
|
62
|
+
# String representation of the identity of the work item.
|
63
|
+
#
|
64
|
+
# You may want to overwrite this method as it tries the :name property or whatever #inspect returns if that
|
65
|
+
# failes. Typically this should return the key value, file name or id number. If that's what your :name property
|
66
|
+
# contains, you're fine.
|
67
|
+
#
|
68
|
+
# @return [String] string identification for this work item.
|
69
|
+
def name
|
70
|
+
# noinspection RubyResolve
|
71
|
+
self.properties['name'] || self.inspect
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s;
|
75
|
+
self.name;
|
76
|
+
end
|
77
|
+
|
78
|
+
def names
|
79
|
+
(self.parent.names rescue Array.new).push(name).compact
|
80
|
+
end
|
81
|
+
|
82
|
+
def namepath;
|
83
|
+
self.names.join('/');
|
84
|
+
end
|
85
|
+
|
86
|
+
# File name safe version of the to_s output.
|
87
|
+
#
|
88
|
+
# The output should be safe to use as a file name to store work item
|
89
|
+
# data. Typical use is when extra file items are created by a task and need to be stored on disk. The default
|
90
|
+
# implementation URL-encodes (%xx) all characters except alphanumeric, '.' and '-'.
|
91
|
+
#
|
92
|
+
# @return [String] file name
|
93
|
+
def to_filename
|
94
|
+
self.to_s.gsub(/[^\w.-]/) { |s| '%%%02x' % s.ord }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Iterates over the work item clients and invokes code on each of them.
|
98
|
+
def each(&block)
|
99
|
+
self.items.each(&block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def size
|
103
|
+
self.items.size
|
104
|
+
end
|
105
|
+
|
106
|
+
alias_method :count, :size
|
107
|
+
|
108
|
+
# Add a child work item
|
109
|
+
#
|
110
|
+
# @param [WorkItem] item to be added to the child list :items
|
111
|
+
def add_item(item)
|
112
|
+
return self unless item and item.is_a?(Libis::Workflow::Base::WorkItem)
|
113
|
+
self.items << item
|
114
|
+
item.parent = self
|
115
|
+
self.save!
|
116
|
+
item.save!
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
alias_method :<<, :add_item
|
121
|
+
|
122
|
+
# Get list of items.
|
123
|
+
#
|
124
|
+
# This method should return a list of items that can be accessed during long processing times.
|
125
|
+
def get_items
|
126
|
+
self.items
|
127
|
+
end
|
128
|
+
|
129
|
+
# Get list of items.
|
130
|
+
#
|
131
|
+
# This method should return a list of items that is safe to iterate over while it is being altered.
|
132
|
+
def get_item_list
|
133
|
+
self.items.dup
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return item's parent
|
137
|
+
# @return [Libis::Workflow::Base::WorkItem]
|
138
|
+
def get_parent
|
139
|
+
self.parent
|
140
|
+
end
|
141
|
+
|
142
|
+
# go up the hierarchy and return the topmost work item
|
143
|
+
#
|
144
|
+
# @return [Libis::Workflow::Base::WorkItem]
|
145
|
+
def get_root
|
146
|
+
self.get_parent && self.get_parent.is_a?(Libis::Workflow::Base::WorkItem) && self.get_parent.get_root || self
|
147
|
+
end
|
148
|
+
|
149
|
+
# Get the top
|
150
|
+
#
|
151
|
+
# @return [Libis::Workflow::Base::Run]
|
152
|
+
def get_run
|
153
|
+
return self if self.is_a?(Libis::Workflow::Base::Run)
|
154
|
+
self.get_parent && self.get_parent.get_run || nil
|
155
|
+
end
|
156
|
+
|
157
|
+
# Dummy method. It is a placeholder for DB backed implementations. Wherever appropriate WorkItem#save will be
|
158
|
+
# called to save the current item's state. If state needs to persisted, you should override this method or make
|
159
|
+
# sure your persistence layer implements it in your class.
|
160
|
+
def save
|
161
|
+
end
|
162
|
+
|
163
|
+
# Dummy method. It is a placeholder for DB backed implementations. Wherever appropriate WorkItem#save will be
|
164
|
+
# called to save the current item's state. If state needs to persisted, you should override this method or make
|
165
|
+
# sure your persistence layer implements it in your class.
|
166
|
+
def save!
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|