Rework of how services are sorted based on dependencies using a topological sort.
Includes error handling to detect circular/self imports (should raise a DependecyError).
Added in logging to the CLI to log out any DependencyErrors.
Removed the compact module as it is no longer used.
This commit is contained in:
Cameron Maske 2014-01-23 22:27:54 +00:00
commit ae7573b9b8
5 changed files with 139 additions and 39 deletions

View file

@ -2,21 +2,36 @@ from __future__ import unicode_literals
from __future__ import absolute_import
import logging
from .service import Service
from .compat.functools import cmp_to_key
log = logging.getLogger(__name__)
def sort_service_dicts(services):
# Sort in dependency order
def cmp(x, y):
x_deps_y = y['name'] in x.get('links', [])
y_deps_x = x['name'] in y.get('links', [])
if x_deps_y and not y_deps_x:
return 1
elif y_deps_x and not x_deps_y:
return -1
return 0
return sorted(services, key=cmp_to_key(cmp))
# Get all services that are dependant on another.
dependent_services = [s for s in services if s.get('links')]
flatten_links = sum([s['links'] for s in dependent_services], [])
# Get all services that are not linked to and don't link to others.
non_dependent_sevices = [s for s in services if s['name'] not in flatten_links and not s.get('links')]
sorted_services = []
# Topological sort.
while dependent_services:
n = dependent_services.pop()
# Check if a service is dependent on itself, if so raise an error.
if n['name'] in n.get('links', []):
raise DependencyError('A service can not link to itself: %s' % n['name'])
sorted_services.append(n)
for l in n['links']:
# Get the linked service.
linked_service = next(s for s in services if l == s['name'])
# Check that there isn't a circular import between services.
if n['name'] in linked_service.get('links', []):
raise DependencyError('Circular import between %s and %s' % (n['name'], linked_service['name']))
# Check the linked service has no links and is not already in the
# sorted service list.
if not linked_service.get('links') and linked_service not in sorted_services:
sorted_services.insert(0, linked_service)
return non_dependent_sevices + sorted_services
class Project(object):
"""
@ -134,3 +149,11 @@ class NoSuchService(Exception):
def __str__(self):
return self.msg
class DependencyError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg