libis-workflow 2.0.beta.19-java

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 (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