<commit_before># Copyright (c) 2016 Cisco Systems, Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import eventlet.queue
from oslo_config import cfg
from oslo_log import log as logging
import requests
import threading

from neutron.common import constants as n_const
from neutron import context as n_context
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.common import constants as p_constants
from neutron.plugins.ml2 import driver_api as api
from neutron_lib import constants as nl_const

LOG = logging.getLogger(__name__)

vpp_opts = [
    cfg.StrOpt('agents',
               help=_("HTTP URLs of agents on compute nodes.")),
]

cfg.CONF.register_opts(vpp_opts, "ml2_vpp")

class VPPMechanismDriver(api.MechanismDriver):
    supported_vnic_types = [portbindings.VNIC_NORMAL]
    allowed_network_types = [p_constants.TYPE_VLAN,p_constants.TYPE_VXLAN]
    MECH_NAME = 'vpp'

    # TODO(ijw): we have no agent registration because we're not using
    # Neutron style agents, so at the moment we make up one physical net
    # that all 'agents' are assumed to know.
    physical_networks = ['physnet']

    def initialize(self):
        self.communicator = AgentCommunicator()

    def bind_port(self, port_context):
        """Attempt to bind a port.

        :param port_context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        port_context.segments_to_bind property, based on the value of the
        port_context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, port_context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        port_context.segments_to_bind, it must call port_context.set_binding
        with the binding details. If it can partially bind the port,
        it must call port_context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """
        LOG.debug("ML2_VPP: Attempting to bind port %(port)s on "
                  "network %(network)s",
                  {'port': port_context.current['id'],
                   'network': port_context.network.current['id']})
        vnic_type = port_context.current.get(portbindings.VNIC_TYPE,
                                             portbindings.VNIC_NORMAL)
        if vnic_type not in self.supported_vnic_types:
            LOG.debug("ML2_VPP: Refusing to bind due to unsupported vnic_type: %s",
                      vnic_type)
            return

        for segment in port_context.segments_to_bind:
            if self.check_segment(segment, port_context.host):
                vif_details = dict(self.vif_details)
                # TODO(ijw) should be in a library that the agent uses
                vif_details['vhostuser_socket'] = \
                    '/tmp/%s' % port_context.current['id']
                vif_details['vhostuser_mode'] = \
                    'client'
                LOG.debug('ML2_VPP: Setting details: %s', vif_details)
                port_context.set_binding(segment[api.ID],
                                         self.vif_type,
                                         vif_details)
                LOG.debug("ML2_VPP: Bound using segment: %s", segment)
                return

    # TODO(ijw) should be pulled from a constants file
    vif_type = 'vhostuser'
    vif_details = {}

    def check_segment(self, segment, host):
        """Check if segment can be bound.

        :param segment: segment dictionary describing segment to bind
        :param host: host on which the segment must be bound to a port
        :returns: True iff segment can be bound for host

        """

        # TODO(ijw): naive - doesn't check host, or configured
        # physnets on the host.  Should work out if the binding
        # can't be achieved before accepting it

        network_type = segment[api.NETWORK_TYPE]
        if network_type not in self.allowed_network_types:
            LOG.debug(
                'ML2_VPP: Network %(network_id)s is %(network_type)s, but this driver '
                'only supports types %(allowed_network_types)s.  The type '
                'must be supported  if binding is to succeed.',
                {'network_id': segment['id'],
                 'network_type': network_type,
                 'allowed_network_types':
                 ', '.join(self.allowed_network_types)}
            )
            return False

        if network_type in [p_constants.TYPE_FLAT, p_constants.TYPE_VLAN]:
            physnet = segment[api.PHYSICAL_NETWORK]
            if not self.physnet_known(physnet):
                LOG.debug(
                    'ML2_VPP: Network %(network_id)s is connected to physical '
                    'network %(physnet)s, but the physical network '
                    'is not one this mechdriver knows.  The physical network '
                    'must be known if binding is to succeed.',
                    {'network_id': segment['id'],
                     'physnet': physnet}
                )
                return False

        return True

    def physnet_known(self, physnet):
        return physnet in self.physical_networks

    def check_vlan_transparency(self, port_context):
        """Check if the network supports vlan transparency.

        :param port_context: NetworkContext instance describing the network.

        In general we do not support VLAN transparency (yet).
        """
        return False

    def update_port_postcommit(self, port_context):
        """Work to do, post-DB commit, when updating a port

        After accepting an update_port, determine if we have any work to do
        on the network devices.
        """
        # TODO(ijw): optimisation: the update port may leave the
        # binding state the same as before if someone updated
        # something other than the binding on the port, but this
        # way we always send it out and it's the far end's job to
        # ignore it.  Doing less work is nevertheless good, so we
        # should in future avoid the send.

        LOG.debug('ML2_VPP: update_port_postcommit, port is %s' % str(port_context.current))

        if port_context.binding_levels is not None:
            current_bind = port_context.binding_levels[-1]
            if port_context.original_binding_levels is None:
                prev_bind = None
            else:
                prev_bind = port_context.original_binding_levels[-1]

            # We have to explicitly avoid binding agent ports - DHCP,
            # L3 etc. - as vhostuser. The interface code below takes
            # care of those.

            bind_type = 'vhostuser'

            owner = port_context.current['device_owner']

            for f in nl_const.DEVICE_OWNER_PREFIXES:
                if owner.startswith(f):
                    bind_type = 'plugtap'

            if (current_bind is not None and
               current_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # then send the bind out (may equally be an update on a bound
                # port)
                LOG.debug("ML2-VPP: Sending bind request to agent communicator for port %(port)s"
                          "segment %(segment)s, host %(host)s, type %(bind_type)s",
                          {
                          'port': port_context.current,
                          'segment': current_bind[api.BOUND_SEGMENT],
                          'host': port_context.host,
                          'bind_type': bind_type
                          }
                         )
                self.communicator.bind(port_context.current,
                                       current_bind[api.BOUND_SEGMENT],
                                       port_context.host,
                                       bind_type)
            elif (prev_bind is not None and
                  prev_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # If we were the last binder of this port but are no longer
                LOG.debug("ML2_VPP: Sending unbind request to agent communicator for port %(port)s"
                          "on host %(host)s",
                          {
                          'port': port_context.current,
                          'host': port_context.original_host,
                          }
                         )
                self.communicator.unbind(port_context.current,
                                         port_context.original_host)

class AgentCommunicator(object):
    def __init__(self):
        if cfg.CONF.ml2_vpp.agents is None:
            LOG.error('ML2_VPP: needs agents configured right now')
        self.agents = cfg.CONF.ml2_vpp.agents.split(',')
        LOG.debug("ML2_VPP: Configured agents are: %s " % str(self.agents))
        self.recursive = False
        self.queue = eventlet.queue.Queue()
        self.sync_thread = threading.Thread(
            name='vpp-sync',
            target=self._worker)
        self.sync_thread.start()

    def _worker(self):
        while True:
            msg = self.queue.get()
            op = msg[0]
            args = msg[1:]
            if op == 'bind':
                self.send_bind(*args)
            elif op == 'unbind':
                self.send_unbind(*args)
            else:
                LOG.error('ML2_VPP: unknown queue op %s' % str(op))

    def bind(self, port, segment, host, type):
        """Queue up a bind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """
        # TODO(ijw): should queue the bind, not send it
        LOG.debug("ML2_VPP: Queing bind request for port:%(port)s, segment:%(segment)s"
                  "on host:%(host)s, type:%(type)s",
                  {
                  'port': port, 'segment': segment,
                  'host': host, 'type': type
                  } )
        self.queue.put(['bind', port, segment, host, type])
        #self.send_bind(port, segment, host, type)

    def unbind(self, port, host):
        """Queue up an unbind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """
        # TODO(ijw): should queue the unbind, not send it
        LOG.debug("ML2_VPP: Queing unbind request for port:%(port)s,"
                  "on host:%(host)s,",
                  {
                  'port': port,
                  'host': host
                  } )
        self.queue.put(['unbind', port, host])
        #self.send_unbind(port, host)

    def send_bind(self, port, segment, host, type):
        data = {
            'host': host,
            'mac_address': port['mac_address'],
            'mtu': 1500,  # not this, but what?: port['mtu'],
            'network_type': segment[api.NETWORK_TYPE],
            'segmentation_id': segment[api.SEGMENTATION_ID],
            'binding_type': type
        }
        self._broadcast_msg('ports/%s/bind' % port['id'], data)

        # This should only be sent when we're certain that the port
        # is bound If this is in a bg thread, it should be sent there,
        # and it should only go when we have confirmed that the far end
        # has done its work.  The VM will start when it's called and
        # will wait until then.  For us this is useful beyond the usual
        # reasons of deplying the VM start until DHCP can be reached,
        # because we know the server socket is in place for the port.

        context = n_context.get_admin_context()
        plugin = manager.NeutronManager.get_plugin()
        # Bodge
        if self.recursive:
            LOG.warning('ML2_VPP: Your recursion check hit on activating port')
        else:
            self.recursive = True
            plugin.update_port_status(context, port['id'],
                                      n_const.PORT_STATUS_ACTIVE,
                                      host=host)
            self.recursive = False

    def send_unbind(self, port, host):
        data = {}
        self._broadcast_msg('ports/%s/unbind/%s' % (port['id'], host),
                            data)

    def _broadcast_msg(self, urlfrag, msg):
        # TODO(ijw): since we pretty much always know the host to which the
        # port is being bound or unbound, there's absolutely no reason
        # to broadcast this, but right now this saves us config work.
        # In a small cloud with not too many ports the workload on the
        # agents is not onerous.
        for url in self.agents:
            LOG.debug("ML2_VPP: Sending message: %s to agent: %s" % (msg, url + urlfrag))
            requests.put(url + urlfrag, data=msg)
<commit_msg>update agent list in devstack settings<commit_after># Copyright (c) 2016 Cisco Systems, Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import eventlet.queue
from oslo_config import cfg
from oslo_log import log as logging
import requests
import threading

from neutron.common import constants as n_const
from neutron import context as n_context
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.common import constants as p_constants
from neutron.plugins.ml2 import driver_api as api
from neutron_lib import constants as nl_const

LOG = logging.getLogger(__name__)

vpp_opts = [
    cfg.StrOpt('agents',
               help=_("HTTP URLs of agents on compute nodes.")),
]

cfg.CONF.register_opts(vpp_opts, "ml2_vpp")

class VPPMechanismDriver(api.MechanismDriver):
    supported_vnic_types = [portbindings.VNIC_NORMAL]
    allowed_network_types = [p_constants.TYPE_VLAN,p_constants.TYPE_VXLAN]
    MECH_NAME = 'vpp'

    # TODO(ijw): we have no agent registration because we're not using
    # Neutron style agents, so at the moment we make up one physical net
    # that all 'agents' are assumed to know.
    physical_networks = ['physnet']

    def initialize(self):
        self.communicator = AgentCommunicator()

    def bind_port(self, port_context):
        """Attempt to bind a port.

        :param port_context: PortContext instance describing the port

        This method is called outside any transaction to attempt to
        establish a port binding using this mechanism driver. Bindings
        may be created at each of multiple levels of a hierarchical
        network, and are established from the top level downward. At
        each level, the mechanism driver determines whether it can
        bind to any of the network segments in the
        port_context.segments_to_bind property, based on the value of the
        port_context.host property, any relevant port or network
        attributes, and its own knowledge of the network topology. At
        the top level, port_context.segments_to_bind contains the static
        segments of the port's network. At each lower level of
        binding, it contains static or dynamic segments supplied by
        the driver that bound at the level above. If the driver is
        able to complete the binding of the port to any segment in
        port_context.segments_to_bind, it must call port_context.set_binding
        with the binding details. If it can partially bind the port,
        it must call port_context.continue_binding with the network
        segments to be used to bind at the next lower level.

        If the binding results are committed after bind_port returns,
        they will be seen by all mechanism drivers as
        update_port_precommit and update_port_postcommit calls. But if
        some other thread or process concurrently binds or updates the
        port, these binding results will not be committed, and
        update_port_precommit and update_port_postcommit will not be
        called on the mechanism drivers with these results. Because
        binding results can be discarded rather than committed,
        drivers should avoid making persistent state changes in
        bind_port, or else must ensure that such state changes are
        eventually cleaned up.

        Implementing this method explicitly declares the mechanism
        driver as having the intention to bind ports. This is inspected
        by the QoS service to identify the available QoS rules you
        can use with ports.
        """
        LOG.debug("ML2_VPP: Attempting to bind port %(port)s on "
                  "network %(network)s",
                  {'port': port_context.current['id'],
                   'network': port_context.network.current['id']})
        vnic_type = port_context.current.get(portbindings.VNIC_TYPE,
                                             portbindings.VNIC_NORMAL)
        if vnic_type not in self.supported_vnic_types:
            LOG.debug("ML2_VPP: Refusing to bind due to unsupported vnic_type: %s",
                      vnic_type)
            return

        for segment in port_context.segments_to_bind:
            if self.check_segment(segment, port_context.host):
                vif_details = dict(self.vif_details)
                # TODO(ijw) should be in a library that the agent uses
                vif_details['vhostuser_socket'] = \
                    '/tmp/%s' % port_context.current['id']
                vif_details['vhostuser_mode'] = \
                    'client'
                LOG.debug('ML2_VPP: Setting details: %s', vif_details)
                port_context.set_binding(segment[api.ID],
                                         self.vif_type,
                                         vif_details)
                LOG.debug("ML2_VPP: Bound using segment: %s", segment)
                return

    # TODO(ijw) should be pulled from a constants file
    vif_type = 'vhostuser'
    vif_details = {}

    def check_segment(self, segment, host):
        """Check if segment can be bound.

        :param segment: segment dictionary describing segment to bind
        :param host: host on which the segment must be bound to a port
        :returns: True iff segment can be bound for host

        """

        # TODO(ijw): naive - doesn't check host, or configured
        # physnets on the host.  Should work out if the binding
        # can't be achieved before accepting it

        network_type = segment[api.NETWORK_TYPE]
        if network_type not in self.allowed_network_types:
            LOG.debug(
                'ML2_VPP: Network %(network_id)s is %(network_type)s, but this driver '
                'only supports types %(allowed_network_types)s.  The type '
                'must be supported  if binding is to succeed.',
                {'network_id': segment['id'],
                 'network_type': network_type,
                 'allowed_network_types':
                 ', '.join(self.allowed_network_types)}
            )
            return False

        if network_type in [p_constants.TYPE_FLAT, p_constants.TYPE_VLAN]:
            physnet = segment[api.PHYSICAL_NETWORK]
            if not self.physnet_known(physnet):
                LOG.debug(
                    'ML2_VPP: Network %(network_id)s is connected to physical '
                    'network %(physnet)s, but the physical network '
                    'is not one this mechdriver knows.  The physical network '
                    'must be known if binding is to succeed.',
                    {'network_id': segment['id'],
                     'physnet': physnet}
                )
                return False

        return True

    def physnet_known(self, physnet):
        return physnet in self.physical_networks

    def check_vlan_transparency(self, port_context):
        """Check if the network supports vlan transparency.

        :param port_context: NetworkContext instance describing the network.

        In general we do not support VLAN transparency (yet).
        """
        return False

    def update_port_postcommit(self, port_context):
        """Work to do, post-DB commit, when updating a port

        After accepting an update_port, determine if we have any work to do
        on the network devices.
        """
        # TODO(ijw): optimisation: the update port may leave the
        # binding state the same as before if someone updated
        # something other than the binding on the port, but this
        # way we always send it out and it's the far end's job to
        # ignore it.  Doing less work is nevertheless good, so we
        # should in future avoid the send.

        LOG.debug('ML2_VPP: update_port_postcommit, port is %s' % str(port_context.current))

        if port_context.binding_levels is not None:
            current_bind = port_context.binding_levels[-1]
            if port_context.original_binding_levels is None:
                prev_bind = None
            else:
                prev_bind = port_context.original_binding_levels[-1]

            # We have to explicitly avoid binding agent ports - DHCP,
            # L3 etc. - as vhostuser. The interface code below takes
            # care of those.

            bind_type = 'vhostuser'

            owner = port_context.current['device_owner']

            for f in nl_const.DEVICE_OWNER_PREFIXES:
                if owner.startswith(f):
                    bind_type = 'plugtap'

            if (current_bind is not None and
               current_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # then send the bind out (may equally be an update on a bound
                # port)
                LOG.debug("ML2-VPP: Sending bind request to agent communicator for port %(port)s"
                          "segment %(segment)s, host %(host)s, type %(bind_type)s",
                          {
                          'port': port_context.current,
                          'segment': current_bind[api.BOUND_SEGMENT],
                          'host': port_context.host,
                          'bind_type': bind_type
                          }
                         )
                self.communicator.bind(port_context.current,
                                       current_bind[api.BOUND_SEGMENT],
                                       port_context.host,
                                       bind_type)
            elif (prev_bind is not None and
                  prev_bind.get(api.BOUND_DRIVER) == self.MECH_NAME):
                # If we were the last binder of this port but are no longer
                LOG.debug("ML2_VPP: Sending unbind request to agent communicator for port %(port)s"
                          "on host %(host)s",
                          {
                          'port': port_context.current,
                          'host': port_context.original_host,
                          }
                         )
                self.communicator.unbind(port_context.current,
                                         port_context.original_host)

class AgentCommunicator(object):
    def __init__(self):
        if cfg.CONF.ml2_vpp.agents is None:
            LOG.error('ML2_VPP: needs agents configured right now')
        self.agents = cfg.CONF.ml2_vpp.agents.split(',')
        LOG.debug("ML2_VPP: Configured agents are: %s " % str(self.agents))
        self.recursive = False
        self.queue = eventlet.queue.Queue()
        self.sync_thread = threading.Thread(
            name='vpp-sync',
            target=self._worker)
        self.sync_thread.start()

    def _worker(self):
        while True:
            msg = self.queue.get()
            op = msg[0]
            args = msg[1:]
            if op == 'bind':
                self.send_bind(*args)
            elif op == 'unbind':
                self.send_unbind(*args)
            else:
                LOG.error('ML2_VPP: unknown queue op %s' % str(op))

    def bind(self, port, segment, host, type):
        """Queue up a bind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """
        # TODO(ijw): should queue the bind, not send it
        LOG.debug("ML2_VPP: Queing bind request for port:%(port)s, segment:%(segment)s"
                  "on host:%(host)s, type:%(type)s",
                  {
                  'port': port, 'segment': segment,
                  'host': host, 'type': type
                  } )
        self.queue.put(['bind', port, segment, host, type])
        #self.send_bind(port, segment, host, type)

    def unbind(self, port, host):
        """Queue up an unbind message for sending.

        This is called in the sequence of a REST call and should take
        as little time as possible.
        """
        # TODO(ijw): should queue the unbind, not send it
        LOG.debug("ML2_VPP: Queing unbind request for port:%(port)s,"
                  "on host:%(host)s,",
                  {
                  'port': port,
                  'host': host
                  } )
        self.queue.put(['unbind', port, host])
        #self.send_unbind(port, host)

    def send_bind(self, port, segment, host, type):
        data = {
            'host': host,
            'mac_address': port['mac_address'],
            'mtu': 1500,  # not this, but what?: port['mtu'],
            'network_type': segment[api.NETWORK_TYPE],
            'segmentation_id': segment[api.SEGMENTATION_ID],
            'binding_type': type
        }
        self._unicast_msg('ports/%s/bind' % port['id'], data)

        # This should only be sent when we're certain that the port
        # is bound If this is in a bg thread, it should be sent there,
        # and it should only go when we have confirmed that the far end
        # has done its work.  The VM will start when it's called and
        # will wait until then.  For us this is useful beyond the usual
        # reasons of deplying the VM start until DHCP can be reached,
        # because we know the server socket is in place for the port.

        context = n_context.get_admin_context()
        plugin = manager.NeutronManager.get_plugin()
        # Bodge
        if self.recursive:
            LOG.warning('ML2_VPP: Your recursion check hit on activating port')
        else:
            self.recursive = True
            plugin.update_port_status(context, port['id'],
                                      n_const.PORT_STATUS_ACTIVE,
                                      host=host)
            self.recursive = False

    def send_unbind(self, port, host):
        data = {}
        self._unicast_msg('ports/%s/unbind/%s' % (port['id'], host),
                            data)

    def _unicast_msg(self, urlfrag, msg):
        # Send unicast message to the agent on the host
        for url in self.agents:
            LOG.debug("ML2_VPP: Sending message: %s to agent: %s" % (msg, url + urlfrag))
            requests.put(url + urlfrag, data=msg)
<|endoftext|>


<commit_before>"""
Computes minimum spanning tree of a weighted graph.

"""
#    Copyright (C) 2009-2010 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.

__all__ = ['mst', 'kruskal_mst',
           'minimum_spanning_edges',
           'minimum_spanning_tree']

import networkx as nx

def minimum_spanning_edges(G):
    """Generate edges in a minimum spanning forest of an undirected
    weighted graph.

    A minimum spanning tree is a subgraph of the graph (a tree)
    with the minimum sum of edge weights.  A spanning forest is a
    union of the spanning trees for each connected component of the graph.

    Parameters
    ----------
    G : NetworkX Graph

    Returns
    -------
    edges : iterator
       A generator that produces edges in the minimum spanning tree.
       The edges are three-tuples (u,v,w) where w is the weight.

    Examples
    --------
    >>> G=nx.cycle_graph(4)
    >>> G.add_edge(0,3,weight=2) # assign weight 2 to edge 0-3
    >>> mst=nx.minimum_spanning_edges(G) # a generator of MST edges
    >>> edgelist=list(mst) # make a list of the edges
    >>> print(sorted(edgelist))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]
    >>> T=nx.Graph(edgelist)  # build a graph of the MST.
    >>> print(sorted(T.edges(data=True)))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]

    Notes
    -----
    Uses Kruskal's algorithm.

    If the graph edges do not have a weight attribute a default weight of 1
    will be assigned.

    Modified code from David Eppstein, April 2006
    http://www.ics.uci.edu/~eppstein/PADS/
    """
    # Modified code from David Eppstein, April 2006
    # http://www.ics.uci.edu/~eppstein/PADS/
    # Kruskal's algorithm: sort edges by weight, and add them one at a time.
    # We use Kruskal's algorithm, first because it is very simple to
    # implement once UnionFind exists, and second, because the only slow
    # part (the sort) is sped up by being built in to Python.
    from networkx.utils import UnionFind

    if G.is_directed():
        raise NetworkXError(\
            "Mimimum spanning tree not defined for directed graphs.")

    subtrees = UnionFind()
    edges = sorted((G[u][v].get('weight',1),u,v) for u in G for v in G[u])
    for W,u,v in edges:
        if subtrees[u] != subtrees[v]:
            yield (u,v,{'weight':W})
            subtrees.union(u,v)

def minimum_spanning_tree(G):
    """Return a minimum spanning tree or forest of an undirected
    weighted graph.

    A minimum spanning tree is a subgraph of the graph (a tree) with
    the minimum sum of edge weights.

    If the graph is not connected a spanning forest is constructed.  A
    spanning forest is a union of the spanning trees for each
    connected component of the graph.

    Parameters
    ----------
    G : NetworkX Graph

    Returns
    -------
    G : NetworkX Graph
       A minimum spanning tree or forest.

    Examples
    --------
    >>> G=nx.cycle_graph(4)
    >>> G.add_edge(0,3,weight=2) # assign weight 2 to edge 0-3
    >>> T=minimum_spanning_tree(G)
    >>> print(sorted(T.edges(data=True)))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]

    Notes
    -----
    Uses Kruskal's algorithm.

    If the graph edges do not have a weight attribute a default weight of 1
    will be assigned.
    """
    T=nx.Graph(nx.minimum_spanning_edges(G))
    # Add isolated nodes
    if len(T)!=len(G):
        T.add_nodes_from([n for n,d in G.degree().items() if d==0])
    return T

kruskal_mst=minimum_spanning_tree
mst=minimum_spanning_tree

<commit_msg>Add nx prefix to doctests<commit_after>"""
Computes minimum spanning tree of a weighted graph.

"""
#    Copyright (C) 2009-2010 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.

__all__ = ['mst', 'kruskal_mst',
           'minimum_spanning_edges',
           'minimum_spanning_tree']

import networkx as nx

def minimum_spanning_edges(G):
    """Generate edges in a minimum spanning forest of an undirected
    weighted graph.

    A minimum spanning tree is a subgraph of the graph (a tree)
    with the minimum sum of edge weights.  A spanning forest is a
    union of the spanning trees for each connected component of the graph.

    Parameters
    ----------
    G : NetworkX Graph

    Returns
    -------
    edges : iterator
       A generator that produces edges in the minimum spanning tree.
       The edges are three-tuples (u,v,w) where w is the weight.

    Examples
    --------
    >>> G=nx.cycle_graph(4)
    >>> G.add_edge(0,3,weight=2) # assign weight 2 to edge 0-3
    >>> mst=nx.minimum_spanning_edges(G) # a generator of MST edges
    >>> edgelist=list(mst) # make a list of the edges
    >>> print(sorted(edgelist))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]
    >>> T=nx.Graph(edgelist)  # build a graph of the MST.
    >>> print(sorted(T.edges(data=True)))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]

    Notes
    -----
    Uses Kruskal's algorithm.

    If the graph edges do not have a weight attribute a default weight of 1
    will be assigned.

    Modified code from David Eppstein, April 2006
    http://www.ics.uci.edu/~eppstein/PADS/
    """
    # Modified code from David Eppstein, April 2006
    # http://www.ics.uci.edu/~eppstein/PADS/
    # Kruskal's algorithm: sort edges by weight, and add them one at a time.
    # We use Kruskal's algorithm, first because it is very simple to
    # implement once UnionFind exists, and second, because the only slow
    # part (the sort) is sped up by being built in to Python.
    from networkx.utils import UnionFind

    if G.is_directed():
        raise NetworkXError(\
            "Mimimum spanning tree not defined for directed graphs.")

    subtrees = UnionFind()
    edges = sorted((G[u][v].get('weight',1),u,v) for u in G for v in G[u])
    for W,u,v in edges:
        if subtrees[u] != subtrees[v]:
            yield (u,v,{'weight':W})
            subtrees.union(u,v)

def minimum_spanning_tree(G):
    """Return a minimum spanning tree or forest of an undirected
    weighted graph.

    A minimum spanning tree is a subgraph of the graph (a tree) with
    the minimum sum of edge weights.

    If the graph is not connected a spanning forest is constructed.  A
    spanning forest is a union of the spanning trees for each
    connected component of the graph.

    Parameters
    ----------
    G : NetworkX Graph

    Returns
    -------
    G : NetworkX Graph
       A minimum spanning tree or forest.

    Examples
    --------
    >>> G=nx.cycle_graph(4)
    >>> G.add_edge(0,3,weight=2) # assign weight 2 to edge 0-3
    >>> T=nx.minimum_spanning_tree(G)
    >>> print(sorted(T.edges(data=True)))
    [(0, 1, {'weight': 1}), (1, 2, {'weight': 1}), (2, 3, {'weight': 1})]

    Notes
    -----
    Uses Kruskal's algorithm.

    If the graph edges do not have a weight attribute a default weight of 1
    will be assigned.
    """
    T=nx.Graph(nx.minimum_spanning_edges(G))
    # Add isolated nodes
    if len(T)!=len(G):
        T.add_nodes_from([n for n,d in G.degree().items() if d==0])
    return T

kruskal_mst=minimum_spanning_tree
mst=minimum_spanning_tree

<|endoftext|>


<commit_before>from __future__ import absolute_import

import requests
import sys

from cStringIO import StringIO

from mapproxy.util.py import reraise_exception
from mapproxy.util.ext.wmsparse.parse import parse_capabilities as parse_wms_capabilities
from mapproxy.grid import tile_grid

from . import csv
from .wmtsparse import parse_capabilities as parse_wmts_capabilities, WMTSCapabilities
from .exceptions import CapabilitiesError, UserError, FeatureError, ServiceError
from .utils import is_supported_srs

webmercator_grid = tile_grid(3857, origin='nw')

def parsed_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wmts_capabilities(cap_doc)
    except Exception as ex:
        try:
            cap_doc.seek(0)
            cap = parse_wms_capabilities(cap_doc)
        except Exception as ex:
            reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def parsed_wmts_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wmts_capabilities(cap_doc)
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def parsed_wms_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wms_capabilities(cap_doc)
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def request_capabilities(cap_url):
    try:
        response = requests.get(cap_url)
    except requests.exceptions.RequestException as ex:
        reraise_exception(CapabilitiesError('Opening given capabilities url failed.', ex.args[0]), sys.exc_info())
    if not response.ok:
        raise CapabilitiesError('Opening given capabilities url failed.', 'response.ok False')

    return StringIO(response.content)

def cap_dict(cap_url):
    cap = parsed_capabilities(cap_url)
    if isinstance(cap, WMTSCapabilities):
        return wmts_cap_dict(cap)
    return wms_cap_dict(cap)

def wmts_cap_dict(cap):
    cap_layers = cap.layers.items()

    layers = []
    for layer_name, layer in cap_layers:
        layer_obj = {
            'name': layer_name,
            'title': layer['title'],
            'matrix_sets': [matrix_set['id'] for matrix_set in layer['matrix_sets']],
            'llbbox': layer['bbox'],
        }
        dimension = wmts_layer_dimensions(layer)
        if dimension:
            layer_obj['dimensions'] = dimension
        if 'url_template' in layer:
            layer_obj['url_template'] = layer['url_template']
        layers.append(layer_obj)
    return {
        'type': 'wmts',
        'title': cap.service['title'],
        'layers': layers,
    }

def wmts_layer_resourceURL(layer):
    pass

def wmts_layer_dimensions(layer):
    dimensions = {}
    for dim in layer['dimensions']:
        dimensions[dim['id']] = {
            'value': dim['value'],
            'default': dim['default'],
        }
    return dimensions

def sorted_srs_list(srs):
    """
    "sort" list of SRS. Moves EPSG:3857, EPSG:900913 and EPSG:4326 to the
    front, keeps order of other projections.
    """
    result = list(srs)
    if 'EPSG:4326' in result:
        result.pop(result.index('EPSG:4326'))
        result.insert(0, 'EPSG:4326')
    if 'EPSG:900913' in result:
        result.pop(result.index('EPSG:900913'))
        result.insert(0, 'EPSG:900913')
    if 'EPSG:3857' in result:
        result.pop(result.index('EPSG:3857'))
        result.insert(0, 'EPSG:3857')
    return result

def wms_cap_dict(cap):
    try:
        cap_layers = cap.layers_list()
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())

    layers = []
    for layer in cap_layers:
        srs = []
        for _srs in sorted_srs_list(layer['srs']):
            # don't add unsupported srs
            if not is_supported_srs(_srs):
                continue
            srs.append(_srs)
        layers.append({
            'name': layer['name'],
            'title': layer['title'],
            'srs': srs,
            'llbbox': layer['llbbox'],
        })
        if layer['res_hint']:
            min_res, max_res = layer['res_hint']
            if min_res is not None:
                layers[-1]['min_level'] = webmercator_grid.closest_level(min_res)
            if max_res is not None:
                layers[-1]['max_level'] = webmercator_grid.closest_level(max_res)

    return {
        'type': 'wms',
        'title': cap.metadata()['title'],
        'layers': layers,
    }

def res_to_zoom(res):
    webmercator_grid.closest_level(res)
    print res

def add_wmts_layer(cap_url, layer_name, matrix_set, csv_config_file, dimensions=None):
    cap = parsed_wmts_capabilities(cap_url)

    if not layer_name in cap.layers.keys():
        raise UserError('Layer "%s" not found in given capabilities document' % layer_name)
    found = False
    for ms in cap.layers[layer_name]['matrix_sets']:
        if ms['id'] == matrix_set:
            found = True
            break

    if not found:
        raise UserError('MatrixSet "%s" not supported by layer "%s"' % (matrix_set, layer_name,))

    try:
        mapproxy_id = csv.to_csv(csv_config_file, 'wmts', cap_url, layer_name, matrix_set, dimensions=dimensions)
    except Exception as ex:
        reraise_exception(ServiceError('Creating layer failed', ex.args[0]), sys.exc_info())

    return mapproxy_id

def add_wms_layer(cap_url, layer_name, srs, csv_config_file):
    cap = parsed_wms_capabilities(cap_url)

    layer = None
    for cap_layer in cap.layers_list():
        if cap_layer['name'] == layer_name:
            layer = cap_layer
            break
    if layer is None:
        raise UserError('Layer "%s" not found in given capabilities document' % layer_name)
    if srs not in layer['srs']:
        raise UserError('SRS "%s" not supported by layer "%s"' % (srs, layer_name,))
    if not is_supported_srs(srs):
        raise FeatureError('Unsupported SRS "%s"' % srs)

    try:
        mapproxy_id = csv.to_csv(csv_config_file, 'wms', cap_url, layer_name, srs)
    except Exception as ex:
        reraise_exception(ServiceError('Creating layer failed', ex.args[0]), sys.exc_info())

    return mapproxy_id

<commit_msg>removed unnused code<commit_after>from __future__ import absolute_import

import requests
import sys

from cStringIO import StringIO

from mapproxy.util.py import reraise_exception
from mapproxy.util.ext.wmsparse.parse import parse_capabilities as parse_wms_capabilities
from mapproxy.grid import tile_grid

from . import csv
from .wmtsparse import parse_capabilities as parse_wmts_capabilities, WMTSCapabilities
from .exceptions import CapabilitiesError, UserError, FeatureError, ServiceError
from .utils import is_supported_srs

webmercator_grid = tile_grid(3857, origin='nw')

def parsed_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wmts_capabilities(cap_doc)
    except Exception as ex:
        try:
            cap_doc.seek(0)
            cap = parse_wms_capabilities(cap_doc)
        except Exception as ex:
            reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def parsed_wmts_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wmts_capabilities(cap_doc)
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def parsed_wms_capabilities(cap_url):
    cap_doc = request_capabilities(cap_url)
    try:
        cap = parse_wms_capabilities(cap_doc)
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())
    return cap

def request_capabilities(cap_url):
    try:
        response = requests.get(cap_url)
    except requests.exceptions.RequestException as ex:
        reraise_exception(CapabilitiesError('Opening given capabilities url failed.', ex.args[0]), sys.exc_info())
    if not response.ok:
        raise CapabilitiesError('Opening given capabilities url failed.', 'response.ok False')

    return StringIO(response.content)

def cap_dict(cap_url):
    cap = parsed_capabilities(cap_url)
    if isinstance(cap, WMTSCapabilities):
        return wmts_cap_dict(cap)
    return wms_cap_dict(cap)

def wmts_cap_dict(cap):
    cap_layers = cap.layers.items()

    layers = []
    for layer_name, layer in cap_layers:
        layer_obj = {
            'name': layer_name,
            'title': layer['title'],
            'matrix_sets': [matrix_set['id'] for matrix_set in layer['matrix_sets']],
            'llbbox': layer['bbox'],
        }
        dimension = wmts_layer_dimensions(layer)
        if dimension:
            layer_obj['dimensions'] = dimension
        if 'url_template' in layer:
            layer_obj['url_template'] = layer['url_template']
        layers.append(layer_obj)
    return {
        'type': 'wmts',
        'title': cap.service['title'],
        'layers': layers,
    }

def wmts_layer_dimensions(layer):
    dimensions = {}
    for dim in layer['dimensions']:
        dimensions[dim['id']] = {
            'value': dim['value'],
            'default': dim['default'],
        }
    return dimensions

def sorted_srs_list(srs):
    """
    "sort" list of SRS. Moves EPSG:3857, EPSG:900913 and EPSG:4326 to the
    front, keeps order of other projections.
    """
    result = list(srs)
    if 'EPSG:4326' in result:
        result.pop(result.index('EPSG:4326'))
        result.insert(0, 'EPSG:4326')
    if 'EPSG:900913' in result:
        result.pop(result.index('EPSG:900913'))
        result.insert(0, 'EPSG:900913')
    if 'EPSG:3857' in result:
        result.pop(result.index('EPSG:3857'))
        result.insert(0, 'EPSG:3857')
    return result

def wms_cap_dict(cap):
    try:
        cap_layers = cap.layers_list()
    except Exception as ex:
        reraise_exception(CapabilitiesError('not a valid capabilities document', ex.args[0]), sys.exc_info())

    layers = []
    for layer in cap_layers:
        srs = []
        for _srs in sorted_srs_list(layer['srs']):
            # don't add unsupported srs
            if not is_supported_srs(_srs):
                continue
            srs.append(_srs)
        layers.append({
            'name': layer['name'],
            'title': layer['title'],
            'srs': srs,
            'llbbox': layer['llbbox'],
        })
        if layer['res_hint']:
            min_res, max_res = layer['res_hint']
            if min_res is not None:
                layers[-1]['min_level'] = webmercator_grid.closest_level(min_res)
            if max_res is not None:
                layers[-1]['max_level'] = webmercator_grid.closest_level(max_res)

    return {
        'type': 'wms',
        'title': cap.metadata()['title'],
        'layers': layers,
    }

def res_to_zoom(res):
    webmercator_grid.closest_level(res)
    print res

def add_wmts_layer(cap_url, layer_name, matrix_set, csv_config_file, dimensions=None):
    cap = parsed_wmts_capabilities(cap_url)

    if not layer_name in cap.layers.keys():
        raise UserError('Layer "%s" not found in given capabilities document' % layer_name)
    found = False
    for ms in cap.layers[layer_name]['matrix_sets']:
        if ms['id'] == matrix_set:
            found = True
            break

    if not found:
        raise UserError('MatrixSet "%s" not supported by layer "%s"' % (matrix_set, layer_name,))

    try:
        mapproxy_id = csv.to_csv(csv_config_file, 'wmts', cap_url, layer_name, matrix_set, dimensions=dimensions)
    except Exception as ex:
        reraise_exception(ServiceError('Creating layer failed', ex.args[0]), sys.exc_info())

    return mapproxy_id

def add_wms_layer(cap_url, layer_name, srs, csv_config_file):
    cap = parsed_wms_capabilities(cap_url)

    layer = None
    for cap_layer in cap.layers_list():
        if cap_layer['name'] == layer_name:
            layer = cap_layer
            break
    if layer is None:
        raise UserError('Layer "%s" not found in given capabilities document' % layer_name)
    if srs not in layer['srs']:
        raise UserError('SRS "%s" not supported by layer "%s"' % (srs, layer_name,))
    if not is_supported_srs(srs):
        raise FeatureError('Unsupported SRS "%s"' % srs)

    try:
        mapproxy_id = csv.to_csv(csv_config_file, 'wms', cap_url, layer_name, srs)
    except Exception as ex:
        reraise_exception(ServiceError('Creating layer failed', ex.args[0]), sys.exc_info())

    return mapproxy_id

<|endoftext|>


<commit_before>"""Easy install Tests
"""
import sys
import os
import shutil
import tempfile
import unittest
import site
import textwrap
import tarfile
import urlparse
import StringIO
import distutils.core

from setuptools.command.easy_install import easy_install, get_script_args, main
from setuptools.command.easy_install import  PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server

try:
    # import multiprocessing solely for the purpose of testing its existence
    __import__('multiprocessing')
    import logging
    _LOG = logging.getLogger('test_easy_install')
    logging.basicConfig(level=logging.INFO, stream=sys.stderr)
    _MULTIPROC = True
except ImportError:
    _MULTIPROC = False
    _LOG = None

class FakeDist(object):
    def get_entry_map(self, group):
        if group != 'console_scripts':
            return {}
        return {'name': 'ep'}

    def as_requirement(self):
        return 'spec'

WANTED = """\
#!%s
# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
__requires__ = 'spec'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('spec', 'console_scripts', 'name')()
    )
""" % sys.executable

SETUP_PY = """\
from setuptools import setup

setup(name='foo')
"""

class TestEasyInstallTest(unittest.TestCase):

    def test_install_site_py(self):
        dist = Distribution()
        cmd = easy_install(dist)
        cmd.sitepy_installed = False
        cmd.install_dir = tempfile.mkdtemp()
        try:
            cmd.install_site_py()
            sitepy = os.path.join(cmd.install_dir, 'site.py')
            self.assert_(os.path.exists(sitepy))
        finally:
            shutil.rmtree(cmd.install_dir)

    def test_get_script_args(self):
        dist = FakeDist()

        old_platform = sys.platform
        try:
            name, script = [i for i in get_script_args(dist).next()][0:2]
        finally:
            sys.platform = old_platform

        self.assertEquals(script, WANTED)

    def test_no_setup_cfg(self):
        # makes sure easy_install as a command (main)
        # doesn't use a setup.cfg file that is located
        # in the current working directory
        dir = tempfile.mkdtemp()
        setup_cfg = open(os.path.join(dir, 'setup.cfg'), 'w')
        setup_cfg.write('[easy_install]\nfind_links = http://example.com')
        setup_cfg.close()
        setup_py = open(os.path.join(dir, 'setup.py'), 'w')
        setup_py.write(SETUP_PY)
        setup_py.close()

        from setuptools.dist import Distribution

        def _parse_command_line(self):
            msg = 'Error: a local setup.cfg was used'
            opts = self.command_options
            if 'easy_install' in opts:
                assert 'find_links' not in opts['easy_install'], msg
            return self._old_parse_command_line()

        Distribution._old_parse_command_line = Distribution.parse_command_line
        Distribution.parse_command_line = _parse_command_line

        old_wd = os.getcwd()
        try:
            os.chdir(dir)
            main([])
        finally:
            os.chdir(old_wd)
            shutil.rmtree(dir)
            Distribution.parse_command_line = Distribution._old_parse_command_line

    def test_no_find_links(self):
        # new option '--no-find-links', that blocks find-links added at
        # the project level
        dist = Distribution()
        cmd = easy_install(dist)
        cmd.check_pth_processing = lambda: True
        cmd.no_find_links = True
        cmd.find_links = ['link1', 'link2']
        cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
        cmd.args = ['ok']
        cmd.ensure_finalized()
        self.assertEquals(cmd.package_index.scanned_urls, {})

        # let's try without it (default behavior)
        cmd = easy_install(dist)
        cmd.check_pth_processing = lambda: True
        cmd.find_links = ['link1', 'link2']
        cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
        cmd.args = ['ok']
        cmd.ensure_finalized()
        keys = cmd.package_index.scanned_urls.keys()
        keys.sort()
        self.assertEquals(keys, ['link1', 'link2'])

class TestPTHFileWriter(unittest.TestCase):
    def test_add_from_cwd_site_sets_dirty(self):
        '''a pth file manager should set dirty
        if a distribution is in site but also the cwd
        '''
        pth = PthDistributions('does-not_exist', [os.getcwd()])
        self.assert_(not pth.dirty)
        pth.add(PRDistribution(os.getcwd()))
        self.assert_(pth.dirty)

    def test_add_from_site_is_ignored(self):
        if os.name != 'nt':
            location = '/test/location/does-not-have-to-exist'
        else:
            location = 'c:\\does_not_exist'
        pth = PthDistributions('does-not_exist', [location, ])
        self.assert_(not pth.dirty)
        pth.add(PRDistribution(location))
        self.assert_(not pth.dirty)

class TestUserInstallTest(unittest.TestCase):

    def setUp(self):
        self.dir = tempfile.mkdtemp()
        setup = os.path.join(self.dir, 'setup.py')
        f = open(setup, 'w')
        f.write(SETUP_PY)
        f.close()
        self.old_cwd = os.getcwd()
        os.chdir(self.dir)
        if sys.version >= "2.6":
            self.old_has_site = easy_install_pkg.HAS_USER_SITE
            self.old_file = easy_install_pkg.__file__
            self.old_base = site.USER_BASE
            site.USER_BASE = tempfile.mkdtemp()
            self.old_site = site.USER_SITE
            site.USER_SITE = tempfile.mkdtemp()
            easy_install_pkg.__file__ = site.USER_SITE

    def tearDown(self):
        os.chdir(self.old_cwd)
        shutil.rmtree(self.dir)
        if sys.version >= "2.6":
            shutil.rmtree(site.USER_BASE)
            shutil.rmtree(site.USER_SITE)
            site.USER_BASE = self.old_base
            site.USER_SITE = self.old_site
            easy_install_pkg.HAS_USER_SITE = self.old_has_site
            easy_install_pkg.__file__ = self.old_file

    def test_user_install_implied(self):
        easy_install_pkg.HAS_USER_SITE = True # disabled sometimes
        #XXX: replace with something meaningfull
        if sys.version < "2.6":
            return #SKIP
        dist = Distribution()
        dist.script_name = 'setup.py'
        cmd = easy_install(dist)
        cmd.args = ['py']
        cmd.ensure_finalized()
        self.assertTrue(cmd.user, 'user should be implied')

    def test_multiproc_atexit(self):
        if not _MULTIPROC:
            return
        _LOG.info('this should not break')

    def test_user_install_not_implied_without_usersite_enabled(self):
        easy_install_pkg.HAS_USER_SITE = False # usually enabled
        #XXX: replace with something meaningfull
        if sys.version < "2.6":
            return #SKIP
        dist = Distribution()
        dist.script_name = 'setup.py'
        cmd = easy_install(dist)
        cmd.args = ['py']
        cmd.initialize_options()
        self.assertFalse(cmd.user, 'NOT user should be implied')

    def test_local_index(self):
        # make sure the local index is used
        # when easy_install looks for installed
        # packages
        new_location = tempfile.mkdtemp()
        target = tempfile.mkdtemp()
        egg_file = os.path.join(new_location, 'foo-1.0.egg-info')
        f = open(egg_file, 'w')
        try:
            f.write('Name: foo\n')
        except:
            f.close()

        sys.path.append(target)
        old_ppath = os.environ.get('PYTHONPATH')
        os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
        try:
            dist = Distribution()
            dist.script_name = 'setup.py'
            cmd = easy_install(dist)
            cmd.install_dir = target
            cmd.args = ['foo']
            cmd.ensure_finalized()
            cmd.local_index.scan([new_location])
            res = cmd.easy_install('foo')
            self.assertEquals(res.location, new_location)
        finally:
            sys.path.remove(target)
            for basedir in [new_location, target, ]:
                if not os.path.exists(basedir) or not os.path.isdir(basedir):
                    continue
                try:
                    shutil.rmtree(basedir)
                except:
                    pass
            if old_ppath is not None:
                os.environ['PYTHONPATH'] = old_ppath
            else:
                del os.environ['PYTHONPATH']

class TestSetupRequires(unittest.TestCase):

    def test_setup_requires_honors_fetch_params(self):
        """
        When easy_install installs a source distribution which specifies
        setup_requires, it should honor the fetch parameters (such as
        allow-hosts, index-url, and find-links).
        """
        # set up a server which will simulate an alternate package index.
        p_index = setuptools.tests.server.MockServer()
        p_index.start()
        netloc = 1
        p_index_loc = urlparse.urlparse(p_index.url)[netloc]

        # I realize this is all-but-impossible to read, because it was
        #  ported from some well-factored, safe code using 'with'. If you
        #  need to maintain this code, consider making the changes in
        #  the parent revision (of this comment) and then port the changes
        #  back for Python 2.4 (or deprecate Python 2.4).

        def install(dist_file):
            def install_at(temp_install_dir):
                def install_env():
                    ei_params = ['--index-url', p_index.url,
                        '--allow-hosts', p_index_loc,
                        '--exclude-scripts', '--install-dir', temp_install_dir,
                        dist_file]
                    def install_clean_reset():
                        def install_clean_argv():
                            # attempt to install the dist. It should fail because
                            #  it doesn't exist.
                            self.assertRaises(SystemExit,
                                easy_install_pkg.main, ei_params)
                        argv_context(install_clean_argv, ['easy_install'])
                    reset_setup_stop_context(install_clean_reset)
                environment_context(install_env, PYTHONPATH=temp_install_dir)
            tempdir_context(install_at)

        # create an sdist that has a build-time dependency.
        self.create_sdist(install)

        self.assertEqual(len(p_index.requests), 2)
        self.assertEqual(p_index.requests[0].path, '/does-not-exist/')

    def create_sdist(self, installer):
        """
        Create an sdist with a setup_requires dependency (of something that
        doesn't exist) and invoke installer on it.
        """
        def build_sdist(dir):
            setup_py = tarfile.TarInfo(name="setup.py")
            setup_py_bytes = StringIO.StringIO(textwrap.dedent("""
                import setuptools
                setuptools.setup(
                    name="distribute-test-fetcher",
                    version="1.0",
                    setup_requires = ['does-not-exist'],
                )
                """).lstrip())
            setup_py.size = len(setup_py_bytes.getvalue())
            dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz')
            dist = tarfile.open(dist_path, 'w:gz')
            try:
                dist.addfile(setup_py, fileobj=setup_py_bytes)
            finally:
                dist.close()
            installer(dist_path)
        tempdir_context(build_sdist)

def tempdir_context(f, cd=lambda dir:None):
    """
    Invoke f in the context
    """
    temp_dir = tempfile.mkdtemp()
    orig_dir = os.getcwd()
    try:
        cd(temp_dir)
        f(temp_dir)
    finally:
        cd(orig_dir)
        shutil.rmtree(temp_dir)

def environment_context(f, **updates):
    """
    Invoke f in the context
    """
    old_env = os.environ.copy()
    os.environ.update(updates)
    try:
        f()
    finally:
        for key in updates:
            del os.environ[key]
        os.environ.update(old_env)

def argv_context(f, repl):
    """
    Invoke f in the context
    """
    old_argv = sys.argv[:]
    sys.argv[:] = repl
    try:
        f()
    finally:
        sys.argv[:] = old_argv

def reset_setup_stop_context(f):
    """
    When the distribute tests are run using setup.py test, and then
    one wants to invoke another setup() command (such as easy_install)
    within those tests, it's necessary to reset the global variable
    in distutils.core so that the setup() command will run naturally.
    """
    setup_stop_after = distutils.core._setup_stop_after
    distutils.core._setup_stop_after = None
    try:
        f()
    finally:
        distutils.core._setup_stop_after = setup_stop_after
<commit_msg>Ensure that the setup.py is generated as bytes on Python 2 and 3 so that the tarfile module will accept it.<commit_after>"""Easy install Tests
"""
import sys
import os
import shutil
import tempfile
import unittest
import site
import textwrap
import tarfile
import urlparse
import StringIO
import distutils.core

from setuptools.command.easy_install import easy_install, get_script_args, main
from setuptools.command.easy_install import  PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server

try:
    # import multiprocessing solely for the purpose of testing its existence
    __import__('multiprocessing')
    import logging
    _LOG = logging.getLogger('test_easy_install')
    logging.basicConfig(level=logging.INFO, stream=sys.stderr)
    _MULTIPROC = True
except ImportError:
    _MULTIPROC = False
    _LOG = None

class FakeDist(object):
    def get_entry_map(self, group):
        if group != 'console_scripts':
            return {}
        return {'name': 'ep'}

    def as_requirement(self):
        return 'spec'

WANTED = """\
#!%s
# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
__requires__ = 'spec'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('spec', 'console_scripts', 'name')()
    )
""" % sys.executable

SETUP_PY = """\
from setuptools import setup

setup(name='foo')
"""

class TestEasyInstallTest(unittest.TestCase):

    def test_install_site_py(self):
        dist = Distribution()
        cmd = easy_install(dist)
        cmd.sitepy_installed = False
        cmd.install_dir = tempfile.mkdtemp()
        try:
            cmd.install_site_py()
            sitepy = os.path.join(cmd.install_dir, 'site.py')
            self.assert_(os.path.exists(sitepy))
        finally:
            shutil.rmtree(cmd.install_dir)

    def test_get_script_args(self):
        dist = FakeDist()

        old_platform = sys.platform
        try:
            name, script = [i for i in get_script_args(dist).next()][0:2]
        finally:
            sys.platform = old_platform

        self.assertEquals(script, WANTED)

    def test_no_setup_cfg(self):
        # makes sure easy_install as a command (main)
        # doesn't use a setup.cfg file that is located
        # in the current working directory
        dir = tempfile.mkdtemp()
        setup_cfg = open(os.path.join(dir, 'setup.cfg'), 'w')
        setup_cfg.write('[easy_install]\nfind_links = http://example.com')
        setup_cfg.close()
        setup_py = open(os.path.join(dir, 'setup.py'), 'w')
        setup_py.write(SETUP_PY)
        setup_py.close()

        from setuptools.dist import Distribution

        def _parse_command_line(self):
            msg = 'Error: a local setup.cfg was used'
            opts = self.command_options
            if 'easy_install' in opts:
                assert 'find_links' not in opts['easy_install'], msg
            return self._old_parse_command_line()

        Distribution._old_parse_command_line = Distribution.parse_command_line
        Distribution.parse_command_line = _parse_command_line

        old_wd = os.getcwd()
        try:
            os.chdir(dir)
            main([])
        finally:
            os.chdir(old_wd)
            shutil.rmtree(dir)
            Distribution.parse_command_line = Distribution._old_parse_command_line

    def test_no_find_links(self):
        # new option '--no-find-links', that blocks find-links added at
        # the project level
        dist = Distribution()
        cmd = easy_install(dist)
        cmd.check_pth_processing = lambda: True
        cmd.no_find_links = True
        cmd.find_links = ['link1', 'link2']
        cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
        cmd.args = ['ok']
        cmd.ensure_finalized()
        self.assertEquals(cmd.package_index.scanned_urls, {})

        # let's try without it (default behavior)
        cmd = easy_install(dist)
        cmd.check_pth_processing = lambda: True
        cmd.find_links = ['link1', 'link2']
        cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
        cmd.args = ['ok']
        cmd.ensure_finalized()
        keys = cmd.package_index.scanned_urls.keys()
        keys.sort()
        self.assertEquals(keys, ['link1', 'link2'])

class TestPTHFileWriter(unittest.TestCase):
    def test_add_from_cwd_site_sets_dirty(self):
        '''a pth file manager should set dirty
        if a distribution is in site but also the cwd
        '''
        pth = PthDistributions('does-not_exist', [os.getcwd()])
        self.assert_(not pth.dirty)
        pth.add(PRDistribution(os.getcwd()))
        self.assert_(pth.dirty)

    def test_add_from_site_is_ignored(self):
        if os.name != 'nt':
            location = '/test/location/does-not-have-to-exist'
        else:
            location = 'c:\\does_not_exist'
        pth = PthDistributions('does-not_exist', [location, ])
        self.assert_(not pth.dirty)
        pth.add(PRDistribution(location))
        self.assert_(not pth.dirty)

class TestUserInstallTest(unittest.TestCase):

    def setUp(self):
        self.dir = tempfile.mkdtemp()
        setup = os.path.join(self.dir, 'setup.py')
        f = open(setup, 'w')
        f.write(SETUP_PY)
        f.close()
        self.old_cwd = os.getcwd()
        os.chdir(self.dir)
        if sys.version >= "2.6":
            self.old_has_site = easy_install_pkg.HAS_USER_SITE
            self.old_file = easy_install_pkg.__file__
            self.old_base = site.USER_BASE
            site.USER_BASE = tempfile.mkdtemp()
            self.old_site = site.USER_SITE
            site.USER_SITE = tempfile.mkdtemp()
            easy_install_pkg.__file__ = site.USER_SITE

    def tearDown(self):
        os.chdir(self.old_cwd)
        shutil.rmtree(self.dir)
        if sys.version >= "2.6":
            shutil.rmtree(site.USER_BASE)
            shutil.rmtree(site.USER_SITE)
            site.USER_BASE = self.old_base
            site.USER_SITE = self.old_site
            easy_install_pkg.HAS_USER_SITE = self.old_has_site
            easy_install_pkg.__file__ = self.old_file

    def test_user_install_implied(self):
        easy_install_pkg.HAS_USER_SITE = True # disabled sometimes
        #XXX: replace with something meaningfull
        if sys.version < "2.6":
            return #SKIP
        dist = Distribution()
        dist.script_name = 'setup.py'
        cmd = easy_install(dist)
        cmd.args = ['py']
        cmd.ensure_finalized()
        self.assertTrue(cmd.user, 'user should be implied')

    def test_multiproc_atexit(self):
        if not _MULTIPROC:
            return
        _LOG.info('this should not break')

    def test_user_install_not_implied_without_usersite_enabled(self):
        easy_install_pkg.HAS_USER_SITE = False # usually enabled
        #XXX: replace with something meaningfull
        if sys.version < "2.6":
            return #SKIP
        dist = Distribution()
        dist.script_name = 'setup.py'
        cmd = easy_install(dist)
        cmd.args = ['py']
        cmd.initialize_options()
        self.assertFalse(cmd.user, 'NOT user should be implied')

    def test_local_index(self):
        # make sure the local index is used
        # when easy_install looks for installed
        # packages
        new_location = tempfile.mkdtemp()
        target = tempfile.mkdtemp()
        egg_file = os.path.join(new_location, 'foo-1.0.egg-info')
        f = open(egg_file, 'w')
        try:
            f.write('Name: foo\n')
        except:
            f.close()

        sys.path.append(target)
        old_ppath = os.environ.get('PYTHONPATH')
        os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
        try:
            dist = Distribution()
            dist.script_name = 'setup.py'
            cmd = easy_install(dist)
            cmd.install_dir = target
            cmd.args = ['foo']
            cmd.ensure_finalized()
            cmd.local_index.scan([new_location])
            res = cmd.easy_install('foo')
            self.assertEquals(res.location, new_location)
        finally:
            sys.path.remove(target)
            for basedir in [new_location, target, ]:
                if not os.path.exists(basedir) or not os.path.isdir(basedir):
                    continue
                try:
                    shutil.rmtree(basedir)
                except:
                    pass
            if old_ppath is not None:
                os.environ['PYTHONPATH'] = old_ppath
            else:
                del os.environ['PYTHONPATH']

class TestSetupRequires(unittest.TestCase):

    def test_setup_requires_honors_fetch_params(self):
        """
        When easy_install installs a source distribution which specifies
        setup_requires, it should honor the fetch parameters (such as
        allow-hosts, index-url, and find-links).
        """
        # set up a server which will simulate an alternate package index.
        p_index = setuptools.tests.server.MockServer()
        p_index.start()
        netloc = 1
        p_index_loc = urlparse.urlparse(p_index.url)[netloc]

        # I realize this is all-but-impossible to read, because it was
        #  ported from some well-factored, safe code using 'with'. If you
        #  need to maintain this code, consider making the changes in
        #  the parent revision (of this comment) and then port the changes
        #  back for Python 2.4 (or deprecate Python 2.4).

        def install(dist_file):
            def install_at(temp_install_dir):
                def install_env():
                    ei_params = ['--index-url', p_index.url,
                        '--allow-hosts', p_index_loc,
                        '--exclude-scripts', '--install-dir', temp_install_dir,
                        dist_file]
                    def install_clean_reset():
                        def install_clean_argv():
                            # attempt to install the dist. It should fail because
                            #  it doesn't exist.
                            self.assertRaises(SystemExit,
                                easy_install_pkg.main, ei_params)
                        argv_context(install_clean_argv, ['easy_install'])
                    reset_setup_stop_context(install_clean_reset)
                environment_context(install_env, PYTHONPATH=temp_install_dir)
            tempdir_context(install_at)

        # create an sdist that has a build-time dependency.
        self.create_sdist(install)

        self.assertEqual(len(p_index.requests), 2)
        self.assertEqual(p_index.requests[0].path, '/does-not-exist/')

    def create_sdist(self, installer):
        """
        Create an sdist with a setup_requires dependency (of something that
        doesn't exist) and invoke installer on it.
        """
        def build_sdist(dir):
            setup_py = tarfile.TarInfo(name="setup.py")
            try:
                # Python 3 (StringIO gets converted to io module)
                MemFile = StringIO.BytesIO
            except AttributeError:
                MemFile = StringIO.StringIO
            setup_py_bytes = MemFile(textwrap.dedent("""
                import setuptools
                setuptools.setup(
                    name="distribute-test-fetcher",
                    version="1.0",
                    setup_requires = ['does-not-exist'],
                )
                """).lstrip().encode('utf-8'))
            setup_py.size = len(setup_py_bytes.getvalue())
            dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz')
            dist = tarfile.open(dist_path, 'w:gz')
            try:
                dist.addfile(setup_py, fileobj=setup_py_bytes)
            finally:
                dist.close()
            installer(dist_path)
        tempdir_context(build_sdist)

def tempdir_context(f, cd=lambda dir:None):
    """
    Invoke f in the context
    """
    temp_dir = tempfile.mkdtemp()
    orig_dir = os.getcwd()
    try:
        cd(temp_dir)
        f(temp_dir)
    finally:
        cd(orig_dir)
        shutil.rmtree(temp_dir)

def environment_context(f, **updates):
    """
    Invoke f in the context
    """
    old_env = os.environ.copy()
    os.environ.update(updates)
    try:
        f()
    finally:
        for key in updates:
            del os.environ[key]
        os.environ.update(old_env)

def argv_context(f, repl):
    """
    Invoke f in the context
    """
    old_argv = sys.argv[:]
    sys.argv[:] = repl
    try:
        f()
    finally:
        sys.argv[:] = old_argv

def reset_setup_stop_context(f):
    """
    When the distribute tests are run using setup.py test, and then
    one wants to invoke another setup() command (such as easy_install)
    within those tests, it's necessary to reset the global variable
    in distutils.core so that the setup() command will run naturally.
    """
    setup_stop_after = distutils.core._setup_stop_after
    distutils.core._setup_stop_after = None
    try:
        f()
    finally:
        distutils.core._setup_stop_after = setup_stop_after
<|endoftext|>


<commit_before>#!/usr/bin/python -u

# TODO: what is this script for? why not using cfg/options.cfg ?
# TODO: This script should only contain special settings which are not covered by options.cfg

# The reason this script resides in cfg/ folder is that the OLX file downloader will
# deny access to cfg/ folder, and we have admin password here
# .. Why don't we deny access to everything except levels and mods (by checking if a directory
# has got script.lgs in it). Current way sounds sucky to me.

# TODO: move that to options.cfg
ADMIN_PREFIX = "!" # What kind of prefix you want for admin commands. Example: !?-.@$ A.K.A you can use prettymuch everything.

# Where to log what is happening
LOG_FILE = "dedicated_control.log"
# If you modify dedicated_control Python will write errors here
ERROR_FILE = "dedicated_control_errors.log"

# TODO: use the one from options.cfg as default
# (it's ok if presets change the name, but the default should be the one specified in options.cfg)
#SERVER_NAME = "Dedicated" # The name of your server, can be changed by preset

MIN_PLAYERS = 2
MIN_PLAYERS_TEAMS = 4 # Players will be split in two teams automatically if there is enough players
MAX_TEAMS = 2 # Only blue and red teams
TOO_FEW_PLAYERS_MESSAGE = "Game will start with minimum %i players. Team Deathmatch if there's %i or more players" % (MIN_PLAYERS, MIN_PLAYERS_TEAMS)
WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE = 30 # Seconds to wait before another "Game will start with %i players" message

# Seconds before rotating preset
PRESET_TIMEOUT = 300

WAIT_AFTER_GAME = 10 # Seconds to wait in lobby after round finished
WAIT_BEFORE_GAME = 15 # Seconds to wait in lobby before next round, will give some message
WAIT_BEFORE_GAME_MESSAGE = "Game will start in %i seconds" % WAIT_BEFORE_GAME

# TODO: same thing as for SERVERNAME. it's ok if presets change them but options.cfg should define the default
GAME_LIVES = -2 # -2 = unlimited, can be changed by TeamArena preset
GAME_MAX_KILLS = 15
GAME_MAX_TIME = 7 # In minutes
WEAPON_SELECTION_TIME = 40 # In seconds

# TODO: This is unfair and I don't thing it is such a good idea.
# A user with a high ping doesn't give any disadvantages to other players (or at least that should not be the case and I wonder if it is).
MAX_PING = 800 # Max ping to auto-kick player

# TODO: We should use the OLX chatcommand system.
# TODO: Register dedscript commands in OLX chatcommand system.
# Users can enter some commands too
USER_PREFIX = ADMIN_PREFIX # Change to have custom user command prefix instead of "//"
ALLOW_TEAM_CHANGE = True # Player should type "!b", "!r", "!g", or "!y" to set it's own team
TEAM_CHANGE_MESSAGE = "Set your team with %steam b/r" % USER_PREFIX
if MAX_TEAMS >= 3:
	TEAM_CHANGE_MESSAGE += "/g"
if MAX_TEAMS >= 4:
	TEAM_CHANGE_MESSAGE += "/y"

RANKING = 1 # Should we allow !rank user command
RANKING_AUTHENTICATION = 0 # Should we authenticate worm by it's skin color (pretty weak, but !password cmd is kinda ugly)

VOTING = 1 # Should we allow voting for preset/map/mod/lt/kick/mute
VOTING_PERCENT = 51 # How much users in percent should vote yes for vote to pass
VOTING_TIME = 15 # For how much time we should wait votes from users
VOTING_COUNT_NEGATIVE = 1 # If we should count negative votes, so users can fail unpopular vote before timeout
VOTING_KICK_TIME = 5 # Time in minutes when user kicked by voting cannot re-join server (it auto-kicks user again with message)

# List of levels - preset chooses a random level from those
LEVELS = [	"FossilFacility.lxl",
			"LieroFactory(Revisited).lxl",
			"LieroFactory_Maintenance.lxl",
			"JailBreak.lxl",
			"JukkeDome.lxl",
			"Lake Liero.lxl",
			"Lamda_bunker_(Razvisited).lxl",
			"MsPaintPower.lxl",
			"MsPaintPower2.lxl",
			"Ore Quarry.lxl",
			"Poo Arena.lxl",
			"RIP_Home.lxl",
			"Sunrise_Mansion.lxl",
			"wormmountain.lxl",
			"Alien Hood.lxl",
			"FightBox.lxl",
			"Duel.lxl",
			"Tetrisv2.lxl"
		]

# List of presets to cycle on server - you may specify some preset multiple times, then it will have higher chances of appearing
# If this list is empty all presets are used
PRESETS = [ "Mortars", "MSF_II", "Classic", "Shock", "ModernWarfare" ]

# General options that should be set
GLOBAL_SETTINGS = {

#	"GameOptions.Network.WelcomeMessage":           "<player> from <country> connected",
#	"GameOptions.GameInfo.MaxPlayers":              8,
#	"GameOptions.GameInfo.WeaponSelectionMaxTime":  40,
#	"GameOptions.Network.MaxUploadBandwidth":       40000, # Should be enough for 8-player game, raise this if your network is fast

	# Various options that should be set, you don't need to touch them in most cases

	"GameOptions.GameInfo.ServerSideHealth":        0, # Turn this on if ppl hack and don't die on your server
	"GameOptions.GameInfo.AllowNickChange":         1,
	"GameOptions.GameInfo.AllowStrafing":           1,
	"GameOptions.Network.AllowRemoteBots":          1,
	"GameOptions.Network.AllowWantsJoinMsg":        1,
	"GameOptions.Network.WantsToJoinFromBanned":    0,
	"GameOptions.Network.UseIpToCountry":           1, # Do not change, needed for correct server messages ; TODO: fix that
	"GameOptions.Network.RegisterServer":           1,
	"GameOptions.Network.Speed":                    2, # 2 = LAN, do not change
	"GameOptions.Advanced.MaxFPS":                  95, # Higher values will decrease netlag, also needed if ServerSideHealth = 1,
	"GameOptions.Game.AntilagMovementPrediction":   1, # If ServerSideHealth = 1 this influences gameplay
# TODO: OLX should not do that anyway in dedicated mode. if it does, please fix that in OLX
#	"GameOptions.Game.Blood":                       0, # Ded server does not need any eye candies
#	"GameOptions.Game.Particles":                   0, # Ded server does not need any eye candies
#	"GameOptions.Game.Shadows":                     0, # Ded server does not need any eye candies
	"GameOptions.Misc.LogConversations":            0,
	"GameOptions.Advanced.MatchLogging":            0, # Do not save game results screenshot
	"GameOptions.Misc.ScreenshotFormat":            1, # 0 = JPG, 1 = PNG
	"GameOptions.Network.AutoSetupHttpProxy":       1,
	"GameOptions.Network.EnableChat":               0, # No IRC chat needed for ded server
	"GameOptions.Network.HttpProxy":                "",
}

<commit_msg>better default value for the average noob<commit_after>#!/usr/bin/python -u

# TODO: what is this script for? why not using cfg/options.cfg ?
# TODO: This script should only contain special settings which are not covered by options.cfg

# The reason this script resides in cfg/ folder is that the OLX file downloader will
# deny access to cfg/ folder, and we have admin password here
# .. Why don't we deny access to everything except levels and mods (by checking if a directory
# has got script.lgs in it). Current way sounds sucky to me.

# TODO: move that to options.cfg
ADMIN_PREFIX = "!" # What kind of prefix you want for admin commands. Example: !?-.@$ A.K.A you can use prettymuch everything.

# Where to log what is happening
LOG_FILE = "dedicated_control.log"
# If you modify dedicated_control Python will write errors here
ERROR_FILE = "dedicated_control_errors.log"

# TODO: use the one from options.cfg as default
# (it's ok if presets change the name, but the default should be the one specified in options.cfg)
#SERVER_NAME = "Dedicated" # The name of your server, can be changed by preset

MIN_PLAYERS = 2
MIN_PLAYERS_TEAMS = 4 # Players will be split in two teams automatically if there is enough players
MAX_TEAMS = 2 # Only blue and red teams
TOO_FEW_PLAYERS_MESSAGE = "Game will start with minimum %i players. Team Deathmatch if there's %i or more players" % (MIN_PLAYERS, MIN_PLAYERS_TEAMS)
WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE = 30 # Seconds to wait before another "Game will start with %i players" message

# Seconds before rotating preset
PRESET_TIMEOUT = 300

WAIT_AFTER_GAME = 10 # Seconds to wait in lobby after round finished
WAIT_BEFORE_GAME = 15 # Seconds to wait in lobby before next round, will give some message
WAIT_BEFORE_GAME_MESSAGE = "Game will start in %i seconds" % WAIT_BEFORE_GAME

# TODO: same thing as for SERVERNAME. it's ok if presets change them but options.cfg should define the default
GAME_LIVES = -2 # -2 = unlimited, can be changed by TeamArena preset
GAME_MAX_KILLS = 15
GAME_MAX_TIME = 7 # In minutes
WEAPON_SELECTION_TIME = 40 # In seconds

# TODO: This is unfair and I don't thing it is such a good idea. (At least for the average player, only
# pro-gamers perhaps want that.)
# A user with a high ping doesn't give any disadvantages to other players (or at least that should not be the case and I wonder if it is).
MAX_PING = 30000 # Max ping to auto-kick player

# TODO: We should use the OLX chatcommand system.
# TODO: Register dedscript commands in OLX chatcommand system.
# Users can enter some commands too
USER_PREFIX = ADMIN_PREFIX # Change to have custom user command prefix instead of "//"
ALLOW_TEAM_CHANGE = True # Player should type "!b", "!r", "!g", or "!y" to set it's own team
TEAM_CHANGE_MESSAGE = "Set your team with %steam b/r" % USER_PREFIX
if MAX_TEAMS >= 3:
	TEAM_CHANGE_MESSAGE += "/g"
if MAX_TEAMS >= 4:
	TEAM_CHANGE_MESSAGE += "/y"

RANKING = 1 # Should we allow !rank user command
RANKING_AUTHENTICATION = 0 # Should we authenticate worm by it's skin color (pretty weak, but !password cmd is kinda ugly)

VOTING = 1 # Should we allow voting for preset/map/mod/lt/kick/mute
VOTING_PERCENT = 51 # How much users in percent should vote yes for vote to pass
VOTING_TIME = 15 # For how much time we should wait votes from users
VOTING_COUNT_NEGATIVE = 1 # If we should count negative votes, so users can fail unpopular vote before timeout
VOTING_KICK_TIME = 5 # Time in minutes when user kicked by voting cannot re-join server (it auto-kicks user again with message)

# List of levels - preset chooses a random level from those
LEVELS = [	"FossilFacility.lxl",
			"LieroFactory(Revisited).lxl",
			"LieroFactory_Maintenance.lxl",
			"JailBreak.lxl",
			"JukkeDome.lxl",
			"Lake Liero.lxl",
			"Lamda_bunker_(Razvisited).lxl",
			"MsPaintPower.lxl",
			"MsPaintPower2.lxl",
			"Ore Quarry.lxl",
			"Poo Arena.lxl",
			"RIP_Home.lxl",
			"Sunrise_Mansion.lxl",
			"wormmountain.lxl",
			"Alien Hood.lxl",
			"FightBox.lxl",
			"Duel.lxl",
			"Tetrisv2.lxl"
		]

# List of presets to cycle on server - you may specify some preset multiple times, then it will have higher chances of appearing
# If this list is empty all presets are used
PRESETS = [ "Mortars", "MSF_II", "Classic", "Shock", "ModernWarfare" ]

# General options that should be set
GLOBAL_SETTINGS = {

#	"GameOptions.Network.WelcomeMessage":           "<player> from <country> connected",
#	"GameOptions.GameInfo.MaxPlayers":              8,
#	"GameOptions.GameInfo.WeaponSelectionMaxTime":  40,
#	"GameOptions.Network.MaxUploadBandwidth":       40000, # Should be enough for 8-player game, raise this if your network is fast

	# Various options that should be set, you don't need to touch them in most cases

	"GameOptions.GameInfo.ServerSideHealth":        0, # Turn this on if ppl hack and don't die on your server
	"GameOptions.GameInfo.AllowNickChange":         1,
	"GameOptions.GameInfo.AllowStrafing":           1,
	"GameOptions.Network.AllowRemoteBots":          1,
	"GameOptions.Network.AllowWantsJoinMsg":        1,
	"GameOptions.Network.WantsToJoinFromBanned":    0,
	"GameOptions.Network.UseIpToCountry":           1, # Do not change, needed for correct server messages ; TODO: fix that
	"GameOptions.Network.RegisterServer":           1,
	"GameOptions.Network.Speed":                    2, # 2 = LAN, do not change
	"GameOptions.Advanced.MaxFPS":                  95, # Higher values will decrease netlag, also needed if ServerSideHealth = 1,
	"GameOptions.Game.AntilagMovementPrediction":   1, # If ServerSideHealth = 1 this influences gameplay
# TODO: OLX should not do that anyway in dedicated mode. if it does, please fix that in OLX
#	"GameOptions.Game.Blood":                       0, # Ded server does not need any eye candies
#	"GameOptions.Game.Particles":                   0, # Ded server does not need any eye candies
#	"GameOptions.Game.Shadows":                     0, # Ded server does not need any eye candies
	"GameOptions.Misc.LogConversations":            0,
	"GameOptions.Advanced.MatchLogging":            0, # Do not save game results screenshot
	"GameOptions.Misc.ScreenshotFormat":            1, # 0 = JPG, 1 = PNG
	"GameOptions.Network.AutoSetupHttpProxy":       1,
	"GameOptions.Network.EnableChat":               0, # No IRC chat needed for ded server
	"GameOptions.Network.HttpProxy":                "",
}

<|endoftext|>