libis-workflow 2.0.beta.19-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +36 -0
  4. data/.travis.yml +32 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +21 -0
  7. data/README.md +397 -0
  8. data/Rakefile +7 -0
  9. data/lib/libis/exceptions.rb +8 -0
  10. data/lib/libis/workflow/action.rb +24 -0
  11. data/lib/libis/workflow/base/dir_item.rb +15 -0
  12. data/lib/libis/workflow/base/file_item.rb +82 -0
  13. data/lib/libis/workflow/base/job.rb +85 -0
  14. data/lib/libis/workflow/base/logger.rb +30 -0
  15. data/lib/libis/workflow/base/logging.rb +76 -0
  16. data/lib/libis/workflow/base/run.rb +86 -0
  17. data/lib/libis/workflow/base/work_item.rb +176 -0
  18. data/lib/libis/workflow/base/workflow.rb +153 -0
  19. data/lib/libis/workflow/base.rb +7 -0
  20. data/lib/libis/workflow/config.rb +24 -0
  21. data/lib/libis/workflow/dir_item.rb +12 -0
  22. data/lib/libis/workflow/file_item.rb +17 -0
  23. data/lib/libis/workflow/job.rb +26 -0
  24. data/lib/libis/workflow/message_registry.rb +32 -0
  25. data/lib/libis/workflow/run.rb +26 -0
  26. data/lib/libis/workflow/status.rb +83 -0
  27. data/lib/libis/workflow/task.rb +287 -0
  28. data/lib/libis/workflow/task_group.rb +62 -0
  29. data/lib/libis/workflow/tasks/analyzer.rb +49 -0
  30. data/lib/libis/workflow/version.rb +7 -0
  31. data/lib/libis/workflow/work_item.rb +43 -0
  32. data/lib/libis/workflow/worker.rb +42 -0
  33. data/lib/libis/workflow/workflow.rb +22 -0
  34. data/lib/libis/workflow.rb +40 -0
  35. data/lib/libis-workflow.rb +2 -0
  36. data/libis-workflow.gemspec +38 -0
  37. data/spec/items/test_dir_item.rb +15 -0
  38. data/spec/items/test_file_item.rb +18 -0
  39. data/spec/items/test_run.rb +10 -0
  40. data/spec/items.rb +3 -0
  41. data/spec/spec_helper.rb +8 -0
  42. data/spec/task_spec.rb +16 -0
  43. data/spec/tasks/camelize_name.rb +13 -0
  44. data/spec/tasks/checksum_tester.rb +33 -0
  45. data/spec/tasks/collect_files.rb +48 -0
  46. data/spec/workflow_spec.rb +188 -0
  47. metadata +196 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c33864ac6963e1e65b061ec72575a3a78c5297ec
