|
@@ -6,7 +6,7 @@
|
|
The bootsteps!
|
|
The bootsteps!
|
|
|
|
|
|
"""
|
|
"""
|
|
-from __future__ import absolute_import
|
|
+from __future__ import absolute_import, unicode_literals
|
|
|
|
|
|
from collections import deque
|
|
from collections import deque
|
|
from importlib import import_module
|
|
from importlib import import_module
|
|
@@ -15,7 +15,7 @@ from threading import Event
|
|
from kombu.common import ignore_errors
|
|
from kombu.common import ignore_errors
|
|
from kombu.utils import symbol_by_name
|
|
from kombu.utils import symbol_by_name
|
|
|
|
|
|
-from .datastructures import DependencyGraph
|
|
+from .datastructures import DependencyGraph, GraphFormatter
|
|
from .utils.imports import instantiate, qualname
|
|
from .utils.imports import instantiate, qualname
|
|
from .utils.log import get_logger
|
|
from .utils.log import get_logger
|
|
from .utils.threads import default_socket_timeout
|
|
from .utils.threads import default_socket_timeout
|
|
@@ -42,10 +42,40 @@ def _pre(ns, fmt):
|
|
return '| {0}: {1}'.format(ns.alias, fmt)
|
|
return '| {0}: {1}'.format(ns.alias, fmt)
|
|
|
|
|
|
|
|
|
|
-def _maybe_name(s):
|
|
+def _label(s):
|
|
- if not isinstance(s, basestring):
|
|
+ return s.name.rsplit('.', 1)[-1]
|
|
- return s.name
|
|
+
|
|
- return s
|
|
+
|
|
|
|
+class StepFormatter(GraphFormatter):
|
|
|
|
+
|
|
|
|
+ namespace_prefix = '⧉'
|
|
|
|
+ conditional_prefix = '∘'
|
|
|
|
+ namespace_scheme = {
|
|
|
|
+ 'shape': 'parallelogram',
|
|
|
|
+ 'color': 'slategray4',
|
|
|
|
+ 'fillcolor': 'slategray3',
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ def label(self, step):
|
|
|
|
+ return '{0}{1}'.format(self._get_prefix(step),
|
|
|
|
+ (step.label or _label(step)).encode('utf-8', 'ignore'),
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ def _get_prefix(self, step):
|
|
|
|
+ if step.last:
|
|
|
|
+ return self.namespace_prefix
|
|
|
|
+ if step.conditional:
|
|
|
|
+ return self.conditional_prefix
|
|
|
|
+ return ''
|
|
|
|
+
|
|
|
|
+ def node(self, obj, **attrs):
|
|
|
|
+ scheme = self.namespace_scheme if obj.last else self.node_scheme
|
|
|
|
+ return self.draw_node(obj, scheme, attrs)
|
|
|
|
+
|
|
|
|
+ def edge(self, a, b, **attrs):
|
|
|
|
+ if a.last:
|
|
|
|
+ attrs.update(arrowhead='none', color='darkseagreen3')
|
|
|
|
+ return self.draw_edge(a, b, self.edge_scheme, attrs)
|
|
|
|
|
|
|
|
|
|
class Namespace(object):
|
|
class Namespace(object):
|
|
@@ -59,6 +89,8 @@ class Namespace(object):
|
|
:keyword on_stopped: Optional callback applied after namespace stopped.
|
|
:keyword on_stopped: Optional callback applied after namespace stopped.
|
|
|
|
|
|
"""
|
|
"""
|
|
|
|
+ GraphFormatter = StepFormatter
|
|
|
|
+
|
|
name = None
|
|
name = None
|
|
state = None
|
|
state = None
|
|
started = 0
|
|
started = 0
|
|
@@ -145,8 +177,9 @@ class Namespace(object):
|
|
steps = self.steps = self.claim_steps()
|
|
steps = self.steps = self.claim_steps()
|
|
|
|
|
|
self._debug('Building graph...')
|
|
self._debug('Building graph...')
|
|
- for name in self._finalize_steps(steps):
|
|
+ for S in self._finalize_steps(steps):
|
|
- step = steps[name] = steps[name](parent, **kwargs)
|
|
+ step = S(parent, **kwargs)
|
|
|
|
+ steps[step.name] = step
|
|
order.append(step)
|
|
order.append(step)
|
|
self._debug('New boot order: {%s}',
|
|
self._debug('New boot order: {%s}',
|
|
', '.join(s.alias for s in self.order))
|
|
', '.join(s.alias for s in self.order))
|
|
@@ -173,20 +206,21 @@ class Namespace(object):
|
|
if node.name not in self.steps:
|
|
if node.name not in self.steps:
|
|
steps[node.name] = node
|
|
steps[node.name] = node
|
|
stream.append(node.requires)
|
|
stream.append(node.requires)
|
|
- for node in steps.itervalues():
|
|
+
|
|
- node.requires = [_maybe_name(n) for n in node.requires]
|
|
+ assert [steps[req.name] for step in steps.values()
|
|
- for step in steps.values():
|
|
+ for req in step.requires]
|
|
- [steps[n] for n in step.requires]
|
|
|
|
|
|
|
|
def _finalize_steps(self, steps):
|
|
def _finalize_steps(self, steps):
|
|
- self._firstpass(steps)
|
|
|
|
- G = self.graph = DependencyGraph((C.name, C.requires)
|
|
|
|
- for C in steps.itervalues())
|
|
|
|
last = self._find_last()
|
|
last = self._find_last()
|
|
|
|
+ self._firstpass(steps)
|
|
|
|
+ it = ((C, C.requires) for C in steps.itervalues())
|
|
|
|
+ G = self.graph = DependencyGraph(it,
|
|
|
|
+ formatter=self.GraphFormatter(root=last),
|
|
|
|
+ )
|
|
if last:
|
|
if last:
|
|
for obj in G:
|
|
for obj in G:
|
|
- if obj != last.name:
|
|
+ if obj != last:
|
|
- G.add_edge(last.name, obj)
|
|
+ G.add_edge(last, obj)
|
|
try:
|
|
try:
|
|
return G.topsort()
|
|
return G.topsort()
|
|
except KeyError as exc:
|
|
except KeyError as exc:
|
|
@@ -196,7 +230,6 @@ class Namespace(object):
|
|
return dict(self.load_step(step) for step in self._all_steps())
|
|
return dict(self.load_step(step) for step in self._all_steps())
|
|
|
|
|
|
def _all_steps(self):
|
|
def _all_steps(self):
|
|
- print('My NAME IS: %r' % (self.name, ))
|
|
|
|
return self.types | self.app.steps[self.name.lower()]
|
|
return self.types | self.app.steps[self.name.lower()]
|
|
|
|
|
|
def load_step(self, step):
|
|
def load_step(self, step):
|
|
@@ -208,7 +241,7 @@ class Namespace(object):
|
|
|
|
|
|
@property
|
|
@property
|
|
def alias(self):
|
|
def alias(self):
|
|
- return self.name.rsplit('.', 1)[-1]
|
|
+ return _label(self)
|
|
|
|
|
|
|
|
|
|
class StepType(type):
|
|
class StepType(type):
|
|
@@ -224,6 +257,9 @@ class StepType(type):
|
|
)
|
|
)
|
|
return super(StepType, cls).__new__(cls, name, bases, attrs)
|
|
return super(StepType, cls).__new__(cls, name, bases, attrs)
|
|
|
|
|
|
|
|
+ def __str__(self):
|
|
|
|
+ return self.name
|
|
|
|
+
|
|
def __repr__(self):
|
|
def __repr__(self):
|
|
return 'step:{0.name}{{{0.requires!r}}}'.format(self)
|
|
return 'step:{0.name}{{{0.requires!r}}}'.format(self)
|
|
|
|
|
|
@@ -242,6 +278,12 @@ class Step(object):
|
|
|
|
|
|
name = None
|
|
name = None
|
|
|
|
|
|
|
|
+
|
|
|
|
+ label = None
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ conditional = False
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
requires = ()
|
|
requires = ()
|
|
@@ -283,7 +325,7 @@ class Step(object):
|
|
|
|
|
|
@property
|
|
@property
|
|
def alias(self):
|
|
def alias(self):
|
|
- return self.name.rsplit('.', 1)[-1]
|
|
+ return self.label or _label(self)
|
|
|
|
|
|
|
|
|
|
class StartStopStep(Step):
|
|
class StartStopStep(Step):
|