82 lines
2.7 KiB
Python
82 lines
2.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from taskflow.engines.action_engine import base_action as base
|
|
|
|
|
|
class GraphAction(base.Action):
|
|
|
|
def __init__(self, graph):
|
|
self._graph = graph
|
|
self._action_mapping = {}
|
|
|
|
def add(self, node, action):
|
|
self._action_mapping[node] = action
|
|
|
|
def _succ(self, node):
|
|
return self._graph.successors(node)
|
|
|
|
def _pred(self, node):
|
|
return self._graph.predecessors(node)
|
|
|
|
def _resolve_dependencies(self, node, deps_counter, revert=False):
|
|
to_execute = []
|
|
nodes = self._pred(node) if revert else self._succ(node)
|
|
for next_node in nodes:
|
|
deps_counter[next_node] -= 1
|
|
if not deps_counter[next_node]:
|
|
to_execute.append(next_node)
|
|
return to_execute
|
|
|
|
def _browse_nodes_to_execute(self, deps_counter):
|
|
to_execute = []
|
|
for node, deps in deps_counter.items():
|
|
if not deps:
|
|
to_execute.append(node)
|
|
return to_execute
|
|
|
|
def _get_nodes_dependencies_count(self, revert=False):
|
|
deps_counter = {}
|
|
for node in self._graph.nodes_iter():
|
|
nodes = self._succ(node) if revert else self._pred(node)
|
|
deps_counter[node] = len(nodes)
|
|
return deps_counter
|
|
|
|
|
|
class SequentialGraphAction(GraphAction):
|
|
|
|
def execute(self, engine):
|
|
deps_counter = self._get_nodes_dependencies_count()
|
|
to_execute = self._browse_nodes_to_execute(deps_counter)
|
|
|
|
while to_execute:
|
|
node = to_execute.pop()
|
|
action = self._action_mapping[node]
|
|
action.execute(engine) # raises on failure
|
|
to_execute += self._resolve_dependencies(node, deps_counter)
|
|
|
|
def revert(self, engine):
|
|
deps_counter = self._get_nodes_dependencies_count(True)
|
|
to_revert = self._browse_nodes_to_execute(deps_counter)
|
|
|
|
while to_revert:
|
|
node = to_revert.pop()
|
|
action = self._action_mapping[node]
|
|
action.revert(engine) # raises on failure
|
|
to_revert += self._resolve_dependencies(node, deps_counter, True)
|