sort_services.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. return get_source_name_from_net(net_config, 'service')
  6. def get_container_name_from_net(net_config):
  7. return get_source_name_from_net(net_config, 'container')
  8. def get_source_name_from_net(net_config, source_type):
  9. if not net_config:
  10. return
  11. if not net_config.startswith(source_type+':'):
  12. return
  13. _, net_name = net_config.split(':', 1)
  14. return net_name
  15. def sort_service_dicts(services):
  16. # Topological sort (Cormen/Tarjan algorithm).
  17. unmarked = services[:]
  18. temporary_marked = set()
  19. sorted_services = []
  20. def get_service_names(links):
  21. return [link.split(':')[0] for link in links]
  22. def get_service_names_from_volumes_from(volumes_from):
  23. return [volume_from.source for volume_from in volumes_from]
  24. def get_service_dependents(service_dict, services):
  25. name = service_dict['name']
  26. return [
  27. service for service in services
  28. if (name in get_service_names(service.get('links', [])) or
  29. name in get_service_names_from_volumes_from(service.get('volumes_from', [])) or
  30. name == get_service_name_from_net(service.get('network_mode')) or
  31. name in service.get('depends_on', []))
  32. ]
  33. def visit(n):
  34. if n['name'] in temporary_marked:
  35. if n['name'] in get_service_names(n.get('links', [])):
  36. raise DependencyError('A service can not link to itself: %s' % n['name'])
  37. if n['name'] in n.get('volumes_from', []):
  38. raise DependencyError('A service can not mount itself as volume: %s' % n['name'])
  39. if n['name'] in n.get('depends_on', []):
  40. raise DependencyError('A service can not depend on itself: %s' % n['name'])
  41. raise DependencyError('Circular dependency between %s' % ' and '.join(temporary_marked))
  42. if n in unmarked:
  43. temporary_marked.add(n['name'])
  44. for m in get_service_dependents(n, services):
  45. visit(m)
  46. temporary_marked.remove(n['name'])
  47. unmarked.remove(n)
  48. sorted_services.insert(0, n)
  49. while unmarked:
  50. visit(unmarked[-1])
  51. return sorted_services