2010-03-18 08:32:47 +02:00
|
|
|
# Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
|
2009-10-02 23:57:11 +03:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
"""
|
2010-02-26 12:35:09 +02:00
|
|
|
The backbone of the command system. Provides automatic dispatching which
|
|
|
|
does not require explicit registering commands or containers and remains
|
|
|
|
active even after everything is done, so new commands can be added
|
|
|
|
during the runtime.
|
2009-10-02 23:57:11 +03:00
|
|
|
"""
|
|
|
|
|
|
|
|
from types import NoneType
|
|
|
|
|
|
|
|
class Dispatcher(type):
|
|
|
|
|
|
|
|
containers = {}
|
|
|
|
commands = {}
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def register_host(klass, host):
|
|
|
|
klass.containers[host] = []
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def register_container(klass, container):
|
|
|
|
for host in container.HOSTS:
|
|
|
|
klass.containers[host].append(container)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def register_commands(klass, container):
|
|
|
|
klass.commands[container] = {}
|
|
|
|
for command in klass.traverse_commands(container):
|
|
|
|
for name in command.names:
|
|
|
|
klass.commands[container][name] = command
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_command(klass, host, name):
|
|
|
|
for container in klass.containers[host]:
|
|
|
|
command = klass.commands[container].get(name)
|
|
|
|
if command:
|
|
|
|
return command
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def list_commands(klass, host):
|
|
|
|
for container in klass.containers[host]:
|
|
|
|
commands = klass.commands[container]
|
|
|
|
for name, command in commands.iteritems():
|
|
|
|
yield name, command
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def traverse_commands(klass, container):
|
|
|
|
for name in dir(container):
|
|
|
|
attribute = getattr(container, name)
|
|
|
|
if klass.is_command(attribute):
|
|
|
|
yield attribute
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def is_root(ns):
|
|
|
|
meta = ns.get('__metaclass__', NoneType)
|
|
|
|
return issubclass(meta, Dispatcher)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def is_command(attribute):
|
|
|
|
name = attribute.__class__.__name__
|
|
|
|
return name == 'Command'
|
|
|
|
|
|
|
|
class HostDispatcher(Dispatcher):
|
|
|
|
|
|
|
|
def __init__(klass, name, bases, ns):
|
|
|
|
if not Dispatcher.is_root(ns):
|
|
|
|
HostDispatcher.register_host(klass)
|
|
|
|
super(HostDispatcher, klass).__init__(name, bases, ns)
|
|
|
|
|
|
|
|
class ContainerDispatcher(Dispatcher):
|
|
|
|
|
|
|
|
def __init__(klass, name, bases, ns):
|
|
|
|
if not Dispatcher.is_root(ns):
|
|
|
|
ContainerDispatcher.register_container(klass)
|
|
|
|
ContainerDispatcher.register_commands(klass)
|
|
|
|
super(ContainerDispatcher, klass).__init__(name, bases, ns)
|