tengine_job 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile.lock +78 -48
- data/bin/tengine_job +71 -0
- data/examples/0004_retry_one_layer.rb +10 -7
- data/examples/0027_parallel_ssh_job +9 -0
- data/examples/0027_parallel_ssh_jobs.rb +14 -0
- data/lib/tengine/job.rb +19 -49
- data/lib/tengine/job/dsl.rb +13 -0
- data/lib/tengine/job/{dsl_binder.rb → dsl/binder.rb} +4 -4
- data/lib/tengine/job/{dsl_evaluator.rb → dsl/evaluator.rb} +2 -2
- data/lib/tengine/job/{dsl_loader.rb → dsl/loader.rb} +20 -22
- data/lib/tengine/job/runtime.rb +32 -0
- data/lib/tengine/job/{drivers → runtime/drivers}/job_control_driver.rb +46 -92
- data/lib/tengine/job/{drivers → runtime/drivers}/job_execution_driver.rb +14 -10
- data/lib/tengine/job/runtime/drivers/jobnet_control_driver.rb +240 -0
- data/lib/tengine/job/{drivers → runtime/drivers}/schedule_driver.rb +4 -4
- data/lib/tengine/job/{edge.rb → runtime/edge.rb} +79 -25
- data/lib/tengine/job/{executable.rb → runtime/executable.rb} +35 -15
- data/lib/tengine/job/{execution.rb → runtime/execution.rb} +19 -11
- data/lib/tengine/job/runtime/job_base.rb +5 -0
- data/lib/tengine/job/runtime/jobnet.rb +283 -0
- data/lib/tengine/job/runtime/junction.rb +44 -0
- data/lib/tengine/job/runtime/named_vertex.rb +95 -0
- data/lib/tengine/job/runtime/root_jobnet.rb +81 -0
- data/lib/tengine/job/{signal.rb → runtime/signal.rb} +99 -13
- data/lib/tengine/job/runtime/ssh_job.rb +486 -0
- data/lib/tengine/job/{jobnet → runtime}/state_transition.rb +6 -4
- data/lib/tengine/job/runtime/stoppable.rb +64 -0
- data/lib/tengine/job/runtime/vertex.rb +50 -0
- data/lib/tengine/job/structure.rb +20 -0
- data/lib/tengine/job/{category.rb → structure/category.rb} +9 -5
- data/lib/tengine/job/{jobnet/builder.rb → structure/edge_builder.rb} +11 -7
- data/lib/tengine/job/{element_selector_notation.rb → structure/element_selector_notation.rb} +15 -11
- data/lib/tengine/job/structure/jobnet_builder.rb +83 -0
- data/lib/tengine/job/structure/jobnet_finder.rb +60 -0
- data/lib/tengine/job/{name_path.rb → structure/name_path.rb} +2 -2
- data/lib/tengine/job/structure/tree.rb +20 -0
- data/lib/tengine/job/structure/visitor.rb +67 -0
- data/lib/tengine/job/template.rb +24 -0
- data/lib/tengine/job/template/edge.rb +37 -0
- data/lib/tengine/job/template/expansion.rb +24 -0
- data/lib/tengine/job/template/generator.rb +111 -0
- data/lib/tengine/job/template/jobnet.rb +83 -0
- data/lib/tengine/job/template/junction.rb +14 -0
- data/lib/tengine/job/{job.rb → template/named_vertex.rb} +3 -5
- data/lib/tengine/job/{root_jobnet_template.rb → template/root_jobnet.rb} +12 -26
- data/lib/tengine/job/template/ssh_job.rb +80 -0
- data/lib/tengine/job/template/vertex.rb +97 -0
- metadata +127 -93
- data/lib/tengine/job/connectable.rb +0 -43
- data/lib/tengine/job/drivers/jobnet_control_driver.rb +0 -249
- data/lib/tengine/job/end.rb +0 -32
- data/lib/tengine/job/expansion.rb +0 -37
- data/lib/tengine/job/fork.rb +0 -6
- data/lib/tengine/job/jobnet.rb +0 -184
- data/lib/tengine/job/jobnet/job_state_transition.rb +0 -167
- data/lib/tengine/job/jobnet/jobnet_state_transition.rb +0 -110
- data/lib/tengine/job/jobnet_actual.rb +0 -84
- data/lib/tengine/job/jobnet_template.rb +0 -10
- data/lib/tengine/job/join.rb +0 -6
- data/lib/tengine/job/junction.rb +0 -29
- data/lib/tengine/job/killing.rb +0 -30
- data/lib/tengine/job/mm_compatibility.rb +0 -6
- data/lib/tengine/job/mm_compatibility/connectable.rb +0 -13
- data/lib/tengine/job/root.rb +0 -16
- data/lib/tengine/job/root_jobnet_actual.rb +0 -58
- data/lib/tengine/job/script_executable.rb +0 -235
- data/lib/tengine/job/start.rb +0 -20
- data/lib/tengine/job/stoppable.rb +0 -15
- data/lib/tengine/job/vertex.rb +0 -181
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
require 'tengine/job/
|
2
|
+
require 'tengine/job/runtime'
|
3
3
|
|
4
|
-
module Tengine::Job::
|
4
|
+
module Tengine::Job::Runtime::StateTransition
|
5
5
|
|
6
6
|
def self.included(mod)
|
7
7
|
mod.extend(ClassMethods)
|
@@ -23,10 +23,12 @@ module Tengine::Job::Jobnet::StateTransition
|
|
23
23
|
def #{method_name}(*args, &block)
|
24
24
|
case self.phase_key
|
25
25
|
when #{available_phase_keys.map(&:inspect).join(', ')} then
|
26
|
-
|
26
|
+
update_with_lock do
|
27
|
+
#{original_method}(*args, &block)
|
28
|
+
end
|
27
29
|
#{ignore_case}
|
28
30
|
else
|
29
|
-
raise Tengine::Job::Executable::PhaseError, "\#{name_path} \#{self.class.name}##{method_name} not available when the phase_key of \#{self.name_path.inspect} is \#{self.phase_key.inspect}"
|
31
|
+
raise Tengine::Job::Runtime::Executable::PhaseError, "\#{name_path} \#{self.class.name}##{method_name} not available when the phase_key of \#{self.name_path.inspect} is \#{self.phase_key.inspect}"
|
30
32
|
end
|
31
33
|
end
|
32
34
|
EOS
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job/runtime'
|
3
|
+
require 'selectable_attr'
|
4
|
+
|
5
|
+
# ジョブ/ジョブネットを実行する際の情報に関するモジュール
|
6
|
+
# Tengine::Job::Runtime::Jobnet, Tengine::Job::Template::Jobnetがこのモジュールをincludeします
|
7
|
+
module Tengine::Job::Runtime::Stoppable
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
field :stopped_at , :type => DateTime # 停止時刻。停止を開始した時刻です。
|
12
|
+
field :stop_reason, :type => String # 停止理由。手動以外での停止ならば停止した理由が設定されます。
|
13
|
+
end
|
14
|
+
|
15
|
+
# https://www.pivotaltracker.com/story/show/23329935
|
16
|
+
|
17
|
+
def stop_reason= r
|
18
|
+
super
|
19
|
+
children.each do |i|
|
20
|
+
if i.respond_to?(:chained_box?) && i.chained_box?
|
21
|
+
i.stop_reason = r
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def stopped_at= t
|
27
|
+
super
|
28
|
+
children.each do |i|
|
29
|
+
if i.respond_to?(:chained_box?) && i.chained_box?
|
30
|
+
i.stopped_at = t
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def fire_stop_event(root_jobnet, options = Hash.new)
|
36
|
+
root_jobnet_id = root_jobnet.id.to_s
|
37
|
+
result = Tengine::Job::Runtime::Execution.create!(
|
38
|
+
options.merge(:root_jobnet_id => root_jobnet_id))
|
39
|
+
properties = {
|
40
|
+
:execution_id => result.id.to_s,
|
41
|
+
:root_jobnet_id => root_jobnet_id,
|
42
|
+
:stop_reason => "user_stop"
|
43
|
+
}
|
44
|
+
|
45
|
+
target_id = self.id.to_s
|
46
|
+
# if target.children.blank?
|
47
|
+
if script_executable?
|
48
|
+
event = :"stop.job.job.tengine"
|
49
|
+
properties[:target_job_id] = target_id
|
50
|
+
properties[:target_jobnet_id] = parent.id.to_s
|
51
|
+
else
|
52
|
+
event = :"stop.jobnet.job.tengine"
|
53
|
+
properties[:target_jobnet_id] = target_id
|
54
|
+
end
|
55
|
+
|
56
|
+
EM.run do
|
57
|
+
Tengine::Event.fire(event,
|
58
|
+
:source_name => name_as_resource,
|
59
|
+
:properties => properties)
|
60
|
+
end
|
61
|
+
|
62
|
+
return result
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job/runtime'
|
3
|
+
|
4
|
+
# Edgeとともにジョブネットを構成するグラフの「頂点」を表すモデルです。
|
5
|
+
# このクラスだけでツリー構造を作ることができますが、ほぼ抽象クラスであり実際には
|
6
|
+
# 派生クラスのオブジェクトによってツリー構造が作られます。
|
7
|
+
class Tengine::Job::Runtime::Vertex
|
8
|
+
include Mongoid::Document
|
9
|
+
include Mongoid::Timestamps
|
10
|
+
include Tengine::Job::Structure::NamePath
|
11
|
+
include Tengine::Job::Structure::Tree
|
12
|
+
include Tengine::Job::Structure::Visitor::Accepter
|
13
|
+
include Tengine::Job::Runtime::Signal::Transmittable
|
14
|
+
|
15
|
+
field :child_index, type: Integer
|
16
|
+
|
17
|
+
# self.cyclic = true
|
18
|
+
with_options(class_name: self.name, foreign_key: "parent_id") do |c|
|
19
|
+
c.belongs_to :parent , inverse_of: :children
|
20
|
+
c.has_many :children, inverse_of: :parent , validate: false, order: {child_index: 1}
|
21
|
+
end
|
22
|
+
|
23
|
+
def template?; false; end
|
24
|
+
def runtime?; !template?; end
|
25
|
+
|
26
|
+
def previous_edges
|
27
|
+
return nil unless parent
|
28
|
+
parent.edges.select{|edge| edge.destination_id == self.id}
|
29
|
+
end
|
30
|
+
alias_method :prev_edges, :previous_edges
|
31
|
+
|
32
|
+
def next_edges
|
33
|
+
return nil unless parent
|
34
|
+
parent.edges.select{|edge| edge.origin_id == self.id}
|
35
|
+
end
|
36
|
+
|
37
|
+
def ancestors_until_expansion
|
38
|
+
if parent = self.parent
|
39
|
+
parent.ancestors_until_expansion + [parent]
|
40
|
+
else
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Tengine::Job::Runtime::Vertexは構成されるツリーのルートを保存しても、embedでないので
|
46
|
+
# 各vertexをsaveしないと保存されないため、明示的に保存しています。
|
47
|
+
def save_descendants!
|
48
|
+
accept_visitor(Tengine::Job::Structure::Visitor::All.new{|v| v.save! })
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'tengine/job'
|
2
|
+
|
3
|
+
module Tengine::Job::Structure
|
4
|
+
autoload :Category , "tengine/job/structure/category"
|
5
|
+
autoload :NamePath , "tengine/job/structure/name_path"
|
6
|
+
autoload :Tree , "tengine/job/structure/tree"
|
7
|
+
|
8
|
+
autoload :Visitor , "tengine/job/structure/visitor"
|
9
|
+
|
10
|
+
autoload :EdgeBuilder , "tengine/job/structure/edge_builder"
|
11
|
+
|
12
|
+
autoload :JobnetBuilder , "tengine/job/structure/jobnet_builder"
|
13
|
+
autoload :JobnetFinder , "tengine/job/structure/jobnet_finder"
|
14
|
+
|
15
|
+
autoload :ElementSelectorNotation, "tengine/job/structure/element_selector_notation"
|
16
|
+
|
17
|
+
class Error < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
require 'tengine/job'
|
2
|
+
require 'tengine/job/template'
|
3
3
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'tengine/support/yaml_with_erb'
|
6
6
|
|
7
|
-
class Tengine::Job::Category
|
7
|
+
class Tengine::Job::Structure::Category
|
8
8
|
include Mongoid::Document
|
9
9
|
include Mongoid::Timestamps
|
10
10
|
include Tengine::Core::FindByName
|
@@ -12,16 +12,20 @@ class Tengine::Job::Category
|
|
12
12
|
field :name , :type => String # カテゴリ名。ディレクトリ名を元に設定されるので、"/"などは使用不可。
|
13
13
|
field :caption , :type => String # カテゴリの表示名。各ディレクトリ名に対応する表示名。通常dictionary.ymlに定義する。
|
14
14
|
|
15
|
-
with_options(:class_name =>
|
15
|
+
with_options(:class_name => self.name) do |c|
|
16
16
|
c.belongs_to :parent, :inverse_of => :children, :index => true
|
17
17
|
c.has_many :children, :inverse_of => :parent, :order => [:name, :asc]
|
18
18
|
end
|
19
19
|
|
20
|
+
# embeddedなDocumentをその外部のドキュメントから参照することはできないので、これはNG
|
21
|
+
# has_many :template_root_jobnets, class_name: "Tengine::Job::Template::RootJobnet", inverse_of: :category
|
22
|
+
has_many :runtime_root_jobnets , class_name: "Tengine::Job::Runtime::RootJobnet" , inverse_of: :category
|
23
|
+
|
20
24
|
class << self
|
21
25
|
def update_for(base_dir)
|
22
26
|
root_dir = File.basename(base_dir)
|
23
27
|
dic_dir_base = File.dirname(base_dir)
|
24
|
-
root_jobnets = Tengine::Job::
|
28
|
+
root_jobnets = Tengine::Job::Template::RootJobnet.all
|
25
29
|
root_jobnets.each do |root_jobnet|
|
26
30
|
dirs = File.dirname(root_jobnet.dsl_filepath || "").split('/') - ['.', '..']
|
27
31
|
dirs.unshift(root_dir)
|
@@ -35,7 +39,7 @@ class Tengine::Job::Category
|
|
35
39
|
hash = YAML.load_file(dic_path)
|
36
40
|
caption = hash[dir]
|
37
41
|
end
|
38
|
-
category =
|
42
|
+
category = self.find_or_create_by(
|
39
43
|
:name => dir,
|
40
44
|
:caption => caption || dir,
|
41
45
|
:parent_id => last_category ? last_category.id : nil)
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job/structure'
|
3
|
+
|
2
4
|
require 'tsort'
|
3
5
|
|
4
|
-
class Tengine::Job::
|
6
|
+
class Tengine::Job::Structure::EdgeBuilder
|
5
7
|
include TSort
|
6
8
|
|
7
|
-
def initialize(client, boot_job_names, redirections)
|
9
|
+
def initialize(client, boot_job_names, redirections, options = {})
|
8
10
|
@client, @boot_job_names, @redirections = client, boot_job_names, redirections.dup
|
9
11
|
@graph = Hash.new do |h, k| h[k] = Array.new end
|
10
12
|
@redirections.each do |(x, y)|
|
11
13
|
@graph[x] << y
|
12
14
|
end
|
15
|
+
@fork_class = options[:fork_class]
|
16
|
+
@join_class = options[:join_class]
|
13
17
|
end
|
14
18
|
|
15
19
|
def children; @client.children; end
|
@@ -20,7 +24,7 @@ class Tengine::Job::Jobnet::Builder
|
|
20
24
|
def process
|
21
25
|
tsort
|
22
26
|
rescue TSort::Cyclic
|
23
|
-
raise Tengine::Job::
|
27
|
+
raise Tengine::Job::Structure::Error, "circular dependency found in jobnet ``#{@client.name}''"
|
24
28
|
else
|
25
29
|
build_start_edges
|
26
30
|
build_edge_by_redirections
|
@@ -46,7 +50,7 @@ class Tengine::Job::Jobnet::Builder
|
|
46
50
|
when 1 then
|
47
51
|
new_edge(start, child_by_name(@boot_job_names.first))
|
48
52
|
else
|
49
|
-
fork =
|
53
|
+
fork = @fork_class.new
|
50
54
|
children << fork
|
51
55
|
new_edge(start, fork)
|
52
56
|
@boot_job_names.each do |boot_job_name|
|
@@ -87,7 +91,7 @@ class Tengine::Job::Jobnet::Builder
|
|
87
91
|
def build_forks_and_edges
|
88
92
|
@fork_origin_to_fork = {}
|
89
93
|
@fork_origins.each do |fork_origin|
|
90
|
-
children << fork =
|
94
|
+
children << fork = @fork_class.new
|
91
95
|
@fork_origin_to_fork[fork_origin] = fork
|
92
96
|
new_edge(child_by_name(fork_origin), fork)
|
93
97
|
@redirections.dup.
|
@@ -101,7 +105,7 @@ class Tengine::Job::Jobnet::Builder
|
|
101
105
|
def build_joins_and_edges
|
102
106
|
@join_destination_to_join = {}
|
103
107
|
@join_destinations.each do |join_destination|
|
104
|
-
children << join =
|
108
|
+
children << join = @join_class.new
|
105
109
|
@join_destination_to_join[join_destination] = join
|
106
110
|
@redirections.dup.
|
107
111
|
delete_if{|r| @fork_to_join.include?(r)}.
|
@@ -132,7 +136,7 @@ class Tengine::Job::Jobnet::Builder
|
|
132
136
|
when 0 then raise "Must be a bug!!!"
|
133
137
|
when 1 then new_edge(child_by_name(end_points.first), _end)
|
134
138
|
else
|
135
|
-
join =
|
139
|
+
join = @join_class.new
|
136
140
|
children << join
|
137
141
|
end_points.each{|point| new_edge(child_by_name(point), join)}
|
138
142
|
new_edge(join, _end)
|
data/lib/tengine/job/{element_selector_notation.rb → structure/element_selector_notation.rb}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
require 'tengine/job'
|
2
|
+
require 'tengine/job/structure'
|
3
3
|
|
4
4
|
# # Tengine Jobnet Element Selector Notation
|
5
5
|
# Tengineジョブネット要素セレクタ記法
|
@@ -60,7 +60,7 @@ require 'tengine/job'
|
|
60
60
|
#
|
61
61
|
#
|
62
62
|
|
63
|
-
module Tengine::Job::ElementSelectorNotation
|
63
|
+
module Tengine::Job::Structure::ElementSelectorNotation
|
64
64
|
|
65
65
|
class NotFound < Tengine::Errors::NotFound
|
66
66
|
attr_reader :jobnet, :notation
|
@@ -73,6 +73,9 @@ module Tengine::Job::ElementSelectorNotation
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
def base_module
|
77
|
+
self.template? ? Tengine::Job::Template : Tengine::Job::Runtime
|
78
|
+
end
|
76
79
|
|
77
80
|
NAME_PART = /[A-Za-z_][\w\-]*/.freeze
|
78
81
|
NAME_PATH_PART = /[A-Za-z_\/][\w\-\/]*/.freeze
|
@@ -81,7 +84,7 @@ module Tengine::Job::ElementSelectorNotation
|
|
81
84
|
# 例外をraiseさせたい場合は element!メソッドを使ってください。
|
82
85
|
def element(notation)
|
83
86
|
direction, current_path = *notation.split(/@/, 2)
|
84
|
-
return vertex_by_name_path(direction) if current_path.nil? && Tengine::Job::NamePath.absolute?(direction)
|
87
|
+
return vertex_by_name_path(direction) if current_path.nil? && Tengine::Job::Structure::NamePath.absolute?(direction)
|
85
88
|
current = current_path ? vertex_by_name_path(current_path) : self
|
86
89
|
raise "#{current_path.inspect} not found" unless current
|
87
90
|
case direction
|
@@ -99,10 +102,10 @@ module Tengine::Job::ElementSelectorNotation
|
|
99
102
|
job2 = current.child_by_name($2)
|
100
103
|
job1.next_edges.detect{|edge| edge.destination_id == job2.id}
|
101
104
|
when /^(fork|join)!(#{NAME_PART})~(#{NAME_PART})$/ then
|
102
|
-
klass =
|
105
|
+
klass = base_module.const_get($1.capitalize)
|
103
106
|
job1 = current.child_by_name($2)
|
104
107
|
job2 = current.child_by_name($3)
|
105
|
-
paths = PathFinder.new(job1, job2).process
|
108
|
+
paths = PathFinder.new(self, job1, job2).process
|
106
109
|
paths.each do |path|
|
107
110
|
path.each do |element|
|
108
111
|
return element if element.is_a?(klass)
|
@@ -111,12 +114,12 @@ module Tengine::Job::ElementSelectorNotation
|
|
111
114
|
when /^fork~join!(#{NAME_PART})~(#{NAME_PART})$/ then
|
112
115
|
job1 = current.child_by_name($1)
|
113
116
|
job2 = current.child_by_name($2)
|
114
|
-
paths = PathFinder.new(job1, job2).process
|
117
|
+
paths = PathFinder.new(self, job1, job2).process
|
115
118
|
paths.each do |path|
|
116
119
|
path.each do |element|
|
117
|
-
if element.is_a?(
|
118
|
-
if element.origin.is_a?(
|
119
|
-
element.destination.is_a?(
|
120
|
+
if element.is_a?(base_module.const_get(:Edge))
|
121
|
+
if element.origin.is_a?(base_module.const_get(:Fork)) &&
|
122
|
+
element.destination.is_a?(base_module.const_get(:Join))
|
120
123
|
return element
|
121
124
|
end
|
122
125
|
end
|
@@ -136,7 +139,8 @@ module Tengine::Job::ElementSelectorNotation
|
|
136
139
|
end
|
137
140
|
|
138
141
|
class PathFinder
|
139
|
-
def initialize(origin, dest)
|
142
|
+
def initialize(client, origin, dest)
|
143
|
+
@client = client
|
140
144
|
@origin, @dest = origin, dest
|
141
145
|
end
|
142
146
|
|
@@ -149,7 +153,7 @@ module Tengine::Job::ElementSelectorNotation
|
|
149
153
|
|
150
154
|
def visit(element)
|
151
155
|
@current_route << element
|
152
|
-
if element.is_a?(
|
156
|
+
if element.is_a?(@client.base_module.const_get(:Edge))
|
153
157
|
element.destination.accept_visitor(self)
|
154
158
|
else
|
155
159
|
@routes << @current_route.dup
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job/structure'
|
3
|
+
|
4
|
+
module Tengine::Job::Structure::JobnetBuilder
|
5
|
+
|
6
|
+
def start_vertex
|
7
|
+
self.children.detect{|child| child.is_a?(self.class.start_vertex_class)}
|
8
|
+
end
|
9
|
+
|
10
|
+
def end_vertex
|
11
|
+
self.children.detect{|child| child.is_a?(self.class.end_vertex_class)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def finally_vertex
|
15
|
+
self.children.detect{|child| child.is_a?(self.class.jobnet_class) && (child.jobnet_type_key == :finally)}
|
16
|
+
end
|
17
|
+
alias_method :finally_jobnet, :finally_vertex
|
18
|
+
|
19
|
+
def with_start
|
20
|
+
self.children << self.class.start_vertex_class.new
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def prepare_end
|
25
|
+
if self.children.last.is_a?(self.class.end_vertex_class)
|
26
|
+
_end = self.children.last
|
27
|
+
yield(_end) if block_given?
|
28
|
+
else
|
29
|
+
_end = self.class.end_vertex_class.new
|
30
|
+
yield(_end) if block_given?
|
31
|
+
self.children << _end
|
32
|
+
end
|
33
|
+
_end
|
34
|
+
end
|
35
|
+
|
36
|
+
def child_by_name(str)
|
37
|
+
case str
|
38
|
+
when '..' then parent
|
39
|
+
when '.' then self
|
40
|
+
when 'start' then start_vertex
|
41
|
+
when 'end' then end_vertex
|
42
|
+
when 'finally' then finally_vertex
|
43
|
+
else
|
44
|
+
self.children.detect{|c| c.respond_to?(:name) && (c.name == str)}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_edges(auto_sequence, boot_job_names, redirections)
|
49
|
+
if self.children.length == 1 # 最初に追加したStartだけなら。
|
50
|
+
self.children.delete_all
|
51
|
+
return
|
52
|
+
end
|
53
|
+
if auto_sequence || boot_job_names.empty?
|
54
|
+
prepare_end
|
55
|
+
build_sequencial_edges
|
56
|
+
else
|
57
|
+
edge_builder = Tengine::Job::Structure::EdgeBuilder.new(self, boot_job_names, redirections,
|
58
|
+
fork_class: self.class.fork_class,
|
59
|
+
join_class: self.class.join_class
|
60
|
+
)
|
61
|
+
edge_builder.process
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_sequencial_edges
|
66
|
+
self.edges.clear
|
67
|
+
current = nil
|
68
|
+
self.children.each do |child|
|
69
|
+
next if child.is_a?(self.class.jobnet_class) && !!child.jobnet_type_entry[:alternative]
|
70
|
+
if current
|
71
|
+
edge = self.new_edge(current, child)
|
72
|
+
yield(edge) if block_given?
|
73
|
+
end
|
74
|
+
current = child
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_edge(origin, destination)
|
79
|
+
origin_id = origin.is_a?(self.class.vertex_class) ? origin.id : origin
|
80
|
+
destination_id = destination.is_a?(self.class.vertex_class) ? destination.id : destination
|
81
|
+
edges.new(:origin_id => origin_id, :destination_id => destination_id)
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'tengine/job/structure'
|
2
|
+
|
3
|
+
module Tengine::Job::Structure::JobnetFinder
|
4
|
+
|
5
|
+
def find_descendant_edge(edge_id)
|
6
|
+
edge_id = String(edge_id)
|
7
|
+
visitor = Tengine::Job::Structure::Visitor::Any.new do |vertex|
|
8
|
+
if vertex.respond_to?(:edges)
|
9
|
+
vertex.edges.detect{|edge| edge.id.to_s == edge_id}
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
visitor.visit(self)
|
15
|
+
end
|
16
|
+
alias_method :edge, :find_descendant_edge
|
17
|
+
|
18
|
+
def find_descendant(vertex_id)
|
19
|
+
vertex_id = String(vertex_id)
|
20
|
+
return nil if vertex_id == self.id.to_s
|
21
|
+
vertex(vertex_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def vertex(vertex_id)
|
25
|
+
vertex_id = String(vertex_id)
|
26
|
+
return self if vertex_id == self.id.to_s
|
27
|
+
visitor = Tengine::Job::Structure::Visitor::Any.new{|v| vertex_id == v.id.to_s ? v : nil }
|
28
|
+
visitor.visit(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_descendant_by_name_path(name_path)
|
32
|
+
return nil if name_path == self.name_path
|
33
|
+
vertex_by_name_path(name_path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def vertex_by_name_path(name_path)
|
37
|
+
Tengine::Job::Structure::NamePath.absolute?(name_path) ?
|
38
|
+
root.vertex_by_absolute_name_path(name_path) :
|
39
|
+
vertex_by_relative_name_path(name_path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def vertex_by_absolute_name_path(name_path)
|
43
|
+
return self if name_path.to_s == self.name_path
|
44
|
+
visitor = Tengine::Job::Structure::Visitor::Any.new do |vertex|
|
45
|
+
if name_path == (vertex.respond_to?(:name_path) ? vertex.name_path : nil)
|
46
|
+
vertex
|
47
|
+
else
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
visitor.visit(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
def vertex_by_relative_name_path(name_path)
|
55
|
+
head, tail = *name_path.split(Tengine::Job::Structure::NamePath::SEPARATOR, 2)
|
56
|
+
child = child_by_name(head)
|
57
|
+
tail ? child.vertex_by_relative_name_path(tail) : child
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|