sort_services.py 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. from compose.config.errors import DependencyError
  4. def get_service_name_from_net(net_config):
  5. if not net_config:
  6. return
  7. if not net_config.startswith('container:'):
  8. return
  9. _, net_name = net_config.split(':', 1)
  10. return net_name
  11. def sort_service_dicts(services):
  12. # Topological sort (Cormen/Tarjan algorithm).
  13. unmarked = services[:]
  14. temporary_marked = set()
  15. sorted_services = []
  16. def get_service_names(links):
  17. return [link.split(':')[0] for link in links]
  18. def get_service_names_from_volumes_from(volumes_from):
  19. return [volume_from.source for volume_from in volumes_from]
  20. def get_service_dependents(service_dict, services):
  21. name = service_dict['name']
  22. return [
  23. service for service in services
  24. if (name in get_service_names(service.get('links', [])) or
  25. name in get_service_names_from_volumes_from(service.get('volumes_from', [])) or
  26. name == get_service_name_from_net(service.get('net')))
  27. ]
  28. def visit(n):
  29. if n['name'] in temporary_marked:
  30. if n['name'] in get_service_names(n.get('links', [])):
  31. raise DependencyError('A service can not link to itself: %s' % n['name'])
  32. if n['name'] in n.get('volumes_from', []):
  33. raise DependencyError('A service can not mount itself as volume: %s' % n['name'])
  34. else:
  35. raise DependencyError('Circular import between %s' % ' and '.join(temporary_marked))
  36. if n in unmarked:
  37. temporary_marked.add(n['name'])
  38. for m in get_service_dependents(n, services):
  39. visit(m)
  40. temporary_marked.remove(n['name'])
  41. unmarked.remove(n)
  42. sorted_services.insert(0, n)
  43. while unmarked:
  44. visit(unmarked[-1])
  45. return sorted_services