def merge(hosts, roles, exclude, roledefs):
    """
    Merge given host and role lists into one list of deduped hosts.
    """
    # Abort if any roles don't exist
    bad_roles = [x for x in roles if x not in roledefs]
    if bad_roles:
        abort("The following specified roles do not exist:\n%s" % (
            indent(bad_roles)
        ))

    # Coerce strings to one-item lists
    if isinstance(hosts, basestring):
        hosts = [hosts]

    # Look up roles, turn into flat list of hosts
    role_hosts = []
    for role in roles:
        value = roledefs[role]
        # Handle dict style roledefs
        if isinstance(value, dict):
            value = value['hosts']
        # Handle "lazy" roles (callables)
        if callable(value):
            value = value()
        role_hosts += value

    # Strip whitespace from host strings.
    cleaned_hosts = [x.strip() for x in list(hosts) + list(role_hosts)]
    # Return deduped combo of hosts and role_hosts, preserving order within
    # them (vs using set(), which may lose ordering) and skipping hosts to be
    # excluded.
    # But only if the user hasn't indicated they want this behavior disabled.
    all_hosts = cleaned_hosts
    if state.env.dedupe_hosts:
        deduped_hosts = []
        for host in cleaned_hosts:
            if host not in deduped_hosts and host not in exclude:
                deduped_hosts.append(host)
        all_hosts = deduped_hosts
    return all_hosts
dataset/ETHPy150Open fabric/fabric/fabric/task_utils.py/merge/original