4
+ data.tar.gz: dd8d3ad399c31eb235b87df55d58e7dee65a6062
5
+ SHA512:
6
+ metadata.gz: fbd0c33ede85632502787118d8398febec7f56828270d40409c396fbc3689ab8204f9f7fde4784cd3912cf4c0278f706845f1baf241651a03b2929155707f41e
7
+ data.tar.gz: 1028ba91dde40522ac90cf2696c6ba19950d0659cc7bf5636db297eeb078a91d003611bf7661ac08a482ecd31ed59ae518e071a6ccf90338242eadb52b4b0dca
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: TMosCEIw4eu2hK05NxyY2UYIRJYQPzemt
data/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ .idea/
data/.travis.yml ADDED
@@ -0,0 +1,32 @@
1
+ language: ruby
2
+ sudo: false
3
+ bundler_args: --without development
4
+ cache: bundler
5
+ rvm:
6
+ - 2.1.0
7
+ - 2.2.0
8
+ - ruby-head
9
+ - jruby-9.0.1.0
10
+ jdk:
11
+ - openjdk7
12
+ - oraclejdk7
13
+ - oraclejdk8
14
+ matrix:
15
+ exclude:
16
+ - rvm: 2.1.0
17
+ jdk: oraclejdk7
18
+ - rvm: 2.1.0
19
+ jdk: oraclejdk8
20
+ - rvm: 2.2.0
21
+ jdk: oraclejdk7
22
+ - rvm: 2.2.0
23
+ jdk: oraclejdk8
24
+ - rvm: ruby-head
25
+ jdk: oraclejdk7
26
+ - rvm: ruby-head
27
+ jdk: oraclejdk8
28
+ allow_failures:
29
+ - rvm: ruby-head
30
+ branches:
31
+ only:
32
+ - master
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec name: 'libis-workflow', development_group: :test
4
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 LIBIS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,397 @@
1
+
2
+ [![Build Status](https://travis-ci.org/Kris-LIBIS/workflow.svg?branch=master)](https://travis-ci.org/Kris-LIBIS/workflow)
3
+ [![Coverage Status](https://img.shields.io/coveralls/Kris-LIBIS/workflow.svg)](https://coveralls.io/r/Kris-LIBIS/workflow)
4
+
5
+ # LIBIS Workflow
6
+
7
+ LIBIS Workflow framework
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'libis-workflow'
15
+ ```
16
+
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install 'libis-workflow'
25
+
26
+ ## Architecture
27
+
28
+ This gem is essentially a simple, custom workflow system. The core of the workflow are the tasks. You can - and should -
29
+ create your own tasks by creating new classes inherited from ::Libis::Workflow::Task. The ::Libis::Workflow::Task class
30
+ and the included ::Libis::Workflow::Base::Logger module provide the necessary attributes and methods to make them work
31
+ in the workflow. See the detailed documentation for the class and module for more information.
32
+
33
+ The objects that the tasks will be working on should include the ::Libis::Workflow::Base::WorkItem module.
34
+ When working with file objects the module ::Libis::Workflow::Base::FileItem and/or ::Libis::Workflow::Base::DirItem
35
+ modules should be included for additional file-specific functionality.
36
+ Work items can be organized in different types and a hierarchical structure. A simple implementation of work items with
37
+ in-memory storage is provided as classes ::Libis::Workflow::WorkItem, ::Libis::Workflow::FileItem and
38
+ ::Libis::Workflow::DirItem.
39
+
40
+ All the tasks will be organized into a workflow object for which a base module ::Libis::Workflow::Base::Workflow is
41
+ provided. It contains all the basic logic required for proper configuration and operation. Again a in-memory
42
+ implementation is provided in the class ::Libis::Workflow::Workflow for your convenience to be used as-is or to derive
43
+ your own from.
44
+
45
+ The Job class is responsible for instantiating a run-time workflow execution object - a Run - that captures the
46
+ configuration, logs and workitems generated while executing the tasks. Essential logic is provided in the module
47
+ ::Libis::Workflow::Base::Run with a simple in-memory implementation in ::Libis::Workflow::Run. The run object's class
48
+ name has to be provided to the job configuration so that the job can instantiate the correct object. The run object
49
+ will be able to execute the tasks in proper order on all the WorkItems supplied/collected. Each task can be implemented
50
+ with code to run or simply contain a list of child tasks.
51
+
52
+ One task is predefined:
53
+ ::Libis::Workflow::Tasks::Analyzer - analyzes the workflow run and summarizes the results. It is always included as the
54
+ last task by the workflow unless you supply a closing task called 'Analyzer' yourself.
55
+
56
+ The whole ingester workflow is configured by a Singleton object ::Libis::Workflow::Config which contains settings for
57
+ logging and paths where tasks and workitems can be found.
58
+
59
+ ## Usage
60
+
61
+ You should start by including the following line in your source code:
62
+
63
+ ```ruby
64
+ require 'libis-workflow'
65
+ ```
66
+
67
+ This will load all of the Libis Workflow framework into your environment, but including only the required parts is OK as
68
+ well. This is shown in the examples below.
69
+
70
+ ### Workflows and Jobs
71
+
72
+ An implementation of ::Libis::Workflow::Base::Workflow contains the definition of a workflow. Once instantiated, it can
73
+ be run by calling the 'execute' method on a job object created for that workflow. This will create an intance of an
74
+ implementation of ::Libis::Workflow::Base::Run, configure it and call the 'run' method on it. The Workflow constructor
75
+ takes no arguments, but is should be configured by calling the 'configure' method with the workflow configuration as an
76
+ argument. The job's 'execute' method takes an option Hash as argument with extra/overriding configuration values.
77
+
78
+ ### Job configuration
79
+ A job configuration is a Hash with:
80
+ * name: String to identify the workflow
81
+ * description: String with detailed textual information
82
+ * workflow: Object reference to a Workflow that contains the task configuration
83
+ * run_object: String with class name of the ::Libis::Workflow::Base::Run implementation to be created. An istance of
84
+ this class will be created for each run and serves as the root work item for that particular run.
85
+ * input: Hash with input parameter values for the workflow
86
+
87
+ #### Workflow configuration
88
+
89
+ A workflow configuration is a Hash with:
90
+ * name: String to identify the workflow
91
+ * description: String with detailed textual information
92
+ * tasks: Array of task descriptions
93
+ * input: Hash with input variable definitions
94
+
95
+ ##### Task description
96
+
97
+ is a Hash with:
98
+ * class: String with class name of the task
99
+ * name: String with the name of the task
100
+ * tasks: Array with task definitions of sub-tasks
101
+ * any task parameter values. Each task can define parameters that configure the task. It is using the
102
+ ::Libis::Tools::Parameter class for this.
103
+
104
+ The ::Libis::Workflow::Task base class allready defines the following parameters:
105
+ * quiet: Prevent generating log output. Default: false
106
+ * recursive: Run the task on all subitems recursively. Default: false
107
+ * retry_count: Number of times to retry the task. Default: 0
108
+ * retry_interval: Number of seconds to wait between retries. Default: 10
109
+
110
+ If 'class' is not present, the default '::Libis::Workflow::TaskGroup' with the given name will be instantiated, which
111
+ performs each sub-task on the item. If the task is configured to be recursive, it will iterate over the child items and
112
+ perform each sub-task on each of the child items. If a 'class' value is given, an instance of that class will be created
113
+ and the task will be handed the work item to process on. See the chapter on 'Tasks' below for more information on tasks.
114
+
115
+ Note that a task with custom processing will not execute sub-tasks. If you configured a processing task with subtasks
116
+ an exception will be thrown when trying to execute the job.
117
+
118
+ ##### Input variable definition
119
+
120
+ The input variables define parameters for the workflow. When a job is executed, it can provide values for any of these
121
+ input variables and the workflow run will use the new values instead of the defaults.
122
+
123
+ The key of the input Hash is the unique name of the variable. The value is another Hash with the parameter definition.
124
+ See ::Libis::Tools::Parameter for the content of this Hash.
125
+
126
+ An additional property of the parameters is the 'propagate_to' property. It defines how the workflow run should push
127
+ the values set for the input parameters to the parameters on the tasks. These task parameters can be addressed by a
128
+ '<Task class or Task name>[#<parameter name>]' string. If necessary the task class or name may be specified as a full
129
+ path with '/' separators. The parameter name part is optional and considered to be the same as the input parameter name
130
+ if absent.
131
+
132
+ #### Run-time configuration
133
+
134
+ The job's 'execute' method takes an optional Hash as argument which will complement and override the options Hash
135
+ described in the previous chapter.
136
+
137
+ Once the workflow is configured and the root work item instantiated, the method will run each top-level task on the root
138
+ work item in sequence until all tasks have completed successfully or a task has failed.
139
+
140
+ ### Work items
141
+
142
+ Creating your own work items is highly recommended and is fairly easy:
143
+
144
+ ```ruby
145
+
146
+ require 'libis/workflow'
147
+
148
+ class MyWorkItem < ::Libis::Workflow::WorkItem
149
+ attr_accesor :name
150
+
151
+ def initialize
152
+ @name = 'My work item'
153
+ super # Note: this is important as the base class requires some initialization
154
+ end
155
+ end
156
+ ```
157
+
158
+ or if a custom storage implementation is desired, a number of data items and methods require implementation:
159
+
160
+ ```ruby
161
+
162
+ require 'libis/workflow'
163
+
164
+ class MyWorkItem < MyStorageItem
165
+ include ::Libis::Workflow::Base::WorkItem
166
+
167
+ stored_attribute :parent
168
+ stored_attribute :items
169
+ stored_attribute :options
170
+ stored_attribute :properties
171
+ stored_attribute :log_history
172
+ stored_attribute :status_log
173
+ stored_attribute :summary
174
+
175
+ def initialize
176
+ self.parent = nil
177
+ self.items = []
178
+ self.options = {}
179
+ self.properties = {}
180
+ self.log_history = []
181
+ self.status_log = []
182
+ self.summary = {}
183
+ end
184
+
185
+ protected
186
+
187
+ def add_log_entry(msg)
188
+ self.log_history << msg.merge(c_at: ::Time.now)
189
+ end
190
+
191
+ def add_status_log(message, tasklist = nil)
192
+ self.status_log << { timestamp: ::Time.now, tasklist: tasklist, text: message }.cleanup
193
+ end
194
+
195
+ def status_label(status_entry)
196
+ "#{status_entry[:tasklist].last rescue nil}#{status_entry[:text] rescue nil}"
197
+ end
198
+
199
+ end
200
+ ```
201
+
202
+ Work items that are file-based can derive from the ::Libis::Workflow::FileItem class:
203
+
204
+ ```ruby
205
+
206
+ require 'libis/workflow'
207
+
208
+ class MyFileItem < ::Libis::Workflow::FileItem
209
+
210
+ def initialize(file)
211
+ filename = file
212
+ super
213
+ end
214
+
215
+ def filesize
216
+ properties[:size]
217
+ end
218
+
219
+ def fixity_check(checksum)
220
+ properties[:checksum] == checksum
221
+ end
222
+
223
+ end
224
+ ```
225
+
226
+ or include the ::Libis::Workflow::Base::FileItem module:
227
+
228
+ ```ruby
229
+
230
+ require 'libis/workflow'
231
+
232
+ class MyFileItem < MyWorkItem
233
+ include ::Libis::Workflow::FileItem
234
+
235
+ def initialize(file)
236
+ filename = file
237
+ super
238
+ end
239
+
240
+ def filesize
241
+ properties[:size]
242
+ end
243
+
244
+ def fixity_check(checksum)
245
+ properties[:checksum] == checksum
246
+ end
247
+
248
+ end
249
+ ```
250
+
251
+
252
+
253
+ ## Tasks
254
+
255
+ Tasks should inherit from ::Libis::Workflow::Task and specify the actions it wants to
256
+ perform on each work item:
257
+
258
+ ```ruby
259
+
260
+ class MyTask < ::Libis::Workflow::Task
261
+
262
+ def process_item(item)
263
+ if do_something(item)
264
+ info "Did something"
265
+ else
266
+ raise ::Libis::WorkflowError, "Something went wrong"
267
+ end
268
+ rescue Exception => e
269
+ error "Fatal problem, aborting"
270
+ raise ::Libis::WorkflowAbort, "Fatal problem"
271
+ ensure
272
+ item
273
+ end
274
+
275
+ end
276
+ ```
277
+
278
+ As seen above, the task should define a method called process_item that takes one argument. The argument will be a
279
+ reference to the work item that it needs to perform an action on. The task has several option to progress after
280
+ performing its actions:
281
+ * return. This is considered a normal and successful operation result. After a successful return the item's status will
282
+ be set to 'done' for the given task.
283
+ * raise a ::Libis::WorkflowError. Indicates that something went wrong during the processing of the item. The item's
284
+ status will be set to failed for the given task and the exception message will be printed in the error log. Processing
285
+ will continue with the next item. This action is recommended for temporary or recoverable errors. The parent item will
286
+ be flagged as 'failed' if any of the child items failed.
287
+ * raise a ::Libis::WorkflowAbort. A severe and fatal error has occured. Processing will abort immediately and the
288
+ failure status will be escalated to all items up the item hierarchy. Due to the escalating behaviour, no message is
289
+ printed in the error log automatically, so it is up to the task to an appropriate log the error itself.
290
+ * raise any other Exception. Should be avoided, but if it happens nevertheless, it will cause the item to fail for the
291
+ given task and the exception message to be logged in the error log. It will not attempt to process the other items.
292
+
293
+ ### Controlling behavior with parameters
294
+
295
+ You have some options to control how the task will behave in special cases. These are controlled using parameters on
296
+ the task, which can be set (and fixed with the 'frozen' option) on the task, but can be configured at run-time with the
297
+ help of workflow input parameters and run options.
298
+
299
+ #### Preventing any logging output from the task
300
+
301
+ Logging output can be blocked on a task-by-task basis by setting the 'quiet' parameter to true. Probably not usefull
302
+ except for the Analyzer task where the parameter is fixed to true. Logging output would otherwise intervene with the
303
+ log summary processing performed by the task.
304
+
305
+ #### Performing an action on the work item and all child items recursively
306
+
307
+ With the 'recursive' parameter set to true, your task's process_item method will be called for the work item and then
308
+ once for each child and each child's children recursively.
309
+
310
+ Note: you should not make both parent and child tasks recursive as this will cause the subitems to be processed
311
+ multiple times. If you make the parent task recursive, all tasks and sub-tasks will be performed on each item in the
312
+ tree. Making the child tasks recursive makes the parent task only perform on the top item and then performs each
313
+ sub-task one-by-one for the whole item tree. The last option is the most efficient.
314
+
315
+ Attention should be paid for the
316
+
317
+ #### Retrying if task failed
318
+
319
+ The parameters 'retry_count' and 'retry_interval' control the task's behaviour if a task has to wait for a result for an
320
+ asynchonous job. A task could be waiting for a result from the other job which will be indicated by a 'ASYNC_WAIT'
321
+ status. Alternatively the task may know that the job is halted and waiting for user interaction, indicated with the
322
+ 'ASYNC_HALT' status. Only when the status is 'ASYNC_WAIT', the task will retry its process. By default the 'retry_count'
323
+ is 0, which causes the task not to retry. Before retrying the task will pause for the number of seconds given in the
324
+ parameter 'retry_interval', which is 30 by default.
325
+
326
+ ### Pre- and postprocessing
327
+
328
+ The default implementation of 'process' is to call 'pre_process' and then call 'process_item' on each child item,
329
+ followed by calling 'post_process'. The methods 'pre_process' and 'post_process' are no-operation methods by default,
330
+ but can be overwritten if needed.
331
+
332
+ The 'pre_process' is intended to re-initialize the task before processing a new item. It can also be used to force the
333
+ task to skip processing the items altogether by calling the 'skip_processing_item' method or to prevent a recursive
334
+ task from traveling further down the item tree by calling the 'stop_processing_subitems' method. The temporary locks
335
+ behave as reset-on-read switches and are only active for the processing of the current item.
336
+
337
+ The 'post_process' method can be used to update any object after the item processing.
338
+
339
+ ### Convenience functions
340
+
341
+ #### get_root_item()
342
+
343
+ Returns the work item that the workflow started with (and is the root/grand parent of all work items in the ingest run).
344
+
345
+ #### get_work_dir()
346
+
347
+ Returns the work directory as configured for the current ingest run. The work directory can be used as scrap directory
348
+ for creating derived files that can be added as work items to the current flow or for downloading files that will be
349
+ processed later. The work directory is not automaticaly cleaned up, which is considered a task for the workflow implementation.
350
+
351
+ #### capture_cmd(cmd, *args)
352
+
353
+ Allows the task to run an external command-line program and capture it's stdout and stderr output at the same time. The
354
+ first argument is mandatory and should be the command-line program that has to be executed. An arbitrary number of
355
+ command-line arguments may follow.
356
+
357
+ The return value is an array with three elements: the status code returned by the command, the stdout string and the
358
+ stderr string.
359
+
360
+ #### names()
361
+
362
+ An array of strings with the hierarchical path of tasks leading to the current task. Can be usefull for log messages.
363
+ The method 'namepath' returns a '/' separated path of tasks.
364
+
365
+ #### (debug/info/warn/error/fatal)(message, *args)
366
+
367
+ Convenience function for creating log entries. The logger set in ::Libis::Workflow::Config is used to dump log messages.
368
+
369
+ The first argument is mandatory and can be:
370
+ * an integer. The integer is used to look up the message text in ::Libis::Workflow::MessageRegistry.
371
+ * a static string. The message text is used as-is.
372
+ * a string with placement holders as used in String#%. Args can either be an array or a hash. See also Kernel#sprintf.
373
+
374
+ The log message is logged to the general logging and attached to the current work item (workitem) unless another
375
+ work item is passed as first argument after the message.
376
+
377
+ #### check_item_type(klass, item = nil)
378
+
379
+ Checks if the work item is of the given class. 'workitem' is checked if the item argument is not present. If the check
380
+ fails a Runtime exception is thrown which will cause the task to abort if not catched.
381
+
382
+ #### item_type?(klass, item = nil)
383
+
384
+ A less severe variant version of check_item_type which returns a boolean (false if failed).
385
+
386
+ #### to_status(status)
387
+
388
+ Simply prepends the status text with the current task name. The output of this function is typically what the work item
389
+ status field should be set at.
390
+
391
+ ## Contributing
392
+
393
+ 1. Fork it ( https://github.com/libis/workflow/fork )
394
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
395
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
396
+ 4. Push to the branch (`git push origin my-new-feature`)
397
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ desc 'run tests'
7
+ task :default => :spec
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ module Libis
4
+ class WorkflowError < ::RuntimeError
5
+ end
6
+ class WorkflowAbort < ::RuntimeError
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module Libis
2
+ module Workflow
3
+ module Action
4
+
5
+ RUN = 0
6
+ CONTINUE = 1
7
+ RETRY = 2
8
+ ALWAYS_RUN = 3
9
+ FAILED = 4
10
+
11
+ def next_success_action(action)
12
+ case action
13
+ when :run, :continue, :retry, :always_run
14
+ :always_run
15
+ when :failed
16
+ :failed
17
+ else
18
+ :failed
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'libis/workflow/base/file_item'
4
+
5
+ module Libis
6
+ module Workflow
7
+ module Base
8
+
9
+ module DirItem
10
+ include ::Libis::Workflow::Base::FileItem
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+
3
+ require 'digest'
4
+
5
+ require 'libis/workflow/base/work_item'
6
+
7
+ module Libis
8
+ module Workflow
9
+ module Base
10
+
11
+ # noinspection RubyResolve
12
+ module FileItem
13
+ include Libis::Workflow::Base::WorkItem
14
+
15
+ def filename
16
+ File.basename(self.properties[:filename]) || self.properties[:link]
17
+ end
18
+
19
+ def name
20
+ self.properties[:name] || self.filename
21
+ end
22
+
23
+ def filelist
24
+ (self.parent.filelist rescue Array.new).push(filename).compact
25
+ end
26
+
27
+ def filepath
28
+ self.filelist.join('/')
29
+ end
30
+
31
+ def fullpath
32
+ self.properties[:filename]
33
+ end
34
+
35
+ def filename=(name)
36
+ begin
37
+ stats = ::File.stat name
38
+ self.properties[:size] = stats.size
39
+ self.properties[:access_time] = stats.atime
40
+ self.properties[:modification_time] = stats.mtime
41
+ self.properties[:creation_time] = stats.ctime
42
+ self.properties[:mode] = stats.mode
43
+ self.properties[:uid] = stats.uid
44
+ self.properties[:gid] = stats.gid
45
+ set_checksum(:MD5, ::Digest::MD5.hexdigest(File.read(name))) if File.file?(name)
46
+ rescue
47
+ # ignored
48
+ end
49
+ self.properties[:filename] = name
50
+ end
51
+
52
+ def checksum(checksum_type)
53
+ self.properties[('checksum_' + checksum_type.to_s.downcase).to_sym]
54
+ end
55
+
56
+ def set_checksum(checksum_type, value)
57
+ self.properties[('checksum_' + checksum_type.to_s.downcase).to_sym] = value
58
+ end
59
+
60
+ def link
61
+ self.properties[:link]
62
+ end
63
+
64
+ def link=(name)
65
+ self.properties[:link] = name
66
+ end
67
+
68
+ def set_info(info)
69
+ info.each do |k, v|
70
+ self.properties[k] = v
71
+ end
72
+ end
73
+
74
+ def safe_name
75
+ self.name.to_s.gsub(/[^\w.-]/) { |s| '%%%02x' % s.ord }
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end