tumugi 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +27 -1
- data/examples/event_callbacks.rb +37 -0
- data/lib/tumugi/cli.rb +14 -6
- data/lib/tumugi/command/new.rb +16 -60
- data/lib/tumugi/command/new/generator.rb +76 -0
- data/lib/tumugi/command/new/plugin_generator.rb +60 -0
- data/lib/tumugi/command/new/project_generator.rb +45 -0
- data/lib/tumugi/command/run.rb +2 -9
- data/lib/tumugi/dag_result_reporter.rb +5 -5
- data/lib/tumugi/data/new/{Gemfile.erb → plugin/Gemfile.erb} +0 -0
- data/lib/tumugi/data/new/{README.md.erb → plugin/README.md.erb} +0 -0
- data/lib/tumugi/data/new/{Rakefile.erb → plugin/Rakefile.erb} +0 -0
- data/lib/tumugi/data/new/{examples → plugin/examples}/example.rb.erb +0 -0
- data/lib/tumugi/data/new/{gemspec.erb → plugin/gemspec.erb} +0 -0
- data/lib/tumugi/data/new/{gitignore.erb → plugin/gitignore.erb} +0 -0
- data/lib/tumugi/data/new/{lib → plugin/lib}/tumugi/plugin/target/target.rb.erb +0 -0
- data/lib/tumugi/data/new/{lib → plugin/lib}/tumugi/plugin/task/task.rb.erb +0 -0
- data/lib/tumugi/data/new/{test → plugin/test}/plugin/target/target_test.rb.erb +0 -0
- data/lib/tumugi/data/new/{test → plugin/test}/plugin/task/task_test.rb.erb +0 -0
- data/lib/tumugi/data/new/{test → plugin/test}/test.rb.erb +0 -0
- data/lib/tumugi/data/new/{test → plugin/test}/test_helper.rb.erb +0 -0
- data/lib/tumugi/data/new/project/Gemfile.erb +3 -0
- data/lib/tumugi/data/new/project/tumugi_config.rb.erb +33 -0
- data/lib/tumugi/data/new/project/workflow.rb.erb +3 -0
- data/lib/tumugi/event.rb +11 -0
- data/lib/tumugi/executor/local_executor.rb +16 -12
- data/lib/tumugi/mixin/human_readable.rb +16 -0
- data/lib/tumugi/parameter/parameter.rb +10 -8
- data/lib/tumugi/task.rb +46 -3
- data/lib/tumugi/task_definition.rb +32 -4
- data/lib/tumugi/version.rb +1 -1
- data/lib/tumugi/workflow.rb +27 -11
- metadata +23 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1245ddebd2d69768433b3cfdea9ea0c3e39cff8
|
4
|
+
data.tar.gz: f40eded5362a22f951caf384411387758fb668ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1d78046c13e29e2f0cff749e54cfb020256de583c5561c9664edbabfcdae7a45fc64918b5cb4582a0ea7321e8f87932e0470365f142e12c792b82e432d94bff
|
7
|
+
data.tar.gz: b6745f25485a5aaa1e6ad494e468640209839fe77a7952ba955f888554f41764ccd31c6c983b04e6030a82e2e040f51af01d8f8d7c51b097ec62016ea5eb0bd0
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,28 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [v0.
|
3
|
+
## [v0.7.0](https://github.com/tumugi/tumugi/tree/v0.7.0) (2016-11-01)
|
4
|
+
[Full Changelog](https://github.com/tumugi/tumugi/compare/v0.6.3...v0.7.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Force run all tasks in a workflow [\#125](https://github.com/tumugi/tumugi/issues/125)
|
9
|
+
- Custom callback on success/retry/failure for each task [\#122](https://github.com/tumugi/tumugi/issues/122)
|
10
|
+
- Add secret option for parameter [\#117](https://github.com/tumugi/tumugi/issues/117)
|
11
|
+
- Add log about elapsed time for each tasks and workflow [\#116](https://github.com/tumugi/tumugi/issues/116)
|
12
|
+
- \[Breaking Change\] Introduce subcommand of `tumugi new` [\#111](https://github.com/tumugi/tumugi/issues/111)
|
13
|
+
|
14
|
+
**Merged pull requests:**
|
15
|
+
|
16
|
+
- Introduce success/failure event callback [\#128](https://github.com/tumugi/tumugi/pull/128) ([hakobera](https://github.com/hakobera))
|
17
|
+
- Support force run all tasks [\#127](https://github.com/tumugi/tumugi/pull/127) ([hakobera](https://github.com/hakobera))
|
18
|
+
- Write workflow and task elapsed time to log [\#124](https://github.com/tumugi/tumugi/pull/124) ([hakobera](https://github.com/hakobera))
|
19
|
+
- Filter coverage target files [\#121](https://github.com/tumugi/tumugi/pull/121) ([hakobera](https://github.com/hakobera))
|
20
|
+
- Test with jruby-9.1.5.0 on travis [\#120](https://github.com/tumugi/tumugi/pull/120) ([hakobera](https://github.com/hakobera))
|
21
|
+
- Introduce new sub commands [\#119](https://github.com/tumugi/tumugi/pull/119) ([hakobera](https://github.com/hakobera))
|
22
|
+
- Add param secret option [\#118](https://github.com/tumugi/tumugi/pull/118) ([hakobera](https://github.com/hakobera))
|
23
|
+
- Bumpup version to 0.7.0.dev [\#115](https://github.com/tumugi/tumugi/pull/115) ([hakobera](https://github.com/hakobera))
|
24
|
+
|
25
|
+
## [v0.6.3](https://github.com/tumugi/tumugi/tree/v0.6.3) (2016-08-13)
|
4
26
|
[Full Changelog](https://github.com/tumugi/tumugi/compare/v0.6.2...v0.6.3)
|
5
27
|
|
6
28
|
**Implemented enhancements:**
|
@@ -12,6 +34,10 @@
|
|
12
34
|
- Fix plugin template [\#112](https://github.com/tumugi/tumugi/pull/112) ([hakobera](https://github.com/hakobera))
|
13
35
|
- Fix commad failed error message [\#110](https://github.com/tumugi/tumugi/pull/110) ([hakobera](https://github.com/hakobera))
|
14
36
|
|
37
|
+
**Merged pull requests:**
|
38
|
+
|
39
|
+
- Prepare release for 0.6.3 [\#114](https://github.com/tumugi/tumugi/pull/114) ([hakobera](https://github.com/hakobera))
|
40
|
+
|
15
41
|
## [v0.6.2](https://github.com/tumugi/tumugi/tree/v0.6.2) (2016-08-02)
|
16
42
|
[Full Changelog](https://github.com/tumugi/tumugi/compare/v0.6.1...v0.6.2)
|
17
43
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
task :task1 do
|
2
|
+
requires [:task2, :task3]
|
3
|
+
run { log 'task1#run' }
|
4
|
+
end
|
5
|
+
|
6
|
+
task :task2 do
|
7
|
+
requires [:task4]
|
8
|
+
run { raise "error in #{id}" }
|
9
|
+
on_retry do
|
10
|
+
log 'task2#on_retry'
|
11
|
+
end
|
12
|
+
on_failure do
|
13
|
+
log 'task2#on_failure'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :task3 do
|
18
|
+
requires [:task4]
|
19
|
+
run { log 'task3#run' }
|
20
|
+
on_success do
|
21
|
+
log 'task3#on_success'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
task :task4 do
|
26
|
+
run do
|
27
|
+
log 'task4#run'
|
28
|
+
sleep 1
|
29
|
+
end
|
30
|
+
on_success do
|
31
|
+
log 'task4#on_success'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
on_failure do
|
36
|
+
log 'task1#on_failure'
|
37
|
+
end
|
data/lib/tumugi/cli.rb
CHANGED
@@ -30,6 +30,7 @@ module Tumugi
|
|
30
30
|
map "run" => "run_" # run is thor's reserved word, so this trick is needed
|
31
31
|
option :workers, aliases: '-w', type: :numeric, desc: 'Number of workers to run task concurrently'
|
32
32
|
option :out, aliases: '-o', desc: 'Output log filename. If not specified, log is write to STDOUT'
|
33
|
+
option :all, aliases: '-a', type: :boolean, desc: 'Run all tasks even if target exists', default: false
|
33
34
|
common_options
|
34
35
|
def run_(task)
|
35
36
|
execute(:run, task, options)
|
@@ -45,9 +46,14 @@ module Tumugi
|
|
45
46
|
execute(:show, task, opts.freeze)
|
46
47
|
end
|
47
48
|
|
48
|
-
desc "new
|
49
|
-
def new(name)
|
50
|
-
|
49
|
+
desc "new type NAME", "Create a new template of type. type is 'plugin' or 'project'"
|
50
|
+
def new(type, name)
|
51
|
+
generate_project(type, name, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "init", "Create an tumugi project template"
|
55
|
+
def init(path='')
|
56
|
+
generate_project('project', path, force: true)
|
51
57
|
end
|
52
58
|
|
53
59
|
private
|
@@ -55,6 +61,7 @@ module Tumugi
|
|
55
61
|
def execute(command, task, options)
|
56
62
|
logger.info "tumugi v#{Tumugi::VERSION}"
|
57
63
|
args = { task: task, options: options }
|
64
|
+
logger.info "status: running, command: #{command}, args: #{args}"
|
58
65
|
success = Tumugi.workflow.execute(command, task, options)
|
59
66
|
unless success
|
60
67
|
raise Thor::Error, "execute finished, but failed"
|
@@ -64,10 +71,11 @@ module Tumugi
|
|
64
71
|
handle_error(command, e, args)
|
65
72
|
end
|
66
73
|
|
67
|
-
def
|
74
|
+
def generate_project(type, name, options)
|
68
75
|
logger.info "tumugi v#{Tumugi::VERSION}"
|
69
|
-
args = { name: name, options: options }
|
70
|
-
|
76
|
+
args = { type: type, name: name, options: options }
|
77
|
+
logger.info "status: running, command: new, args: #{args}"
|
78
|
+
Tumugi::Command::New.new.execute(type, name, options)
|
71
79
|
logger.info "status: success, command: new, args: #{args}"
|
72
80
|
rescue => e
|
73
81
|
handle_error("new", e, args)
|
data/lib/tumugi/command/new.rb
CHANGED
@@ -1,71 +1,27 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative './new/plugin_generator'
|
2
|
+
require_relative './new/project_generator'
|
3
3
|
|
4
4
|
module Tumugi
|
5
5
|
module Command
|
6
6
|
class New
|
7
|
-
def execute(name, options={})
|
8
|
-
|
9
|
-
|
10
|
-
[ "Gemfile.erb", "Gemfile" ],
|
11
|
-
[ "gemspec.erb", "#{full_project_name}.gemspec" ],
|
12
|
-
[ "gitignore.erb", ".gitignore" ],
|
13
|
-
[ "Rakefile.erb", "Rakefile" ],
|
14
|
-
[ "README.md.erb", "README.md" ],
|
15
|
-
[ "examples/example.rb.erb", "examples/example.rb" ],
|
16
|
-
[ "lib/tumugi/plugin/target/target.rb.erb", "lib/tumugi/plugin/target/#{name}.rb" ],
|
17
|
-
[ "lib/tumugi/plugin/task/task.rb.erb", "lib/tumugi/plugin/task/#{name}.rb" ],
|
18
|
-
[ "test/test_helper.rb.erb", "test/test_helper.rb" ],
|
19
|
-
[ "test/test.rb.erb", "test/#{name}_test.rb" ],
|
20
|
-
[ "test/plugin/target/target_test.rb.erb", "test/plugin/target/#{name}_test.rb" ],
|
21
|
-
[ "test/plugin/task/task_test.rb.erb", "test/plugin/task/#{name}_test.rb" ],
|
22
|
-
]
|
23
|
-
|
24
|
-
@data_dir = "#{File.expand_path(File.dirname(__FILE__))}/../data/new"
|
25
|
-
@dest_dir = "#{(options[:path] || '.')}/#{full_project_name}"
|
26
|
-
if File.exist?(@dest_dir)
|
27
|
-
puts "#{@dest_dir} is already exists. Please delete it first"
|
28
|
-
return false
|
29
|
-
end
|
30
|
-
|
31
|
-
puts "Create #{@dest_dir}"
|
32
|
-
FileUtils.mkdir_p(@dest_dir)
|
33
|
-
|
34
|
-
templates.each do |value|
|
35
|
-
src_file, dest_file = value
|
36
|
-
eruby = Erubis::Eruby.new(File.read(src_path(src_file)))
|
37
|
-
eruby.filename = src_path(src_file)
|
38
|
-
context = {
|
39
|
-
full_project_name: full_project_name,
|
40
|
-
name: name,
|
41
|
-
tumugi_version: Tumugi::VERSION,
|
42
|
-
}
|
43
|
-
puts " Create #{dest_path(dest_file)}"
|
44
|
-
FileUtils.mkdir_p(File.dirname(dest_path(dest_file)))
|
45
|
-
File.write(dest_path(dest_file), eruby.result(context))
|
46
|
-
end
|
47
|
-
|
48
|
-
puts ""
|
49
|
-
puts "Plugin template is successfully generated."
|
50
|
-
puts "Next steps:"
|
51
|
-
puts ""
|
52
|
-
puts " $ cd #{full_project_name}"
|
53
|
-
puts " $ git init"
|
54
|
-
puts " $ bundle install"
|
55
|
-
puts " $ bundle exec rake"
|
56
|
-
puts ""
|
57
|
-
|
58
|
-
return true
|
7
|
+
def execute(type, name, options={})
|
8
|
+
generator = create_generator(type, name, options)
|
9
|
+
generator.generate
|
59
10
|
end
|
60
11
|
|
61
|
-
|
62
|
-
|
63
|
-
def src_path(file)
|
64
|
-
"#{@data_dir}/#{file}"
|
12
|
+
def logger
|
13
|
+
@logger ||= Tumugi::ScopedLogger.new("tumugi-new")
|
65
14
|
end
|
66
15
|
|
67
|
-
def
|
68
|
-
|
16
|
+
def create_generator(type, name, options)
|
17
|
+
case type
|
18
|
+
when "plugin"
|
19
|
+
PluginGenerator.new(name, options)
|
20
|
+
when "project"
|
21
|
+
ProjectGenerator.new(name, options)
|
22
|
+
else
|
23
|
+
raise Tumugi::TumugiError.new("Unsupported type of new sub command: #{type}")
|
24
|
+
end
|
69
25
|
end
|
70
26
|
end
|
71
27
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erubis'
|
3
|
+
|
4
|
+
module Tumugi
|
5
|
+
module Command
|
6
|
+
class New
|
7
|
+
class Generator
|
8
|
+
attr_reader :name, :options
|
9
|
+
|
10
|
+
def initialize(name, options={})
|
11
|
+
@name = name
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate
|
16
|
+
if File.exist?(dest_dir) && !options[:force]
|
17
|
+
logger.error "#{dest_dir} is already exists. Please delete it first"
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
logger.info "Create #{dest_dir}"
|
22
|
+
FileUtils.mkdir_p(dest_dir)
|
23
|
+
|
24
|
+
templates.each do |value|
|
25
|
+
src_file, dest_file = value
|
26
|
+
eruby = Erubis::Eruby.new(File.read(src_path(src_file)))
|
27
|
+
eruby.filename = src_path(src_file)
|
28
|
+
logger.info " Create #{dest_path(dest_file)}"
|
29
|
+
FileUtils.mkdir_p(File.dirname(dest_path(dest_file)))
|
30
|
+
File.write(dest_path(dest_file), eruby.result(context))
|
31
|
+
end
|
32
|
+
|
33
|
+
unless post_messages.empty?
|
34
|
+
post_messages.each{|msg| logger.info msg }
|
35
|
+
end
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def data_dir
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def dest_dir
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def templates
|
49
|
+
[]
|
50
|
+
end
|
51
|
+
|
52
|
+
def context
|
53
|
+
{}
|
54
|
+
end
|
55
|
+
|
56
|
+
def post_messages
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
|
60
|
+
def logger
|
61
|
+
@logger ||= Tumugi::ScopedLogger.new("tumugi-new")
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def src_path(file)
|
67
|
+
File.join(data_dir, file)
|
68
|
+
end
|
69
|
+
|
70
|
+
def dest_path(file)
|
71
|
+
File.join(dest_dir, file)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'generator'
|
2
|
+
|
3
|
+
module Tumugi
|
4
|
+
module Command
|
5
|
+
class New
|
6
|
+
class PluginGenerator < Generator
|
7
|
+
def data_dir
|
8
|
+
"#{File.expand_path(File.dirname(__FILE__))}/../../data/new/plugin"
|
9
|
+
end
|
10
|
+
|
11
|
+
def dest_dir
|
12
|
+
File.join(options[:path] || '.', full_project_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def templates
|
16
|
+
[
|
17
|
+
[ "Gemfile.erb", "Gemfile" ],
|
18
|
+
[ "gemspec.erb", "#{full_project_name}.gemspec" ],
|
19
|
+
[ "gitignore.erb", ".gitignore" ],
|
20
|
+
[ "Rakefile.erb", "Rakefile" ],
|
21
|
+
[ "README.md.erb", "README.md" ],
|
22
|
+
[ "examples/example.rb.erb", "examples/example.rb" ],
|
23
|
+
[ "lib/tumugi/plugin/target/target.rb.erb", "lib/tumugi/plugin/target/#{name}.rb" ],
|
24
|
+
[ "lib/tumugi/plugin/task/task.rb.erb", "lib/tumugi/plugin/task/#{name}.rb" ],
|
25
|
+
[ "test/test_helper.rb.erb", "test/test_helper.rb" ],
|
26
|
+
[ "test/test.rb.erb", "test/#{name}_test.rb" ],
|
27
|
+
[ "test/plugin/target/target_test.rb.erb", "test/plugin/target/#{name}_test.rb" ],
|
28
|
+
[ "test/plugin/task/task_test.rb.erb", "test/plugin/task/#{name}_test.rb" ],
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_project_name
|
33
|
+
"tumugi-plugin-#{name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def context
|
37
|
+
{
|
38
|
+
full_project_name: full_project_name,
|
39
|
+
name: name,
|
40
|
+
tumugi_version: Tumugi::VERSION,
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def post_messages
|
45
|
+
[
|
46
|
+
"",
|
47
|
+
"Plugin template is successfully generated.",
|
48
|
+
"Next steps:",
|
49
|
+
"",
|
50
|
+
" $ cd #{full_project_name}",
|
51
|
+
" $ git init",
|
52
|
+
" $ bundle install",
|
53
|
+
" $ bundle exec rake",
|
54
|
+
"",
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'generator'
|
2
|
+
|
3
|
+
module Tumugi
|
4
|
+
module Command
|
5
|
+
class New
|
6
|
+
class ProjectGenerator < Generator
|
7
|
+
def data_dir
|
8
|
+
"#{File.expand_path(File.dirname(__FILE__))}/../../data/new/project"
|
9
|
+
end
|
10
|
+
|
11
|
+
def dest_dir
|
12
|
+
File.join(options[:path] || '.', name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def templates
|
16
|
+
[
|
17
|
+
[ "Gemfile.erb", "Gemfile" ],
|
18
|
+
[ "workflow.rb.erb", "workflow.rb" ],
|
19
|
+
[ "tumugi_config.rb.erb", "tumugi_config.rb" ],
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def context
|
24
|
+
{
|
25
|
+
name: name,
|
26
|
+
tumugi_version: Tumugi::VERSION,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def post_messages
|
31
|
+
[
|
32
|
+
"",
|
33
|
+
"Project template is successfully generated.",
|
34
|
+
"Next steps:",
|
35
|
+
"",
|
36
|
+
name.empty? ? "" : " $ cd #{name}",
|
37
|
+
" $ bundle install",
|
38
|
+
" $ bundle exec tumugi -f workflow.rb main",
|
39
|
+
"",
|
40
|
+
]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/tumugi/command/run.rb
CHANGED
@@ -6,21 +6,14 @@ module Tumugi
|
|
6
6
|
class Run
|
7
7
|
def execute(dag, options={})
|
8
8
|
worker_num = options[:workers] || Tumugi.config.workers
|
9
|
-
executor = Tumugi::Executor::LocalExecutor.new(dag, worker_num: worker_num)
|
10
|
-
result =
|
9
|
+
executor = Tumugi::Executor::LocalExecutor.new(dag, worker_num: worker_num, run_all: options[:all])
|
10
|
+
result = executor.execute
|
11
11
|
show_result_report(dag)
|
12
12
|
result
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
16
16
|
|
17
|
-
def start(executor)
|
18
|
-
logger.info "workflow_start: #{Tumugi.workflow.id}"
|
19
|
-
result = executor.execute
|
20
|
-
logger.info "workflow_end: #{Tumugi.workflow.id}"
|
21
|
-
result
|
22
|
-
end
|
23
|
-
|
24
17
|
def show_result_report(dag)
|
25
18
|
reporter = Tumugi::DAGResultReporter.new
|
26
19
|
report = reporter.show(dag)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'terminal-table'
|
2
|
-
|
3
2
|
require 'tumugi/mixin/listable'
|
4
3
|
|
5
4
|
module Tumugi
|
@@ -7,18 +6,19 @@ module Tumugi
|
|
7
6
|
include Tumugi::Mixin::Listable
|
8
7
|
|
9
8
|
def show(dag)
|
10
|
-
headings = ['Task', 'Requires', 'Parameters', 'State']
|
9
|
+
headings = ['Task', 'Requires', 'Parameters', 'State', 'Elapsed']
|
11
10
|
Terminal::Table.new title: "Workflow Result", headings: headings do |t|
|
12
11
|
dag.tsort.map.with_index do |task, index|
|
13
12
|
proxy = task.class.merged_parameter_proxy
|
14
13
|
requires = list(task.requires).map do |r|
|
15
14
|
r.id
|
16
15
|
end
|
17
|
-
params = proxy.params.map do |name,
|
18
|
-
|
16
|
+
params = proxy.params.map do |name, param|
|
17
|
+
val = param.secret? ? '***' : truncate(task.send(name.to_sym).to_s, 25)
|
18
|
+
"#{name}=#{val}"
|
19
19
|
end
|
20
20
|
t << :separator if index != 0
|
21
|
-
t << [ task.id, requires.join("\n"), params.join("\n"), task.state ]
|
21
|
+
t << [ task.id, requires.join("\n"), params.join("\n"), task.state, task.elapsed_time ]
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Tumugi.configure do |config|
|
2
|
+
##############################################################################
|
3
|
+
# Number of worker threads for parallel execution, default value is 1.
|
4
|
+
# You can override this value by CLI '-w' option like:
|
5
|
+
#
|
6
|
+
# $ tumugi run -f workflow.rb main -w 2
|
7
|
+
##############################################################################
|
8
|
+
# config.workers = 1
|
9
|
+
|
10
|
+
##############################################################################
|
11
|
+
# Max retry count for each task, default value is 3.
|
12
|
+
##############################################################################
|
13
|
+
# config.max_retry = 3
|
14
|
+
|
15
|
+
##############################################################################
|
16
|
+
# Retry interval seconds for each task, default value is 300 seconds.
|
17
|
+
##############################################################################
|
18
|
+
# config.retry_interval = 300
|
19
|
+
|
20
|
+
##############################################################################
|
21
|
+
# Timeout seconds for each task, default value is nil, it means no timeout.
|
22
|
+
##############################################################################
|
23
|
+
# config.timeout = nil
|
24
|
+
|
25
|
+
##############################################################################
|
26
|
+
# If you use plugins and plugins support config section,
|
27
|
+
# define it like following.
|
28
|
+
##############################################################################
|
29
|
+
|
30
|
+
# config.section("section_name") do |section|
|
31
|
+
# section.key = "value"
|
32
|
+
# end
|
33
|
+
end
|
data/lib/tumugi/event.rb
ADDED
@@ -7,17 +7,18 @@ require 'tumugi/error'
|
|
7
7
|
module Tumugi
|
8
8
|
module Executor
|
9
9
|
class LocalExecutor
|
10
|
-
def initialize(dag, worker_num: 1)
|
10
|
+
def initialize(dag, worker_num: 1, run_all: false)
|
11
11
|
@dag = dag
|
12
12
|
@main_task = dag.tsort.last
|
13
|
-
@
|
13
|
+
@worker_num = worker_num
|
14
|
+
@run_all = run_all
|
14
15
|
@mutex = Mutex.new
|
15
16
|
end
|
16
17
|
|
17
18
|
def execute
|
18
19
|
pool = Concurrent::ThreadPoolExecutor.new(
|
19
|
-
min_threads: @
|
20
|
-
max_threads: @
|
20
|
+
min_threads: @worker_num,
|
21
|
+
max_threads: @worker_num
|
21
22
|
)
|
22
23
|
|
23
24
|
setup_task_queue(@dag)
|
@@ -27,7 +28,7 @@ module Tumugi
|
|
27
28
|
|
28
29
|
Concurrent::Future.execute(executor: pool) do
|
29
30
|
if !task.runnable?(Time.now)
|
30
|
-
logger.trace { "
|
31
|
+
logger.trace { "task_not_runnable: #{task.id}" }
|
31
32
|
enqueue_task(task)
|
32
33
|
else
|
33
34
|
begin
|
@@ -37,7 +38,8 @@ module Tumugi
|
|
37
38
|
task.run
|
38
39
|
end
|
39
40
|
task.trigger!(:complete)
|
40
|
-
logger.info { "task_#{task.state}: #{task.id}" }
|
41
|
+
logger.info { "task_#{task.state}: #{task.id}, elapsed_time: #{task.elapsed_time}" }
|
42
|
+
task.on_success
|
41
43
|
rescue => e
|
42
44
|
handle_error(task, e)
|
43
45
|
end
|
@@ -83,10 +85,10 @@ module Tumugi
|
|
83
85
|
|
84
86
|
if task.requires_failed?
|
85
87
|
task.trigger!(:requires_fail)
|
86
|
-
logger.info { "task_#{task.state}: #{task.id} has failed requires task" }
|
87
|
-
elsif task.completed?
|
88
|
+
logger.info { "task_#{task.state}: #{task.id} has failed requires task, elapsed_time: #{task.elapsed_time}" }
|
89
|
+
elsif task.completed? && !@run_all
|
88
90
|
task.trigger!(:skip)
|
89
|
-
logger.info { "task_#{task.state}: #{task.id} is already completed" }
|
91
|
+
logger.info { "task_#{task.state}: #{task.id} is already completed, elapsed_time: #{task.elapsed_time}" }
|
90
92
|
else
|
91
93
|
break task
|
92
94
|
end
|
@@ -102,15 +104,17 @@ module Tumugi
|
|
102
104
|
def handle_error(task, err)
|
103
105
|
if task.retry
|
104
106
|
task.trigger!(:pend)
|
107
|
+
logger.info { "task_#{task.state}: #{task.id} failed, elapsed_time: #{task.elapsed_time}" }
|
105
108
|
logger.error { "#{err.class}: '#{err.message}' - #{task.tries} tries and wait #{task.retry_interval} seconds until the next try." }
|
106
109
|
enqueue_task(task)
|
110
|
+
task.on_retry
|
107
111
|
else
|
108
112
|
task.trigger!(:fail)
|
113
|
+
logger.info { "task_#{task.state}: #{task.id} failed, elapsed_time: #{task.elapsed_time}" }
|
109
114
|
logger.error { "#{err.class}: '#{err.message}' - #{task.tries} tries and reached max retry count, so task #{task.id} failed." }
|
110
|
-
|
111
|
-
logger.error { err.backtrace.join("\n") }
|
115
|
+
task.on_failure
|
112
116
|
end
|
113
|
-
logger.
|
117
|
+
logger.error { err.backtrace.join("\n") }
|
114
118
|
end
|
115
119
|
|
116
120
|
def logger
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Tumugi
|
2
|
+
module Mixin
|
3
|
+
module HumanReadable
|
4
|
+
def human_readable_time(seconds)
|
5
|
+
[[60, :s], [60, :m], [10000, :h]].map{|count, name|
|
6
|
+
if seconds > 0
|
7
|
+
seconds, n = seconds.divmod(count)
|
8
|
+
"#{sprintf('%02d', n)}"
|
9
|
+
else
|
10
|
+
'00'
|
11
|
+
end
|
12
|
+
}.compact.reverse.join(':')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -20,15 +20,11 @@ module Tumugi
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def auto_bind?
|
23
|
-
|
24
|
-
false
|
25
|
-
else
|
26
|
-
@opts[:auto_bind]
|
27
|
-
end
|
23
|
+
option_as_bool(:auto_bind)
|
28
24
|
end
|
29
25
|
|
30
26
|
def required?
|
31
|
-
|
27
|
+
option_as_bool(:required)
|
32
28
|
end
|
33
29
|
|
34
30
|
def type
|
@@ -43,6 +39,10 @@ module Tumugi
|
|
43
39
|
self.class.new(@name, @opts.merge(required: false, default: value))
|
44
40
|
end
|
45
41
|
|
42
|
+
def secret?
|
43
|
+
option_as_bool(:secret)
|
44
|
+
end
|
45
|
+
|
46
46
|
private
|
47
47
|
|
48
48
|
def search_from_workflow_parameters
|
@@ -51,13 +51,15 @@ module Tumugi
|
|
51
51
|
value ? Converter.convert(type, value) : nil
|
52
52
|
end
|
53
53
|
|
54
|
-
private
|
55
|
-
|
56
54
|
def validate
|
57
55
|
if required? && !default_value.nil?
|
58
56
|
raise Tumugi::ParameterError.new("When you set required: true, you cannot set default value")
|
59
57
|
end
|
60
58
|
end
|
59
|
+
|
60
|
+
def option_as_bool(key)
|
61
|
+
@opts[key].nil? ? false : @opts[key]
|
62
|
+
end
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
data/lib/tumugi/task.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
require 'tumugi/event'
|
1
2
|
require 'tumugi/logger/scoped_logger'
|
2
3
|
require 'tumugi/mixin/listable'
|
3
4
|
require 'tumugi/mixin/task_helper'
|
4
5
|
require 'tumugi/mixin/parameterizable'
|
6
|
+
require 'tumugi/mixin/human_readable'
|
5
7
|
|
6
8
|
module Tumugi
|
7
9
|
class Task
|
8
10
|
include Tumugi::Mixin::Parameterizable
|
9
11
|
include Tumugi::Mixin::Listable
|
10
12
|
include Tumugi::Mixin::TaskHelper
|
13
|
+
include Tumugi::Mixin::HumanReadable
|
11
14
|
|
12
|
-
attr_reader :visible_at, :tries, :max_retry, :retry_interval
|
15
|
+
attr_reader :visible_at, :tries, :max_retry, :retry_interval, :elapsed_time
|
13
16
|
|
14
17
|
AVAILABLE_STATES = [
|
15
18
|
:pending,
|
@@ -28,6 +31,8 @@ module Tumugi
|
|
28
31
|
@retry_interval = Tumugi.config.retry_interval
|
29
32
|
@state = :pending
|
30
33
|
@lock = Mutex.new
|
34
|
+
@_elapsed_times = []
|
35
|
+
@elapsed_time = '00:00:00'
|
31
36
|
end
|
32
37
|
|
33
38
|
def id
|
@@ -98,6 +103,27 @@ module Tumugi
|
|
98
103
|
ready? && visible?(now)
|
99
104
|
end
|
100
105
|
|
106
|
+
def ready?
|
107
|
+
list(_requires).all? { |t| t.instance.completed? }
|
108
|
+
end
|
109
|
+
|
110
|
+
def completed?
|
111
|
+
outputs = list(output)
|
112
|
+
if outputs.empty?
|
113
|
+
success?
|
114
|
+
else
|
115
|
+
outputs.all?(&:exist?)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def requires_failed?
|
120
|
+
list(_requires).any? { |t| t.instance.finished? && !t.instance.success? }
|
121
|
+
end
|
122
|
+
|
123
|
+
def runnable?(now)
|
124
|
+
ready? && visible?(now)
|
125
|
+
end
|
126
|
+
|
101
127
|
def success?
|
102
128
|
case state
|
103
129
|
when :completed, :skipped
|
@@ -107,15 +133,19 @@ module Tumugi
|
|
107
133
|
end
|
108
134
|
end
|
109
135
|
|
110
|
-
def
|
136
|
+
def failure?
|
111
137
|
case state
|
112
|
-
when :
|
138
|
+
when :failed, :requires_failed
|
113
139
|
true
|
114
140
|
else
|
115
141
|
false
|
116
142
|
end
|
117
143
|
end
|
118
144
|
|
145
|
+
def finished?
|
146
|
+
success? or failure?
|
147
|
+
end
|
148
|
+
|
119
149
|
def timeout
|
120
150
|
nil # meaning use default timeout
|
121
151
|
end
|
@@ -132,6 +162,9 @@ module Tumugi
|
|
132
162
|
|
133
163
|
def trigger!(event)
|
134
164
|
@lock.synchronize do
|
165
|
+
now = Time.now
|
166
|
+
@_elapsed_times[tries] ||= { start: now }
|
167
|
+
|
135
168
|
s = case event
|
136
169
|
when :skip
|
137
170
|
:skipped
|
@@ -153,10 +186,20 @@ module Tumugi
|
|
153
186
|
raise Tumugi::TumugiError.new("Invalid state: #{s}")
|
154
187
|
end
|
155
188
|
|
189
|
+
@_elapsed_times[tries][:end] = now
|
190
|
+
@elapsed_time = human_readable_time((@_elapsed_times[tries][:end] - @_elapsed_times[tries][:start]).to_i)
|
156
191
|
@state = s
|
157
192
|
end
|
158
193
|
end
|
159
194
|
|
195
|
+
# Event callbacks
|
196
|
+
Event.all.each do |event|
|
197
|
+
class_eval <<-EOS
|
198
|
+
def on_#{event}
|
199
|
+
end
|
200
|
+
EOS
|
201
|
+
end
|
202
|
+
|
160
203
|
# Following methods are internal use only
|
161
204
|
|
162
205
|
def _requires
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'tumugi/event'
|
1
2
|
require 'tumugi/plugin'
|
2
3
|
require 'tumugi/task'
|
3
4
|
require 'tumugi/logger/logger'
|
@@ -64,6 +65,14 @@ module Tumugi
|
|
64
65
|
@run = block
|
65
66
|
end
|
66
67
|
|
68
|
+
Event.all.each do |event|
|
69
|
+
class_eval <<-EOS
|
70
|
+
def on_#{event}(&block)
|
71
|
+
@on_#{event} ||= block
|
72
|
+
end
|
73
|
+
EOS
|
74
|
+
end
|
75
|
+
|
67
76
|
def output_eval(task)
|
68
77
|
@out ||= @outputs.is_a?(Proc) ? task.instance_eval(&@outputs) : @outputs
|
69
78
|
end
|
@@ -72,10 +81,6 @@ module Tumugi
|
|
72
81
|
@required_tasks
|
73
82
|
end
|
74
83
|
|
75
|
-
def run_block(task)
|
76
|
-
task.instance_eval(&@run)
|
77
|
-
end
|
78
|
-
|
79
84
|
def parent_task_class
|
80
85
|
if @opts[:type].is_a?(Class)
|
81
86
|
@opts[:type]
|
@@ -84,6 +89,15 @@ module Tumugi
|
|
84
89
|
end
|
85
90
|
end
|
86
91
|
|
92
|
+
def run_block(task)
|
93
|
+
task.instance_eval(&@run)
|
94
|
+
end
|
95
|
+
|
96
|
+
def event_block(task, event)
|
97
|
+
callback = instance_variable_get("@on_#{event}")
|
98
|
+
task.instance_eval(&callback)
|
99
|
+
end
|
100
|
+
|
87
101
|
private
|
88
102
|
|
89
103
|
def create_task
|
@@ -98,6 +112,7 @@ module Tumugi
|
|
98
112
|
define_requires_method(task_class)
|
99
113
|
define_output_method(task_class)
|
100
114
|
define_run_method(task_class)
|
115
|
+
define_event_callback_methods(task_class)
|
101
116
|
setup_params(task_class)
|
102
117
|
task_class
|
103
118
|
end
|
@@ -138,6 +153,19 @@ module Tumugi
|
|
138
153
|
end unless @run.nil?
|
139
154
|
end
|
140
155
|
|
156
|
+
def define_event_callback_methods(task_class)
|
157
|
+
td = self
|
158
|
+
Event.all.each do |event|
|
159
|
+
if instance_variable_get("@on_#{event}")
|
160
|
+
task_class.class_eval do
|
161
|
+
define_method(:"on_#{event}") do
|
162
|
+
td.event_block(self, event)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
141
169
|
def setup_params(task_class)
|
142
170
|
@params.each do |name, opts|
|
143
171
|
task_class.param(name, opts)
|
data/lib/tumugi/version.rb
CHANGED
data/lib/tumugi/workflow.rb
CHANGED
@@ -5,11 +5,14 @@ require 'tumugi/plugin'
|
|
5
5
|
require 'tumugi/target'
|
6
6
|
require 'tumugi/command/run'
|
7
7
|
require 'tumugi/command/show'
|
8
|
+
require 'tumugi/mixin/human_readable'
|
8
9
|
|
9
10
|
require 'securerandom'
|
10
11
|
|
11
12
|
module Tumugi
|
12
13
|
class Workflow
|
14
|
+
include Tumugi::Mixin::HumanReadable
|
15
|
+
|
13
16
|
attr_reader :id
|
14
17
|
attr_accessor :params
|
15
18
|
|
@@ -22,12 +25,14 @@ module Tumugi
|
|
22
25
|
end
|
23
26
|
|
24
27
|
def execute(command, root_task_id, options)
|
28
|
+
@start_time = Time.now
|
29
|
+
logger.info "start id: #{id}"
|
25
30
|
process_common_options(command, options)
|
26
31
|
load_workflow_file(options[:file])
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
result = execute_command(command, root_task_id, options)
|
33
|
+
@end_time = Time.now
|
34
|
+
logger.info "end id: #{id}, elapsed_time: #{elapsed_time}"
|
35
|
+
result
|
31
36
|
end
|
32
37
|
|
33
38
|
def add_task(id, task)
|
@@ -55,13 +60,6 @@ module Tumugi
|
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
|
-
def create_dag(id)
|
59
|
-
dag = Tumugi::DAG.new
|
60
|
-
task = find_task(id)
|
61
|
-
dag.add_task(task)
|
62
|
-
dag
|
63
|
-
end
|
64
|
-
|
65
63
|
def process_common_options(command, options)
|
66
64
|
setup_logger(command, options)
|
67
65
|
load_config(options)
|
@@ -111,5 +109,23 @@ module Tumugi
|
|
111
109
|
logger.info "Parameters: #{@params}"
|
112
110
|
end
|
113
111
|
end
|
112
|
+
|
113
|
+
def elapsed_time
|
114
|
+
human_readable_time((@end_time - @start_time).to_i)
|
115
|
+
end
|
116
|
+
|
117
|
+
def execute_command(command, root_task_id, options)
|
118
|
+
dag = create_dag(root_task_id)
|
119
|
+
command_module = Kernel.const_get("Tumugi").const_get("Command")
|
120
|
+
cmd = command_module.const_get("#{command.to_s.capitalize}").new
|
121
|
+
cmd.execute(dag, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_dag(id)
|
125
|
+
dag = Tumugi::DAG.new
|
126
|
+
task = find_task(id)
|
127
|
+
dag.add_task(task)
|
128
|
+
dag
|
129
|
+
end
|
114
130
|
end
|
115
131
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tumugi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kazuyuki Honda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- examples/concurrent_task_run.rb
|
185
185
|
- examples/config_section.rb
|
186
186
|
- examples/data_pipeline.rb
|
187
|
+
- examples/event_callbacks.rb
|
187
188
|
- examples/fail_first_task.rb
|
188
189
|
- examples/fail_intermediate_task.rb
|
189
190
|
- examples/fail_last_task.rb
|
@@ -198,29 +199,37 @@ files:
|
|
198
199
|
- lib/tumugi/atomic_file.rb
|
199
200
|
- lib/tumugi/cli.rb
|
200
201
|
- lib/tumugi/command/new.rb
|
202
|
+
- lib/tumugi/command/new/generator.rb
|
203
|
+
- lib/tumugi/command/new/plugin_generator.rb
|
204
|
+
- lib/tumugi/command/new/project_generator.rb
|
201
205
|
- lib/tumugi/command/run.rb
|
202
206
|
- lib/tumugi/command/show.rb
|
203
207
|
- lib/tumugi/config.rb
|
204
208
|
- lib/tumugi/dag.rb
|
205
209
|
- lib/tumugi/dag_result_reporter.rb
|
206
|
-
- lib/tumugi/data/new/Gemfile.erb
|
207
|
-
- lib/tumugi/data/new/README.md.erb
|
208
|
-
- lib/tumugi/data/new/Rakefile.erb
|
209
|
-
- lib/tumugi/data/new/examples/example.rb.erb
|
210
|
-
- lib/tumugi/data/new/gemspec.erb
|
211
|
-
- lib/tumugi/data/new/gitignore.erb
|
212
|
-
- lib/tumugi/data/new/lib/tumugi/plugin/target/target.rb.erb
|
213
|
-
- lib/tumugi/data/new/lib/tumugi/plugin/task/task.rb.erb
|
214
|
-
- lib/tumugi/data/new/test/plugin/target/target_test.rb.erb
|
215
|
-
- lib/tumugi/data/new/test/plugin/task/task_test.rb.erb
|
216
|
-
- lib/tumugi/data/new/test/test.rb.erb
|
217
|
-
- lib/tumugi/data/new/test/test_helper.rb.erb
|
210
|
+
- lib/tumugi/data/new/plugin/Gemfile.erb
|
211
|
+
- lib/tumugi/data/new/plugin/README.md.erb
|
212
|
+
- lib/tumugi/data/new/plugin/Rakefile.erb
|
213
|
+
- lib/tumugi/data/new/plugin/examples/example.rb.erb
|
214
|
+
- lib/tumugi/data/new/plugin/gemspec.erb
|
215
|
+
- lib/tumugi/data/new/plugin/gitignore.erb
|
216
|
+
- lib/tumugi/data/new/plugin/lib/tumugi/plugin/target/target.rb.erb
|
217
|
+
- lib/tumugi/data/new/plugin/lib/tumugi/plugin/task/task.rb.erb
|
218
|
+
- lib/tumugi/data/new/plugin/test/plugin/target/target_test.rb.erb
|
219
|
+
- lib/tumugi/data/new/plugin/test/plugin/task/task_test.rb.erb
|
220
|
+
- lib/tumugi/data/new/plugin/test/test.rb.erb
|
221
|
+
- lib/tumugi/data/new/plugin/test/test_helper.rb.erb
|
222
|
+
- lib/tumugi/data/new/project/Gemfile.erb
|
223
|
+
- lib/tumugi/data/new/project/tumugi_config.rb.erb
|
224
|
+
- lib/tumugi/data/new/project/workflow.rb.erb
|
218
225
|
- lib/tumugi/dsl.rb
|
219
226
|
- lib/tumugi/error.rb
|
227
|
+
- lib/tumugi/event.rb
|
220
228
|
- lib/tumugi/executor/local_executor.rb
|
221
229
|
- lib/tumugi/file_system.rb
|
222
230
|
- lib/tumugi/logger/logger.rb
|
223
231
|
- lib/tumugi/logger/scoped_logger.rb
|
232
|
+
- lib/tumugi/mixin/human_readable.rb
|
224
233
|
- lib/tumugi/mixin/listable.rb
|
225
234
|
- lib/tumugi/mixin/parameterizable.rb
|
226
235
|
- lib/tumugi/mixin/task_helper.rb
|