90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
![]() |
#!/usr/bin/python2 -O
|
||
|
|
||
|
import collections
|
||
|
import functools
|
||
|
import sys
|
||
|
|
||
|
import dateutil.parser
|
||
|
|
||
|
import qubes.plugins
|
||
|
|
||
|
class property(object):
|
||
|
def __init__(self, name, default=None, type=None, order=0, doc=None):
|
||
|
self.__name__ = name
|
||
|
self._default = default
|
||
|
self._type = type
|
||
|
self.order = order
|
||
|
self.__doc__ = doc
|
||
|
|
||
|
self._attr_name = '_qubesprop_' + self.__name__
|
||
|
|
||
|
def __get__(self, instance, owner):
|
||
|
if instance is None:
|
||
|
return self
|
||
|
|
||
|
try:
|
||
|
return getattr(instance, self._attr_name)
|
||
|
|
||
|
except AttributeError:
|
||
|
if self._default is None:
|
||
|
raise AttributeError('property not set')
|
||
|
else:
|
||
|
return self._default
|
||
|
|
||
|
def __set__(self, instance, value):
|
||
|
setattr(instance, self._attr_name,
|
||
|
(self._type(value) if self._type is not None else value))
|
||
|
|
||
|
def __repr__(self):
|
||
|
return '<{} object at {:#x} name={!r} default={!r}>'.format(
|
||
|
self.__class__.__name__, id(self), self.__name__, self._default)
|
||
|
|
||
|
def __hash__(self):
|
||
|
return hash(self.__name__)
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
return self.__name__ == other.__name__
|
||
|
|
||
|
class VMPlugin(qubes.plugins.Plugin):
|
||
|
def __init__(cls, name, bases, dict_):
|
||
|
super(VMPlugin, cls).__init__(name, bases, dict_)
|
||
|
cls.__hooks__ = collections.defaultdict(list)
|
||
|
|
||
|
class BaseVM(object):
|
||
|
__metaclass__ = VMPlugin
|
||
|
|
||
|
def get_props_list(self):
|
||
|
props = set()
|
||
|
for class_ in self.__class__.__mro__:
|
||
|
props.update(prop for prop in class_.__dict__.values()
|
||
|
if isinstance(prop, property))
|
||
|
return sorted(props, key=lambda prop: (prop.order, prop.__name__))
|
||
|
|
||
|
def __init__(self, D):
|
||
|
for prop in self.get_props_list():
|
||
|
if prop.__name__ in D:
|
||
|
setattr(self, prop.__name__, D[prop.__name__])
|
||
|
|
||
|
def __repr__(self):
|
||
|
return '<{} object at {:#x} {}>'.format(
|
||
|
self.__class__.__name__, id(self),
|
||
|
' '.join('{}={}'.format(prop.__name__, getattr(self, prop.__name__))
|
||
|
for prop in self.get_props_list()))
|
||
|
|
||
|
@classmethod
|
||
|
def add_hook(cls, event, f):
|
||
|
cls.__hooks__[event].append(f)
|
||
|
|
||
|
def fire_hooks(self, event, *args, **kwargs):
|
||
|
for cls in self.__class__.__mro__:
|
||
|
if not hasattr(cls, '__hooks__'): continue
|
||
|
for hook in cls.__hooks__[event]:
|
||
|
hook(self, *args, **kwargs)
|
||
|
|
||
|
|
||
|
def load(class_, D):
|
||
|
cls = BaseVM[class_]
|
||
|
return cls(D)
|
||
|
|
||
|
__all__ = qubes.plugins.load(__file__)
|