00001 """\
00002 @file compatibility.py
00003 @brief Classes that manage compatibility states.
00004
00005 $LicenseInfo:firstyear=2007&license=mit$
00006
00007 Copyright (c) 2007-2008, Linden Research, Inc.
00008
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 $/LicenseInfo$
00027 """
00028
00029
00030 """Compatibility combination table:
00031
00032 I M O N S
00033 -- -- -- -- --
00034 I: I I I I I
00035 M: I M M M M
00036 O: I M O M O
00037 N: I M M N N
00038 S: I M O N S
00039
00040 """
00041
00042 class _Compatibility(object):
00043 def __init__(self, reason):
00044 self.reasons = [ ]
00045 if reason:
00046 self.reasons.append(reason)
00047
00048 def combine(self, other):
00049 if self._level() <= other._level():
00050 return self._buildclone(other)
00051 else:
00052 return other._buildclone(self)
00053
00054 def prefix(self, leadin):
00055 self.reasons = [ leadin + r for r in self.reasons ]
00056
00057 def same(self): return self._level() >= 1
00058 def deployable(self): return self._level() > 0
00059 def resolved(self): return self._level() > -1
00060 def compatible(self): return self._level() > -2
00061
00062 def explain(self):
00063 return self.__class__.__name__ + "\n" + "\n".join(self.reasons) + "\n"
00064
00065 def _buildclone(self, other=None):
00066 c = self._buildinstance()
00067 c.reasons = self.reasons
00068 if other:
00069 c.reasons = c.reasons + other.reasons
00070 return c
00071
00072 def _buildinstance(self):
00073 return self.__class__(None)
00074
00075
00076
00077
00078
00079 class Incompatible(_Compatibility):
00080 def _level(self):
00081 return -2
00082
00083 class Mixed(_Compatibility):
00084 def __init__(self, *inputs):
00085 _Compatibility.__init__(self, None)
00086 for i in inputs:
00087 self.reasons += i.reasons
00088
00089 def _buildinstance(self):
00090 return self.__class__()
00091
00092 def _level(self):
00093 return -1
00094
00095 class _Aged(_Compatibility):
00096 def combine(self, other):
00097 if self._level() == other._level():
00098 return self._buildclone(other)
00099 if int(self._level()) == int(other._level()):
00100 return Mixed(self, other)
00101 return _Compatibility.combine(self, other)
00102
00103 class Older(_Aged):
00104 def _level(self):
00105 return -0.25
00106
00107 class Newer(_Aged):
00108 def _level(self):
00109 return 0.25
00110
00111 class Same(_Compatibility):
00112 def __init__(self):
00113 _Compatibility.__init__(self, None)
00114
00115 def _buildinstance(self):
00116 return self.__class__()
00117
00118 def _level(self):
00119 return 1
00120
00121
00122
00123