You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@senssoft.apache.org by ar...@apache.org on 2016/11/20 14:16:20 UTC

[44/51] [partial] incubator-senssoft-tap git commit: Initial containerized docker build for tap+es+distill

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/config_schema_v2.0.json
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/config_schema_v2.0.json b/env2/lib/python2.7/site-packages/compose/config/config_schema_v2.0.json
new file mode 100644
index 0000000..e84d131
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/config_schema_v2.0.json
@@ -0,0 +1,318 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "id": "config_schema_v2.0.json",
+  "type": "object",
+
+  "properties": {
+    "version": {
+      "type": "string"
+    },
+
+    "services": {
+      "id": "#/properties/services",
+      "type": "object",
+      "patternProperties": {
+        "^[a-zA-Z0-9._-]+$": {
+          "$ref": "#/definitions/service"
+        }
+      },
+      "additionalProperties": false
+    },
+
+    "networks": {
+      "id": "#/properties/networks",
+      "type": "object",
+      "patternProperties": {
+        "^[a-zA-Z0-9._-]+$": {
+          "$ref": "#/definitions/network"
+        }
+      }
+    },
+
+    "volumes": {
+      "id": "#/properties/volumes",
+      "type": "object",
+      "patternProperties": {
+        "^[a-zA-Z0-9._-]+$": {
+          "$ref": "#/definitions/volume"
+        }
+      },
+      "additionalProperties": false
+    }
+  },
+
+  "additionalProperties": false,
+
+  "definitions": {
+
+    "service": {
+      "id": "#/definitions/service",
+      "type": "object",
+
+      "properties": {
+        "build": {
+          "oneOf": [
+            {"type": "string"},
+            {
+              "type": "object",
+              "properties": {
+                "context": {"type": "string"},
+                "dockerfile": {"type": "string"},
+                "args": {"$ref": "#/definitions/list_or_dict"}
+              },
+              "additionalProperties": false
+            }
+          ]
+        },
+        "cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "cgroup_parent": {"type": "string"},
+        "command": {
+          "oneOf": [
+            {"type": "string"},
+            {"type": "array", "items": {"type": "string"}}
+          ]
+        },
+        "container_name": {"type": "string"},
+        "cpu_shares": {"type": ["number", "string"]},
+        "cpu_quota": {"type": ["number", "string"]},
+        "cpuset": {"type": "string"},
+        "depends_on": {"$ref": "#/definitions/list_of_strings"},
+        "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "dns": {"$ref": "#/definitions/string_or_list"},
+        "dns_search": {"$ref": "#/definitions/string_or_list"},
+        "domainname": {"type": "string"},
+        "entrypoint": {
+          "oneOf": [
+            {"type": "string"},
+            {"type": "array", "items": {"type": "string"}}
+          ]
+        },
+        "env_file": {"$ref": "#/definitions/string_or_list"},
+        "environment": {"$ref": "#/definitions/list_or_dict"},
+
+        "expose": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "expose"
+          },
+          "uniqueItems": true
+        },
+
+        "extends": {
+          "oneOf": [
+            {
+              "type": "string"
+            },
+            {
+              "type": "object",
+
+              "properties": {
+                "service": {"type": "string"},
+                "file": {"type": "string"}
+              },
+              "required": ["service"],
+              "additionalProperties": false
+            }
+          ]
+        },
+
+        "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
+        "hostname": {"type": "string"},
+        "image": {"type": "string"},
+        "ipc": {"type": "string"},
+        "labels": {"$ref": "#/definitions/list_or_dict"},
+        "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+
+        "logging": {
+            "type": "object",
+
+            "properties": {
+                "driver": {"type": "string"},
+                "options": {"type": "object"}
+            },
+            "additionalProperties": false
+        },
+
+        "mac_address": {"type": "string"},
+        "mem_limit": {"type": ["number", "string"]},
+        "memswap_limit": {"type": ["number", "string"]},
+        "network_mode": {"type": "string"},
+
+        "networks": {
+          "oneOf": [
+            {"$ref": "#/definitions/list_of_strings"},
+            {
+              "type": "object",
+              "patternProperties": {
+                "^[a-zA-Z0-9._-]+$": {
+                  "oneOf": [
+                    {
+                      "type": "object",
+                      "properties": {
+                        "aliases": {"$ref": "#/definitions/list_of_strings"},
+                        "ipv4_address": {"type": "string"},
+                        "ipv6_address": {"type": "string"}
+                      },
+                      "additionalProperties": false
+                    },
+                    {"type": "null"}
+                  ]
+                }
+              },
+              "additionalProperties": false
+            }
+          ]
+        },
+        "pid": {"type": ["string", "null"]},
+
+        "ports": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "ports"
+          },
+          "uniqueItems": true
+        },
+
+        "privileged": {"type": "boolean"},
+        "read_only": {"type": "boolean"},
+        "restart": {"type": "string"},
+        "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "shm_size": {"type": ["number", "string"]},
+        "stdin_open": {"type": "boolean"},
+        "stop_signal": {"type": "string"},
+        "tmpfs": {"$ref": "#/definitions/string_or_list"},
+        "tty": {"type": "boolean"},
+        "ulimits": {
+          "type": "object",
+          "patternProperties": {
+            "^[a-z]+$": {
+              "oneOf": [
+                {"type": "integer"},
+                {
+                  "type":"object",
+                  "properties": {
+                    "hard": {"type": "integer"},
+                    "soft": {"type": "integer"}
+                  },
+                  "required": ["soft", "hard"],
+                  "additionalProperties": false
+                }
+              ]
+            }
+          }
+        },
+        "user": {"type": "string"},
+        "volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "volume_driver": {"type": "string"},
+        "volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "working_dir": {"type": "string"}
+      },
+
+      "dependencies": {
+        "memswap_limit": ["mem_limit"]
+      },
+      "additionalProperties": false
+    },
+
+    "network": {
+      "id": "#/definitions/network",
+      "type": "object",
+      "properties": {
+        "driver": {"type": "string"},
+        "driver_opts": {
+          "type": "object",
+          "patternProperties": {
+            "^.+$": {"type": ["string", "number"]}
+          }
+        },
+        "ipam": {
+            "type": "object",
+            "properties": {
+                "driver": {"type": "string"},
+                "config": {
+                    "type": "array"
+                }
+            },
+            "additionalProperties": false
+        },
+        "external": {
+          "type": ["boolean", "object"],
+          "properties": {
+            "name": {"type": "string"}
+          },
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false
+    },
+
+    "volume": {
+      "id": "#/definitions/volume",
+      "type": ["object", "null"],
+      "properties": {
+        "driver": {"type": "string"},
+        "driver_opts": {
+          "type": "object",
+          "patternProperties": {
+            "^.+$": {"type": ["string", "number"]}
+          }
+        },
+        "external": {
+          "type": ["boolean", "object"],
+          "properties": {
+            "name": {"type": "string"}
+          }
+        },
+        "additionalProperties": false
+      },
+      "additionalProperties": false
+    },
+
+    "string_or_list": {
+      "oneOf": [
+        {"type": "string"},
+        {"$ref": "#/definitions/list_of_strings"}
+      ]
+    },
+
+    "list_of_strings": {
+      "type": "array",
+      "items": {"type": "string"},
+      "uniqueItems": true
+    },
+
+    "list_or_dict": {
+      "oneOf": [
+        {
+          "type": "object",
+          "patternProperties": {
+            ".+": {
+              "type": ["string", "number", "null"]
+            }
+          },
+          "additionalProperties": false
+        },
+        {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
+      ]
+    },
+
+    "constraints": {
+      "service": {
+        "id": "#/definitions/constraints/service",
+        "anyOf": [
+          {"required": ["build"]},
+          {"required": ["image"]}
+        ],
+        "properties": {
+          "build": {
+            "required": ["context"]
+          }
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/environment.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/environment.py b/env2/lib/python2.7/site-packages/compose/config/environment.py
new file mode 100644
index 0000000..5d6b5af
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/environment.py
@@ -0,0 +1,107 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import codecs
+import logging
+import os
+
+import six
+
+from ..const import IS_WINDOWS_PLATFORM
+from .errors import ConfigurationError
+
+log = logging.getLogger(__name__)
+
+
+def split_env(env):
+    if isinstance(env, six.binary_type):
+        env = env.decode('utf-8', 'replace')
+    if '=' in env:
+        return env.split('=', 1)
+    else:
+        return env, None
+
+
+def env_vars_from_file(filename):
+    """
+    Read in a line delimited file of environment variables.
+    """
+    if not os.path.exists(filename):
+        raise ConfigurationError("Couldn't find env file: %s" % filename)
+    elif not os.path.isfile(filename):
+        raise ConfigurationError("%s is not a file." % (filename))
+    env = {}
+    for line in codecs.open(filename, 'r', 'utf-8'):
+        line = line.strip()
+        if line and not line.startswith('#'):
+            k, v = split_env(line)
+            env[k] = v
+    return env
+
+
+class Environment(dict):
+    def __init__(self, *args, **kwargs):
+        super(Environment, self).__init__(*args, **kwargs)
+        self.missing_keys = []
+
+    @classmethod
+    def from_env_file(cls, base_dir):
+        def _initialize():
+            result = cls()
+            if base_dir is None:
+                return result
+            env_file_path = os.path.join(base_dir, '.env')
+            try:
+                return cls(env_vars_from_file(env_file_path))
+            except ConfigurationError:
+                pass
+            return result
+        instance = _initialize()
+        instance.update(os.environ)
+        return instance
+
+    @classmethod
+    def from_command_line(cls, parsed_env_opts):
+        result = cls()
+        for k, v in parsed_env_opts.items():
+            # Values from the command line take priority, unless they're unset
+            # in which case they take the value from the system's environment
+            if v is None and k in os.environ:
+                result[k] = os.environ[k]
+            else:
+                result[k] = v
+        return result
+
+    def __getitem__(self, key):
+        try:
+            return super(Environment, self).__getitem__(key)
+        except KeyError:
+            if IS_WINDOWS_PLATFORM:
+                try:
+                    return super(Environment, self).__getitem__(key.upper())
+                except KeyError:
+                    pass
+            if key not in self.missing_keys:
+                log.warn(
+                    "The {} variable is not set. Defaulting to a blank string."
+                    .format(key)
+                )
+                self.missing_keys.append(key)
+
+            return ""
+
+    def __contains__(self, key):
+        result = super(Environment, self).__contains__(key)
+        if IS_WINDOWS_PLATFORM:
+            return (
+                result or super(Environment, self).__contains__(key.upper())
+            )
+        return result
+
+    def get(self, key, *args, **kwargs):
+        if IS_WINDOWS_PLATFORM:
+            return super(Environment, self).get(
+                key,
+                super(Environment, self).get(key.upper(), *args, **kwargs)
+            )
+        return super(Environment, self).get(key, *args, **kwargs)

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/errors.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/errors.py b/env2/lib/python2.7/site-packages/compose/config/errors.py
new file mode 100644
index 0000000..d14cbbd
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/errors.py
@@ -0,0 +1,46 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+
+VERSION_EXPLANATION = (
+    'You might be seeing this error because you\'re using the wrong Compose '
+    'file version. Either specify a version of "2" (or "2.0") and place your '
+    'service definitions under the `services` key, or omit the `version` key '
+    'and place your service definitions at the root of the file to use '
+    'version 1.\nFor more on the Compose file format versions, see '
+    'https://docs.docker.com/compose/compose-file/')
+
+
+class ConfigurationError(Exception):
+    def __init__(self, msg):
+        self.msg = msg
+
+    def __str__(self):
+        return self.msg
+
+
+class DependencyError(ConfigurationError):
+    pass
+
+
+class CircularReference(ConfigurationError):
+    def __init__(self, trail):
+        self.trail = trail
+
+    @property
+    def msg(self):
+        lines = [
+            "{} in {}".format(service_name, filename)
+            for (filename, service_name) in self.trail
+        ]
+        return "Circular reference:\n  {}".format("\n  extends ".join(lines))
+
+
+class ComposeFileNotFound(ConfigurationError):
+    def __init__(self, supported_filenames):
+        super(ComposeFileNotFound, self).__init__("""
+        Can't find a suitable configuration file in this directory or any
+        parent. Are you in the right directory?
+
+        Supported filenames: %s
+        """ % ", ".join(supported_filenames))

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/interpolation.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/interpolation.py b/env2/lib/python2.7/site-packages/compose/config/interpolation.py
new file mode 100644
index 0000000..63020d9
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/interpolation.py
@@ -0,0 +1,63 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import logging
+from string import Template
+
+import six
+
+from .errors import ConfigurationError
+log = logging.getLogger(__name__)
+
+
+def interpolate_environment_variables(config, section, environment):
+
+    def process_item(name, config_dict):
+        return dict(
+            (key, interpolate_value(name, key, val, section, environment))
+            for key, val in (config_dict or {}).items()
+        )
+
+    return dict(
+        (name, process_item(name, config_dict or {}))
+        for name, config_dict in config.items()
+    )
+
+
+def interpolate_value(name, config_key, value, section, mapping):
+    try:
+        return recursive_interpolate(value, mapping)
+    except InvalidInterpolation as e:
+        raise ConfigurationError(
+            'Invalid interpolation format for "{config_key}" option '
+            'in {section} "{name}": "{string}"'.format(
+                config_key=config_key,
+                name=name,
+                section=section,
+                string=e.string))
+
+
+def recursive_interpolate(obj, mapping):
+    if isinstance(obj, six.string_types):
+        return interpolate(obj, mapping)
+    elif isinstance(obj, dict):
+        return dict(
+            (key, recursive_interpolate(val, mapping))
+            for (key, val) in obj.items()
+        )
+    elif isinstance(obj, list):
+        return [recursive_interpolate(val, mapping) for val in obj]
+    else:
+        return obj
+
+
+def interpolate(string, mapping):
+    try:
+        return Template(string).substitute(mapping)
+    except ValueError:
+        raise InvalidInterpolation(string)
+
+
+class InvalidInterpolation(Exception):
+    def __init__(self, string):
+        self.string = string

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/serialize.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/serialize.py b/env2/lib/python2.7/site-packages/compose/config/serialize.py
new file mode 100644
index 0000000..b788a55
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/serialize.py
@@ -0,0 +1,60 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import six
+import yaml
+
+from compose.config import types
+from compose.config.config import V1
+from compose.config.config import V2_0
+
+
+def serialize_config_type(dumper, data):
+    representer = dumper.represent_str if six.PY3 else dumper.represent_unicode
+    return representer(data.repr())
+
+
+yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type)
+yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type)
+
+
+def denormalize_config(config):
+    denormalized_services = [
+        denormalize_service_dict(service_dict, config.version)
+        for service_dict in config.services
+    ]
+    services = {
+        service_dict.pop('name'): service_dict
+        for service_dict in denormalized_services
+    }
+    networks = config.networks.copy()
+    for net_name, net_conf in networks.items():
+        if 'external_name' in net_conf:
+            del net_conf['external_name']
+
+    return {
+        'version': V2_0,
+        'services': services,
+        'networks': networks,
+        'volumes': config.volumes,
+    }
+
+
+def serialize_config(config):
+    return yaml.safe_dump(
+        denormalize_config(config),
+        default_flow_style=False,
+        indent=2,
+        width=80)
+
+
+def denormalize_service_dict(service_dict, version):
+    service_dict = service_dict.copy()
+
+    if 'restart' in service_dict:
+        service_dict['restart'] = types.serialize_restart_spec(service_dict['restart'])
+
+    if version == V1 and 'network_mode' not in service_dict:
+        service_dict['network_mode'] = 'bridge'
+
+    return service_dict

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/sort_services.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/sort_services.py b/env2/lib/python2.7/site-packages/compose/config/sort_services.py
new file mode 100644
index 0000000..20ac446
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/sort_services.py
@@ -0,0 +1,72 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+from compose.config.errors import DependencyError
+
+
+def get_service_name_from_network_mode(network_mode):
+    return get_source_name_from_network_mode(network_mode, 'service')
+
+
+def get_container_name_from_network_mode(network_mode):
+    return get_source_name_from_network_mode(network_mode, 'container')
+
+
+def get_source_name_from_network_mode(network_mode, source_type):
+    if not network_mode:
+        return
+
+    if not network_mode.startswith(source_type+':'):
+        return
+
+    _, net_name = network_mode.split(':', 1)
+    return net_name
+
+
+def get_service_names(links):
+    return [link.split(':')[0] for link in links]
+
+
+def get_service_names_from_volumes_from(volumes_from):
+    return [volume_from.source for volume_from in volumes_from]
+
+
+def get_service_dependents(service_dict, services):
+    name = service_dict['name']
+    return [
+        service for service in services
+        if (name in get_service_names(service.get('links', [])) or
+            name in get_service_names_from_volumes_from(service.get('volumes_from', [])) or
+            name == get_service_name_from_network_mode(service.get('network_mode')) or
+            name in service.get('depends_on', []))
+    ]
+
+
+def sort_service_dicts(services):
+    # Topological sort (Cormen/Tarjan algorithm).
+    unmarked = services[:]
+    temporary_marked = set()
+    sorted_services = []
+
+    def visit(n):
+        if n['name'] in temporary_marked:
+            if n['name'] in get_service_names(n.get('links', [])):
+                raise DependencyError('A service can not link to itself: %s' % n['name'])
+            if n['name'] in n.get('volumes_from', []):
+                raise DependencyError('A service can not mount itself as volume: %s' % n['name'])
+            if n['name'] in n.get('depends_on', []):
+                raise DependencyError('A service can not depend on itself: %s' % n['name'])
+            raise DependencyError('Circular dependency between %s' % ' and '.join(temporary_marked))
+
+        if n in unmarked:
+            temporary_marked.add(n['name'])
+            for m in get_service_dependents(n, services):
+                visit(m)
+            temporary_marked.remove(n['name'])
+            unmarked.remove(n)
+            sorted_services.insert(0, n)
+
+    while unmarked:
+        visit(unmarked[-1])
+
+    return sorted_services

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/types.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/types.py b/env2/lib/python2.7/site-packages/compose/config/types.py
new file mode 100644
index 0000000..e6a3dea
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/types.py
@@ -0,0 +1,198 @@
+"""
+Types for objects parsed from the configuration.
+"""
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import os
+from collections import namedtuple
+
+import six
+
+from compose.config.config import V1
+from compose.config.errors import ConfigurationError
+from compose.const import IS_WINDOWS_PLATFORM
+
+
+class VolumeFromSpec(namedtuple('_VolumeFromSpec', 'source mode type')):
+
+    # TODO: drop service_names arg when v1 is removed
+    @classmethod
+    def parse(cls, volume_from_config, service_names, version):
+        func = cls.parse_v1 if version == V1 else cls.parse_v2
+        return func(service_names, volume_from_config)
+
+    @classmethod
+    def parse_v1(cls, service_names, volume_from_config):
+        parts = volume_from_config.split(':')
+        if len(parts) > 2:
+            raise ConfigurationError(
+                "volume_from {} has incorrect format, should be "
+                "service[:mode]".format(volume_from_config))
+
+        if len(parts) == 1:
+            source = parts[0]
+            mode = 'rw'
+        else:
+            source, mode = parts
+
+        type = 'service' if source in service_names else 'container'
+        return cls(source, mode, type)
+
+    @classmethod
+    def parse_v2(cls, service_names, volume_from_config):
+        parts = volume_from_config.split(':')
+        if len(parts) > 3:
+            raise ConfigurationError(
+                "volume_from {} has incorrect format, should be one of "
+                "'<service name>[:<mode>]' or "
+                "'container:<container name>[:<mode>]'".format(volume_from_config))
+
+        if len(parts) == 1:
+            source = parts[0]
+            return cls(source, 'rw', 'service')
+
+        if len(parts) == 2:
+            if parts[0] == 'container':
+                type, source = parts
+                return cls(source, 'rw', type)
+
+            source, mode = parts
+            return cls(source, mode, 'service')
+
+        if len(parts) == 3:
+            type, source, mode = parts
+            if type not in ('service', 'container'):
+                raise ConfigurationError(
+                    "Unknown volumes_from type '{}' in '{}'".format(
+                        type,
+                        volume_from_config))
+
+        return cls(source, mode, type)
+
+    def repr(self):
+        return '{v.type}:{v.source}:{v.mode}'.format(v=self)
+
+
+def parse_restart_spec(restart_config):
+    if not restart_config:
+        return None
+    parts = restart_config.split(':')
+    if len(parts) > 2:
+        raise ConfigurationError(
+            "Restart %s has incorrect format, should be "
+            "mode[:max_retry]" % restart_config)
+    if len(parts) == 2:
+        name, max_retry_count = parts
+    else:
+        name, = parts
+        max_retry_count = 0
+
+    return {'Name': name, 'MaximumRetryCount': int(max_retry_count)}
+
+
+def serialize_restart_spec(restart_spec):
+    parts = [restart_spec['Name']]
+    if restart_spec['MaximumRetryCount']:
+        parts.append(six.text_type(restart_spec['MaximumRetryCount']))
+    return ':'.join(parts)
+
+
+def parse_extra_hosts(extra_hosts_config):
+    if not extra_hosts_config:
+        return {}
+
+    if isinstance(extra_hosts_config, dict):
+        return dict(extra_hosts_config)
+
+    if isinstance(extra_hosts_config, list):
+        extra_hosts_dict = {}
+        for extra_hosts_line in extra_hosts_config:
+            # TODO: validate string contains ':' ?
+            host, ip = extra_hosts_line.split(':', 1)
+            extra_hosts_dict[host.strip()] = ip.strip()
+        return extra_hosts_dict
+
+
+def normalize_paths_for_engine(external_path, internal_path):
+    """Windows paths, c:\my\path\shiny, need to be changed to be compatible with
+    the Engine. Volume paths are expected to be linux style /c/my/path/shiny/
+    """
+    if not IS_WINDOWS_PLATFORM:
+        return external_path, internal_path
+
+    if external_path:
+        drive, tail = os.path.splitdrive(external_path)
+
+        if drive:
+            external_path = '/' + drive.lower().rstrip(':') + tail
+
+        external_path = external_path.replace('\\', '/')
+
+    return external_path, internal_path.replace('\\', '/')
+
+
+class VolumeSpec(namedtuple('_VolumeSpec', 'external internal mode')):
+
+    @classmethod
+    def parse(cls, volume_config):
+        """Parse a volume_config path and split it into external:internal[:mode]
+        parts to be returned as a valid VolumeSpec.
+        """
+        if IS_WINDOWS_PLATFORM:
+            # relative paths in windows expand to include the drive, eg C:\
+            # so we join the first 2 parts back together to count as one
+            drive, tail = os.path.splitdrive(volume_config)
+            parts = tail.split(":")
+
+            if drive:
+                parts[0] = drive + parts[0]
+        else:
+            parts = volume_config.split(':')
+
+        if len(parts) > 3:
+            raise ConfigurationError(
+                "Volume %s has incorrect format, should be "
+                "external:internal[:mode]" % volume_config)
+
+        if len(parts) == 1:
+            external, internal = normalize_paths_for_engine(
+                None,
+                os.path.normpath(parts[0]))
+        else:
+            external, internal = normalize_paths_for_engine(
+                os.path.normpath(parts[0]),
+                os.path.normpath(parts[1]))
+
+        mode = 'rw'
+        if len(parts) == 3:
+            mode = parts[2]
+
+        return cls(external, internal, mode)
+
+    def repr(self):
+        external = self.external + ':' if self.external else ''
+        return '{ext}{v.internal}:{v.mode}'.format(ext=external, v=self)
+
+    @property
+    def is_named_volume(self):
+        return self.external and not self.external.startswith(('.', '/', '~'))
+
+
+class ServiceLink(namedtuple('_ServiceLink', 'target alias')):
+
+    @classmethod
+    def parse(cls, link_spec):
+        target, _, alias = link_spec.partition(':')
+        if not alias:
+            alias = target
+        return cls(target, alias)
+
+    def repr(self):
+        if self.target == self.alias:
+            return self.target
+        return '{s.target}:{s.alias}'.format(s=self)
+
+    @property
+    def merge_field(self):
+        return self.alias

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/config/validation.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/config/validation.py b/env2/lib/python2.7/site-packages/compose/config/validation.py
new file mode 100644
index 0000000..7452e98
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/config/validation.py
@@ -0,0 +1,421 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import json
+import logging
+import os
+import re
+import sys
+
+import six
+from docker.utils.ports import split_port
+from jsonschema import Draft4Validator
+from jsonschema import FormatChecker
+from jsonschema import RefResolver
+from jsonschema import ValidationError
+
+from ..const import COMPOSEFILE_V1 as V1
+from .errors import ConfigurationError
+from .errors import VERSION_EXPLANATION
+from .sort_services import get_service_name_from_network_mode
+
+
+log = logging.getLogger(__name__)
+
+
+DOCKER_CONFIG_HINTS = {
+    'cpu_share': 'cpu_shares',
+    'add_host': 'extra_hosts',
+    'hosts': 'extra_hosts',
+    'extra_host': 'extra_hosts',
+    'device': 'devices',
+    'link': 'links',
+    'memory_swap': 'memswap_limit',
+    'port': 'ports',
+    'privilege': 'privileged',
+    'priviliged': 'privileged',
+    'privilige': 'privileged',
+    'volume': 'volumes',
+    'workdir': 'working_dir',
+}
+
+
+VALID_NAME_CHARS = '[a-zA-Z0-9\._\-]'
+VALID_EXPOSE_FORMAT = r'^\d+(\-\d+)?(\/[a-zA-Z]+)?$'
+
+
+@FormatChecker.cls_checks(format="ports", raises=ValidationError)
+def format_ports(instance):
+    try:
+        split_port(instance)
+    except ValueError as e:
+        raise ValidationError(six.text_type(e))
+    return True
+
+
+@FormatChecker.cls_checks(format="expose", raises=ValidationError)
+def format_expose(instance):
+    if isinstance(instance, six.string_types):
+        if not re.match(VALID_EXPOSE_FORMAT, instance):
+            raise ValidationError(
+                "should be of the format 'PORT[/PROTOCOL]'")
+
+    return True
+
+
+def match_named_volumes(service_dict, project_volumes):
+    service_volumes = service_dict.get('volumes', [])
+    for volume_spec in service_volumes:
+        if volume_spec.is_named_volume and volume_spec.external not in project_volumes:
+            raise ConfigurationError(
+                'Named volume "{0}" is used in service "{1}" but no'
+                ' declaration was found in the volumes section.'.format(
+                    volume_spec.repr(), service_dict.get('name')
+                )
+            )
+
+
+def python_type_to_yaml_type(type_):
+    type_name = type(type_).__name__
+    return {
+        'dict': 'mapping',
+        'list': 'array',
+        'int': 'number',
+        'float': 'number',
+        'bool': 'boolean',
+        'unicode': 'string',
+        'str': 'string',
+        'bytes': 'string',
+    }.get(type_name, type_name)
+
+
+def validate_config_section(filename, config, section):
+    """Validate the structure of a configuration section. This must be done
+    before interpolation so it's separate from schema validation.
+    """
+    if not isinstance(config, dict):
+        raise ConfigurationError(
+            "In file '{filename}', {section} must be a mapping, not "
+            "{type}.".format(
+                filename=filename,
+                section=section,
+                type=anglicize_json_type(python_type_to_yaml_type(config))))
+
+    for key, value in config.items():
+        if not isinstance(key, six.string_types):
+            raise ConfigurationError(
+                "In file '{filename}', the {section} name {name} must be a "
+                "quoted string, i.e. '{name}'.".format(
+                    filename=filename,
+                    section=section,
+                    name=key))
+
+        if not isinstance(value, (dict, type(None))):
+            raise ConfigurationError(
+                "In file '{filename}', {section} '{name}' must be a mapping not "
+                "{type}.".format(
+                    filename=filename,
+                    section=section,
+                    name=key,
+                    type=anglicize_json_type(python_type_to_yaml_type(value))))
+
+
+def validate_top_level_object(config_file):
+    if not isinstance(config_file.config, dict):
+        raise ConfigurationError(
+            "Top level object in '{}' needs to be an object not '{}'.".format(
+                config_file.filename,
+                type(config_file.config)))
+
+
+def validate_ulimits(service_config):
+    ulimit_config = service_config.config.get('ulimits', {})
+    for limit_name, soft_hard_values in six.iteritems(ulimit_config):
+        if isinstance(soft_hard_values, dict):
+            if not soft_hard_values['soft'] <= soft_hard_values['hard']:
+                raise ConfigurationError(
+                    "Service '{s.name}' has invalid ulimit '{ulimit}'. "
+                    "'soft' value can not be greater than 'hard' value ".format(
+                        s=service_config,
+                        ulimit=ulimit_config))
+
+
+def validate_extends_file_path(service_name, extends_options, filename):
+    """
+    The service to be extended must either be defined in the config key 'file',
+    or within 'filename'.
+    """
+    error_prefix = "Invalid 'extends' configuration for %s:" % service_name
+
+    if 'file' not in extends_options and filename is None:
+        raise ConfigurationError(
+            "%s you need to specify a 'file', e.g. 'file: something.yml'" % error_prefix
+        )
+
+
+def validate_network_mode(service_config, service_names):
+    network_mode = service_config.config.get('network_mode')
+    if not network_mode:
+        return
+
+    if 'networks' in service_config.config:
+        raise ConfigurationError("'network_mode' and 'networks' cannot be combined")
+
+    dependency = get_service_name_from_network_mode(network_mode)
+    if not dependency:
+        return
+
+    if dependency not in service_names:
+        raise ConfigurationError(
+            "Service '{s.name}' uses the network stack of service '{dep}' which "
+            "is undefined.".format(s=service_config, dep=dependency))
+
+
+def validate_links(service_config, service_names):
+    for link in service_config.config.get('links', []):
+        if link.split(':')[0] not in service_names:
+            raise ConfigurationError(
+                "Service '{s.name}' has a link to service '{link}' which is "
+                "undefined.".format(s=service_config, link=link))
+
+
+def validate_depends_on(service_config, service_names):
+    for dependency in service_config.config.get('depends_on', []):
+        if dependency not in service_names:
+            raise ConfigurationError(
+                "Service '{s.name}' depends on service '{dep}' which is "
+                "undefined.".format(s=service_config, dep=dependency))
+
+
+def get_unsupported_config_msg(path, error_key):
+    msg = "Unsupported config option for {}: '{}'".format(path_string(path), error_key)
+    if error_key in DOCKER_CONFIG_HINTS:
+        msg += " (did you mean '{}'?)".format(DOCKER_CONFIG_HINTS[error_key])
+    return msg
+
+
+def anglicize_json_type(json_type):
+    if json_type.startswith(('a', 'e', 'i', 'o', 'u')):
+        return 'an ' + json_type
+    return 'a ' + json_type
+
+
+def is_service_dict_schema(schema_id):
+    return schema_id in ('config_schema_v1.json',  '#/properties/services')
+
+
+def handle_error_for_schema_with_id(error, path):
+    schema_id = error.schema['id']
+
+    if is_service_dict_schema(schema_id) and error.validator == 'additionalProperties':
+        return "Invalid service name '{}' - only {} characters are allowed".format(
+            # The service_name is the key to the json object
+            list(error.instance)[0],
+            VALID_NAME_CHARS)
+
+    if error.validator == 'additionalProperties':
+        if schema_id == '#/definitions/service':
+            invalid_config_key = parse_key_from_error_msg(error)
+            return get_unsupported_config_msg(path, invalid_config_key)
+
+        if not error.path:
+            return '{}\n\n{}'.format(error.message, VERSION_EXPLANATION)
+
+
+def handle_generic_error(error, path):
+    msg_format = None
+    error_msg = error.message
+
+    if error.validator == 'oneOf':
+        msg_format = "{path} {msg}"
+        config_key, error_msg = _parse_oneof_validator(error)
+        if config_key:
+            path.append(config_key)
+
+    elif error.validator == 'type':
+        msg_format = "{path} contains an invalid type, it should be {msg}"
+        error_msg = _parse_valid_types_from_validator(error.validator_value)
+
+    elif error.validator == 'required':
+        error_msg = ", ".join(error.validator_value)
+        msg_format = "{path} is invalid, {msg} is required."
+
+    elif error.validator == 'dependencies':
+        config_key = list(error.validator_value.keys())[0]
+        required_keys = ",".join(error.validator_value[config_key])
+
+        msg_format = "{path} is invalid: {msg}"
+        path.append(config_key)
+        error_msg = "when defining '{}' you must set '{}' as well".format(
+            config_key,
+            required_keys)
+
+    elif error.cause:
+        error_msg = six.text_type(error.cause)
+        msg_format = "{path} is invalid: {msg}"
+
+    elif error.path:
+        msg_format = "{path} value {msg}"
+
+    if msg_format:
+        return msg_format.format(path=path_string(path), msg=error_msg)
+
+    return error.message
+
+
+def parse_key_from_error_msg(error):
+    return error.message.split("'")[1]
+
+
+def path_string(path):
+    return ".".join(c for c in path if isinstance(c, six.string_types))
+
+
+def _parse_valid_types_from_validator(validator):
+    """A validator value can be either an array of valid types or a string of
+    a valid type. Parse the valid types and prefix with the correct article.
+    """
+    if not isinstance(validator, list):
+        return anglicize_json_type(validator)
+
+    if len(validator) == 1:
+        return anglicize_json_type(validator[0])
+
+    return "{}, or {}".format(
+        ", ".join([anglicize_json_type(validator[0])] + validator[1:-1]),
+        anglicize_json_type(validator[-1]))
+
+
+def _parse_oneof_validator(error):
+    """oneOf has multiple schemas, so we need to reason about which schema, sub
+    schema or constraint the validation is failing on.
+    Inspecting the context value of a ValidationError gives us information about
+    which sub schema failed and which kind of error it is.
+    """
+    types = []
+    for context in error.context:
+
+        if context.validator == 'oneOf':
+            _, error_msg = _parse_oneof_validator(context)
+            return path_string(context.path), error_msg
+
+        if context.validator == 'required':
+            return (None, context.message)
+
+        if context.validator == 'additionalProperties':
+            invalid_config_key = parse_key_from_error_msg(context)
+            return (None, "contains unsupported option: '{}'".format(invalid_config_key))
+
+        if context.path:
+            return (
+                path_string(context.path),
+                "contains {}, which is an invalid type, it should be {}".format(
+                    json.dumps(context.instance),
+                    _parse_valid_types_from_validator(context.validator_value)),
+            )
+
+        if context.validator == 'uniqueItems':
+            return (
+                None,
+                "contains non unique items, please remove duplicates from {}".format(
+                    context.instance),
+            )
+
+        if context.validator == 'type':
+            types.append(context.validator_value)
+
+    valid_types = _parse_valid_types_from_validator(types)
+    return (None, "contains an invalid type, it should be {}".format(valid_types))
+
+
+def process_service_constraint_errors(error, service_name, version):
+    if version == V1:
+        if 'image' in error.instance and 'build' in error.instance:
+            return (
+                "Service {} has both an image and build path specified. "
+                "A service can either be built to image or use an existing "
+                "image, not both.".format(service_name))
+
+        if 'image' in error.instance and 'dockerfile' in error.instance:
+            return (
+                "Service {} has both an image and alternate Dockerfile. "
+                "A service can either be built to image or use an existing "
+                "image, not both.".format(service_name))
+
+    if 'image' not in error.instance and 'build' not in error.instance:
+        return (
+            "Service {} has neither an image nor a build context specified. "
+            "At least one must be provided.".format(service_name))
+
+
+def process_config_schema_errors(error):
+    path = list(error.path)
+
+    if 'id' in error.schema:
+        error_msg = handle_error_for_schema_with_id(error, path)
+        if error_msg:
+            return error_msg
+
+    return handle_generic_error(error, path)
+
+
+def validate_against_config_schema(config_file):
+    schema = load_jsonschema(config_file.version)
+    format_checker = FormatChecker(["ports", "expose"])
+    validator = Draft4Validator(
+        schema,
+        resolver=RefResolver(get_resolver_path(), schema),
+        format_checker=format_checker)
+    handle_errors(
+        validator.iter_errors(config_file.config),
+        process_config_schema_errors,
+        config_file.filename)
+
+
+def validate_service_constraints(config, service_name, version):
+    def handler(errors):
+        return process_service_constraint_errors(errors, service_name, version)
+
+    schema = load_jsonschema(version)
+    validator = Draft4Validator(schema['definitions']['constraints']['service'])
+    handle_errors(validator.iter_errors(config), handler, None)
+
+
+def get_schema_path():
+    return os.path.dirname(os.path.abspath(__file__))
+
+
+def load_jsonschema(version):
+    filename = os.path.join(
+        get_schema_path(),
+        "config_schema_v{0}.json".format(version))
+
+    with open(filename, "r") as fh:
+        return json.load(fh)
+
+
+def get_resolver_path():
+    schema_path = get_schema_path()
+    if sys.platform == "win32":
+        scheme = "///"
+        # TODO: why is this necessary?
+        schema_path = schema_path.replace('\\', '/')
+    else:
+        scheme = "//"
+    return "file:{}{}/".format(scheme, schema_path)
+
+
+def handle_errors(errors, format_error_func, filename):
+    """jsonschema returns an error tree full of information to explain what has
+    gone wrong. Process each error and pull out relevant information and re-write
+    helpful error messages that are relevant.
+    """
+    errors = list(sorted(errors, key=str))
+    if not errors:
+        return
+
+    error_msg = '\n'.join(format_error_func(error) for error in errors)
+    raise ConfigurationError(
+        "The Compose file{file_msg} is invalid because:\n{error_msg}".format(
+            file_msg=" '{}'".format(filename) if filename else "",
+            error_msg=error_msg))

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/const.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/const.py b/env2/lib/python2.7/site-packages/compose/const.py
new file mode 100644
index 0000000..b930e0b
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/const.py
@@ -0,0 +1,28 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import sys
+
+DEFAULT_TIMEOUT = 10
+HTTP_TIMEOUT = 60
+IMAGE_EVENTS = ['delete', 'import', 'pull', 'push', 'tag', 'untag']
+IS_WINDOWS_PLATFORM = (sys.platform == "win32")
+LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'
+LABEL_ONE_OFF = 'com.docker.compose.oneoff'
+LABEL_PROJECT = 'com.docker.compose.project'
+LABEL_SERVICE = 'com.docker.compose.service'
+LABEL_VERSION = 'com.docker.compose.version'
+LABEL_CONFIG_HASH = 'com.docker.compose.config-hash'
+
+COMPOSEFILE_V1 = '1'
+COMPOSEFILE_V2_0 = '2.0'
+
+API_VERSIONS = {
+    COMPOSEFILE_V1: '1.21',
+    COMPOSEFILE_V2_0: '1.22',
+}
+
+API_VERSION_TO_ENGINE_VERSION = {
+    API_VERSIONS[COMPOSEFILE_V1]: '1.9.0',
+    API_VERSIONS[COMPOSEFILE_V2_0]: '1.10.0'
+}

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/container.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/container.py b/env2/lib/python2.7/site-packages/compose/container.py
new file mode 100644
index 0000000..2c16863
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/container.py
@@ -0,0 +1,272 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+from functools import reduce
+
+import six
+
+from .const import LABEL_CONTAINER_NUMBER
+from .const import LABEL_PROJECT
+from .const import LABEL_SERVICE
+
+
+class Container(object):
+    """
+    Represents a Docker container, constructed from the output of
+    GET /containers/:id:/json.
+    """
+    def __init__(self, client, dictionary, has_been_inspected=False):
+        self.client = client
+        self.dictionary = dictionary
+        self.has_been_inspected = has_been_inspected
+        self.log_stream = None
+
+    @classmethod
+    def from_ps(cls, client, dictionary, **kwargs):
+        """
+        Construct a container object from the output of GET /containers/json.
+        """
+        name = get_container_name(dictionary)
+        if name is None:
+            return None
+
+        new_dictionary = {
+            'Id': dictionary['Id'],
+            'Image': dictionary['Image'],
+            'Name': '/' + name,
+        }
+        return cls(client, new_dictionary, **kwargs)
+
+    @classmethod
+    def from_id(cls, client, id):
+        return cls(client, client.inspect_container(id), has_been_inspected=True)
+
+    @classmethod
+    def create(cls, client, **options):
+        response = client.create_container(**options)
+        return cls.from_id(client, response['Id'])
+
+    @property
+    def id(self):
+        return self.dictionary['Id']
+
+    @property
+    def image(self):
+        return self.dictionary['Image']
+
+    @property
+    def image_config(self):
+        return self.client.inspect_image(self.image)
+
+    @property
+    def short_id(self):
+        return self.id[:12]
+
+    @property
+    def name(self):
+        return self.dictionary['Name'][1:]
+
+    @property
+    def service(self):
+        return self.labels.get(LABEL_SERVICE)
+
+    @property
+    def name_without_project(self):
+        project = self.labels.get(LABEL_PROJECT)
+
+        if self.name.startswith('{0}_{1}'.format(project, self.service)):
+            return '{0}_{1}'.format(self.service, self.number)
+        else:
+            return self.name
+
+    @property
+    def number(self):
+        number = self.labels.get(LABEL_CONTAINER_NUMBER)
+        if not number:
+            raise ValueError("Container {0} does not have a {1} label".format(
+                self.short_id, LABEL_CONTAINER_NUMBER))
+        return int(number)
+
+    @property
+    def ports(self):
+        self.inspect_if_not_inspected()
+        return self.get('NetworkSettings.Ports') or {}
+
+    @property
+    def human_readable_ports(self):
+        def format_port(private, public):
+            if not public:
+                return private
+            return '{HostIp}:{HostPort}->{private}'.format(
+                private=private, **public[0])
+
+        return ', '.join(format_port(*item)
+                         for item in sorted(six.iteritems(self.ports)))
+
+    @property
+    def labels(self):
+        return self.get('Config.Labels') or {}
+
+    @property
+    def stop_signal(self):
+        return self.get('Config.StopSignal')
+
+    @property
+    def log_config(self):
+        return self.get('HostConfig.LogConfig') or None
+
+    @property
+    def human_readable_state(self):
+        if self.is_paused:
+            return 'Paused'
+        if self.is_restarting:
+            return 'Restarting'
+        if self.is_running:
+            return 'Ghost' if self.get('State.Ghost') else 'Up'
+        else:
+            return 'Exit %s' % self.get('State.ExitCode')
+
+    @property
+    def human_readable_command(self):
+        entrypoint = self.get('Config.Entrypoint') or []
+        cmd = self.get('Config.Cmd') or []
+        return ' '.join(entrypoint + cmd)
+
+    @property
+    def environment(self):
+        def parse_env(var):
+            if '=' in var:
+                return var.split("=", 1)
+            return var, None
+        return dict(parse_env(var) for var in self.get('Config.Env') or [])
+
+    @property
+    def exit_code(self):
+        return self.get('State.ExitCode')
+
+    @property
+    def is_running(self):
+        return self.get('State.Running')
+
+    @property
+    def is_restarting(self):
+        return self.get('State.Restarting')
+
+    @property
+    def is_paused(self):
+        return self.get('State.Paused')
+
+    @property
+    def log_driver(self):
+        return self.get('HostConfig.LogConfig.Type')
+
+    @property
+    def has_api_logs(self):
+        log_type = self.log_driver
+        return not log_type or log_type != 'none'
+
+    def attach_log_stream(self):
+        """A log stream can only be attached if the container uses a json-file
+        log driver.
+        """
+        if self.has_api_logs:
+            self.log_stream = self.attach(stdout=True, stderr=True, stream=True)
+
+    def get(self, key):
+        """Return a value from the container or None if the value is not set.
+
+        :param key: a string using dotted notation for nested dictionary
+                    lookups
+        """
+        self.inspect_if_not_inspected()
+
+        def get_value(dictionary, key):
+            return (dictionary or {}).get(key)
+
+        return reduce(get_value, key.split('.'), self.dictionary)
+
+    def get_local_port(self, port, protocol='tcp'):
+        port = self.ports.get("%s/%s" % (port, protocol))
+        return "{HostIp}:{HostPort}".format(**port[0]) if port else None
+
+    def get_mount(self, mount_dest):
+        for mount in self.get('Mounts'):
+            if mount['Destination'] == mount_dest:
+                return mount
+        return None
+
+    def start(self, **options):
+        return self.client.start(self.id, **options)
+
+    def stop(self, **options):
+        return self.client.stop(self.id, **options)
+
+    def pause(self, **options):
+        return self.client.pause(self.id, **options)
+
+    def unpause(self, **options):
+        return self.client.unpause(self.id, **options)
+
+    def kill(self, **options):
+        return self.client.kill(self.id, **options)
+
+    def restart(self, **options):
+        return self.client.restart(self.id, **options)
+
+    def remove(self, **options):
+        return self.client.remove_container(self.id, **options)
+
+    def create_exec(self, command, **options):
+        return self.client.exec_create(self.id, command, **options)
+
+    def start_exec(self, exec_id, **options):
+        return self.client.exec_start(exec_id, **options)
+
+    def rename_to_tmp_name(self):
+        """Rename the container to a hopefully unique temporary container name
+        by prepending the short id.
+        """
+        self.client.rename(
+            self.id,
+            '%s_%s' % (self.short_id, self.name)
+        )
+
+    def inspect_if_not_inspected(self):
+        if not self.has_been_inspected:
+            self.inspect()
+
+    def wait(self):
+        return self.client.wait(self.id)
+
+    def logs(self, *args, **kwargs):
+        return self.client.logs(self.id, *args, **kwargs)
+
+    def inspect(self):
+        self.dictionary = self.client.inspect_container(self.id)
+        self.has_been_inspected = True
+        return self.dictionary
+
+    def attach(self, *args, **kwargs):
+        return self.client.attach(self.id, *args, **kwargs)
+
+    def __repr__(self):
+        return '<Container: %s (%s)>' % (self.name, self.id[:6])
+
+    def __eq__(self, other):
+        if type(self) != type(other):
+            return False
+        return self.id == other.id
+
+    def __hash__(self):
+        return self.id.__hash__()
+
+
+def get_container_name(container):
+    if not container.get('Name') and not container.get('Names'):
+        return None
+    # inspect
+    if 'Name' in container:
+        return container['Name']
+    # ps
+    shortest_name = min(container['Names'], key=lambda n: len(n.split('/')))
+    return shortest_name.split('/')[-1]

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/errors.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/errors.py b/env2/lib/python2.7/site-packages/compose/errors.py
new file mode 100644
index 0000000..9f68760
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/errors.py
@@ -0,0 +1,7 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+
+class OperationFailedError(Exception):
+    def __init__(self, reason):
+        self.msg = reason

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/network.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/network.py b/env2/lib/python2.7/site-packages/compose/network.py
new file mode 100644
index 0000000..affba7c
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/network.py
@@ -0,0 +1,190 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import logging
+
+from docker.errors import NotFound
+from docker.utils import create_ipam_config
+from docker.utils import create_ipam_pool
+
+from .config import ConfigurationError
+
+
+log = logging.getLogger(__name__)
+
+
+class Network(object):
+    def __init__(self, client, project, name, driver=None, driver_opts=None,
+                 ipam=None, external_name=None):
+        self.client = client
+        self.project = project
+        self.name = name
+        self.driver = driver
+        self.driver_opts = driver_opts
+        self.ipam = create_ipam_config_from_dict(ipam)
+        self.external_name = external_name
+
+    def ensure(self):
+        if self.external_name:
+            try:
+                self.inspect()
+                log.debug(
+                    'Network {0} declared as external. No new '
+                    'network will be created.'.format(self.name)
+                )
+            except NotFound:
+                raise ConfigurationError(
+                    'Network {name} declared as external, but could'
+                    ' not be found. Please create the network manually'
+                    ' using `{command} {name}` and try again.'.format(
+                        name=self.external_name,
+                        command='docker network create'
+                    )
+                )
+            return
+
+        try:
+            data = self.inspect()
+            if self.driver and data['Driver'] != self.driver:
+                raise ConfigurationError(
+                    'Network "{}" needs to be recreated - driver has changed'
+                    .format(self.full_name))
+            if data['Options'] != (self.driver_opts or {}):
+                raise ConfigurationError(
+                    'Network "{}" needs to be recreated - options have changed'
+                    .format(self.full_name))
+        except NotFound:
+            driver_name = 'the default driver'
+            if self.driver:
+                driver_name = 'driver "{}"'.format(self.driver)
+
+            log.info(
+                'Creating network "{}" with {}'
+                .format(self.full_name, driver_name)
+            )
+
+            self.client.create_network(
+                name=self.full_name,
+                driver=self.driver,
+                options=self.driver_opts,
+                ipam=self.ipam,
+            )
+
+    def remove(self):
+        if self.external_name:
+            log.info("Network %s is external, skipping", self.full_name)
+            return
+
+        log.info("Removing network {}".format(self.full_name))
+        self.client.remove_network(self.full_name)
+
+    def inspect(self):
+        return self.client.inspect_network(self.full_name)
+
+    @property
+    def full_name(self):
+        if self.external_name:
+            return self.external_name
+        return '{0}_{1}'.format(self.project, self.name)
+
+
+def create_ipam_config_from_dict(ipam_dict):
+    if not ipam_dict:
+        return None
+
+    return create_ipam_config(
+        driver=ipam_dict.get('driver'),
+        pool_configs=[
+            create_ipam_pool(
+                subnet=config.get('subnet'),
+                iprange=config.get('ip_range'),
+                gateway=config.get('gateway'),
+                aux_addresses=config.get('aux_addresses'),
+            )
+            for config in ipam_dict.get('config', [])
+        ],
+    )
+
+
+def build_networks(name, config_data, client):
+    network_config = config_data.networks or {}
+    networks = {
+        network_name: Network(
+            client=client, project=name, name=network_name,
+            driver=data.get('driver'),
+            driver_opts=data.get('driver_opts'),
+            ipam=data.get('ipam'),
+            external_name=data.get('external_name'),
+        )
+        for network_name, data in network_config.items()
+    }
+
+    if 'default' not in networks:
+        networks['default'] = Network(client, name, 'default')
+
+    return networks
+
+
+class ProjectNetworks(object):
+
+    def __init__(self, networks, use_networking):
+        self.networks = networks or {}
+        self.use_networking = use_networking
+
+    @classmethod
+    def from_services(cls, services, networks, use_networking):
+        service_networks = {
+            network: networks.get(network)
+            for service in services
+            for network in get_network_names_for_service(service)
+        }
+        unused = set(networks) - set(service_networks) - {'default'}
+        if unused:
+            log.warn(
+                "Some networks were defined but are not used by any service: "
+                "{}".format(", ".join(unused)))
+        return cls(service_networks, use_networking)
+
+    def remove(self):
+        if not self.use_networking:
+            return
+        for network in self.networks.values():
+            try:
+                network.remove()
+            except NotFound:
+                log.warn("Network %s not found.", network.full_name)
+
+    def initialize(self):
+        if not self.use_networking:
+            return
+
+        for network in self.networks.values():
+            network.ensure()
+
+
+def get_network_defs_for_service(service_dict):
+    if 'network_mode' in service_dict:
+        return {}
+    networks = service_dict.get('networks', {'default': None})
+    return dict(
+        (net, (config or {}))
+        for net, config in networks.items()
+    )
+
+
+def get_network_names_for_service(service_dict):
+    return get_network_defs_for_service(service_dict).keys()
+
+
+def get_networks(service_dict, network_definitions):
+    networks = {}
+    for name, netdef in get_network_defs_for_service(service_dict).items():
+        network = network_definitions.get(name)
+        if network:
+            networks[network.full_name] = netdef
+        else:
+            raise ConfigurationError(
+                'Service "{}" uses an undefined network "{}"'
+                .format(service_dict['name'], name))
+
+    return networks

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/parallel.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/parallel.py b/env2/lib/python2.7/site-packages/compose/parallel.py
new file mode 100644
index 0000000..7ac66b3
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/parallel.py
@@ -0,0 +1,254 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import logging
+import operator
+import sys
+from threading import Thread
+
+from docker.errors import APIError
+from six.moves import _thread as thread
+from six.moves.queue import Empty
+from six.moves.queue import Queue
+
+from compose.cli.signals import ShutdownException
+from compose.errors import OperationFailedError
+from compose.utils import get_output_stream
+
+
+log = logging.getLogger(__name__)
+
+STOP = object()
+
+
+def parallel_execute(objects, func, get_name, msg, get_deps=None):
+    """Runs func on objects in parallel while ensuring that func is
+    ran on object only after it is ran on all its dependencies.
+
+    get_deps called on object must return a collection with its dependencies.
+    get_name called on object must return its name.
+    """
+    objects = list(objects)
+    stream = get_output_stream(sys.stderr)
+
+    writer = ParallelStreamWriter(stream, msg)
+    for obj in objects:
+        writer.initialize(get_name(obj))
+
+    events = parallel_execute_iter(objects, func, get_deps)
+
+    errors = {}
+    results = []
+    error_to_reraise = None
+
+    for obj, result, exception in events:
+        if exception is None:
+            writer.write(get_name(obj), 'done')
+            results.append(result)
+        elif isinstance(exception, APIError):
+            errors[get_name(obj)] = exception.explanation
+            writer.write(get_name(obj), 'error')
+        elif isinstance(exception, OperationFailedError):
+            errors[get_name(obj)] = exception.msg
+            writer.write(get_name(obj), 'error')
+        elif isinstance(exception, UpstreamError):
+            writer.write(get_name(obj), 'error')
+        else:
+            errors[get_name(obj)] = exception
+            error_to_reraise = exception
+
+    for obj_name, error in errors.items():
+        stream.write("\nERROR: for {}  {}\n".format(obj_name, error))
+
+    if error_to_reraise:
+        raise error_to_reraise
+
+    return results, errors
+
+
+def _no_deps(x):
+    return []
+
+
+class State(object):
+    """
+    Holds the state of a partially-complete parallel operation.
+
+    state.started:   objects being processed
+    state.finished:  objects which have been processed
+    state.failed:    objects which either failed or whose dependencies failed
+    """
+    def __init__(self, objects):
+        self.objects = objects
+
+        self.started = set()
+        self.finished = set()
+        self.failed = set()
+
+    def is_done(self):
+        return len(self.finished) + len(self.failed) >= len(self.objects)
+
+    def pending(self):
+        return set(self.objects) - self.started - self.finished - self.failed
+
+
+def parallel_execute_iter(objects, func, get_deps):
+    """
+    Runs func on objects in parallel while ensuring that func is
+    ran on object only after it is ran on all its dependencies.
+
+    Returns an iterator of tuples which look like:
+
+    # if func returned normally when run on object
+    (object, result, None)
+
+    # if func raised an exception when run on object
+    (object, None, exception)
+
+    # if func raised an exception when run on one of object's dependencies
+    (object, None, UpstreamError())
+    """
+    if get_deps is None:
+        get_deps = _no_deps
+
+    results = Queue()
+    state = State(objects)
+
+    while True:
+        feed_queue(objects, func, get_deps, results, state)
+
+        try:
+            event = results.get(timeout=0.1)
+        except Empty:
+            continue
+        # See https://github.com/docker/compose/issues/189
+        except thread.error:
+            raise ShutdownException()
+
+        if event is STOP:
+            break
+
+        obj, _, exception = event
+        if exception is None:
+            log.debug('Finished processing: {}'.format(obj))
+            state.finished.add(obj)
+        else:
+            log.debug('Failed: {}'.format(obj))
+            state.failed.add(obj)
+
+        yield event
+
+
+def producer(obj, func, results):
+    """
+    The entry point for a producer thread which runs func on a single object.
+    Places a tuple on the results queue once func has either returned or raised.
+    """
+    try:
+        result = func(obj)
+        results.put((obj, result, None))
+    except Exception as e:
+        results.put((obj, None, e))
+
+
+def feed_queue(objects, func, get_deps, results, state):
+    """
+    Starts producer threads for any objects which are ready to be processed
+    (i.e. they have no dependencies which haven't been successfully processed).
+
+    Shortcuts any objects whose dependencies have failed and places an
+    (object, None, UpstreamError()) tuple on the results queue.
+    """
+    pending = state.pending()
+    log.debug('Pending: {}'.format(pending))
+
+    for obj in pending:
+        deps = get_deps(obj)
+
+        if any(dep in state.failed for dep in deps):
+            log.debug('{} has upstream errors - not processing'.format(obj))
+            results.put((obj, None, UpstreamError()))
+            state.failed.add(obj)
+        elif all(
+            dep not in objects or dep in state.finished
+            for dep in deps
+        ):
+            log.debug('Starting producer thread for {}'.format(obj))
+            t = Thread(target=producer, args=(obj, func, results))
+            t.daemon = True
+            t.start()
+            state.started.add(obj)
+
+    if state.is_done():
+        results.put(STOP)
+
+
+class UpstreamError(Exception):
+    pass
+
+
+class ParallelStreamWriter(object):
+    """Write out messages for operations happening in parallel.
+
+    Each operation has it's own line, and ANSI code characters are used
+    to jump to the correct line, and write over the line.
+    """
+
+    def __init__(self, stream, msg):
+        self.stream = stream
+        self.msg = msg
+        self.lines = []
+
+    def initialize(self, obj_index):
+        if self.msg is None:
+            return
+        self.lines.append(obj_index)
+        self.stream.write("{} {} ... \r\n".format(self.msg, obj_index))
+        self.stream.flush()
+
+    def write(self, obj_index, status):
+        if self.msg is None:
+            return
+        position = self.lines.index(obj_index)
+        diff = len(self.lines) - position
+        # move up
+        self.stream.write("%c[%dA" % (27, diff))
+        # erase
+        self.stream.write("%c[2K\r" % 27)
+        self.stream.write("{} {} ... {}\r".format(self.msg, obj_index, status))
+        # move back down
+        self.stream.write("%c[%dB" % (27, diff))
+        self.stream.flush()
+
+
+def parallel_operation(containers, operation, options, message):
+    parallel_execute(
+        containers,
+        operator.methodcaller(operation, **options),
+        operator.attrgetter('name'),
+        message)
+
+
+def parallel_remove(containers, options):
+    stopped_containers = [c for c in containers if not c.is_running]
+    parallel_operation(stopped_containers, 'remove', options, 'Removing')
+
+
+def parallel_start(containers, options):
+    parallel_operation(containers, 'start', options, 'Starting')
+
+
+def parallel_pause(containers, options):
+    parallel_operation(containers, 'pause', options, 'Pausing')
+
+
+def parallel_unpause(containers, options):
+    parallel_operation(containers, 'unpause', options, 'Unpausing')
+
+
+def parallel_kill(containers, options):
+    parallel_operation(containers, 'kill', options, 'Killing')
+
+
+def parallel_restart(containers, options):
+    parallel_operation(containers, 'restart', options, 'Restarting')

http://git-wip-us.apache.org/repos/asf/incubator-senssoft-tap/blob/1ca22406/env2/lib/python2.7/site-packages/compose/progress_stream.py
----------------------------------------------------------------------
diff --git a/env2/lib/python2.7/site-packages/compose/progress_stream.py b/env2/lib/python2.7/site-packages/compose/progress_stream.py
new file mode 100644
index 0000000..a0f5601
--- /dev/null
+++ b/env2/lib/python2.7/site-packages/compose/progress_stream.py
@@ -0,0 +1,112 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+from compose import utils
+
+
+class StreamOutputError(Exception):
+    pass
+
+
+def stream_output(output, stream):
+    is_terminal = hasattr(stream, 'isatty') and stream.isatty()
+    stream = utils.get_output_stream(stream)
+    all_events = []
+    lines = {}
+    diff = 0
+
+    for event in utils.json_stream(output):
+        all_events.append(event)
+        is_progress_event = 'progress' in event or 'progressDetail' in event
+
+        if not is_progress_event:
+            print_output_event(event, stream, is_terminal)
+            stream.flush()
+            continue
+
+        if not is_terminal:
+            continue
+
+        # if it's a progress event and we have a terminal, then display the progress bars
+        image_id = event.get('id')
+        if not image_id:
+            continue
+
+        if image_id in lines:
+            diff = len(lines) - lines[image_id]
+        else:
+            lines[image_id] = len(lines)
+            stream.write("\n")
+            diff = 0
+
+        # move cursor up `diff` rows
+        stream.write("%c[%dA" % (27, diff))
+
+        print_output_event(event, stream, is_terminal)
+
+        if 'id' in event:
+            # move cursor back down
+            stream.write("%c[%dB" % (27, diff))
+
+        stream.flush()
+
+    return all_events
+
+
+def print_output_event(event, stream, is_terminal):
+    if 'errorDetail' in event:
+        raise StreamOutputError(event['errorDetail']['message'])
+
+    terminator = ''
+
+    if is_terminal and 'stream' not in event:
+        # erase current line
+        stream.write("%c[2K\r" % 27)
+        terminator = "\r"
+    elif 'progressDetail' in event:
+        return
+
+    if 'time' in event:
+        stream.write("[%s] " % event['time'])
+
+    if 'id' in event:
+        stream.write("%s: " % event['id'])
+
+    if 'from' in event:
+        stream.write("(from %s) " % event['from'])
+
+    status = event.get('status', '')
+
+    if 'progress' in event:
+        stream.write("%s %s%s" % (status, event['progress'], terminator))
+    elif 'progressDetail' in event:
+        detail = event['progressDetail']
+        total = detail.get('total')
+        if 'current' in detail and total:
+            percentage = float(detail['current']) / float(total) * 100
+            stream.write('%s (%.1f%%)%s' % (status, percentage, terminator))
+        else:
+            stream.write('%s%s' % (status, terminator))
+    elif 'stream' in event:
+        stream.write("%s%s" % (event['stream'], terminator))
+    else:
+        stream.write("%s%s\n" % (status, terminator))
+
+
+def get_digest_from_pull(events):
+    for event in events:
+        status = event.get('status')
+        if not status or 'Digest' not in status:
+            continue
+
+        _, digest = status.split(':', 1)
+        return digest.strip()
+    return None
+
+
+def get_digest_from_push(events):
+    for event in events:
+        digest = event.get('aux', {}).get('Digest')
+        if digest:
+            return digest
+    return None