python/mozbuild/mozpack/chrome/flags.py

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import re
michael@0 6 from distutils.version import LooseVersion
michael@0 7 from mozpack.errors import errors
michael@0 8 from collections import OrderedDict
michael@0 9
michael@0 10
michael@0 11 class Flag(object):
michael@0 12 '''
michael@0 13 Class for flags in manifest entries in the form:
michael@0 14 "flag" (same as "flag=true")
michael@0 15 "flag=yes|true|1"
michael@0 16 "flag=no|false|0"
michael@0 17 '''
michael@0 18 def __init__(self, name):
michael@0 19 '''
michael@0 20 Initialize a Flag with the given name.
michael@0 21 '''
michael@0 22 self.name = name
michael@0 23 self.value = None
michael@0 24
michael@0 25 def add_definition(self, definition):
michael@0 26 '''
michael@0 27 Add a flag value definition. Replaces any previously set value.
michael@0 28 '''
michael@0 29 if definition == self.name:
michael@0 30 self.value = True
michael@0 31 return
michael@0 32 assert(definition.startswith(self.name))
michael@0 33 if definition[len(self.name)] != '=':
michael@0 34 return errors.fatal('Malformed flag: %s' % definition)
michael@0 35 value = definition[len(self.name) + 1:]
michael@0 36 if value in ('yes', 'true', '1', 'no', 'false', '0'):
michael@0 37 self.value = value
michael@0 38 else:
michael@0 39 return errors.fatal('Unknown value in: %s' % definition)
michael@0 40
michael@0 41 def matches(self, value):
michael@0 42 '''
michael@0 43 Return whether the flag value matches the given value. The values
michael@0 44 are canonicalized for comparison.
michael@0 45 '''
michael@0 46 if value in ('yes', 'true', '1', True):
michael@0 47 return self.value in ('yes', 'true', '1', True)
michael@0 48 if value in ('no', 'false', '0', False):
michael@0 49 return self.value in ('no', 'false', '0', False, None)
michael@0 50 raise RuntimeError('Invalid value: %s' % value)
michael@0 51
michael@0 52 def __str__(self):
michael@0 53 '''
michael@0 54 Serialize the flag value in the same form given to the last
michael@0 55 add_definition() call.
michael@0 56 '''
michael@0 57 if self.value is None:
michael@0 58 return ''
michael@0 59 if self.value is True:
michael@0 60 return self.name
michael@0 61 return '%s=%s' % (self.name, self.value)
michael@0 62
michael@0 63
michael@0 64 class StringFlag(object):
michael@0 65 '''
michael@0 66 Class for string flags in manifest entries in the form:
michael@0 67 "flag=string"
michael@0 68 "flag!=string"
michael@0 69 '''
michael@0 70 def __init__(self, name):
michael@0 71 '''
michael@0 72 Initialize a StringFlag with the given name.
michael@0 73 '''
michael@0 74 self.name = name
michael@0 75 self.values = []
michael@0 76
michael@0 77 def add_definition(self, definition):
michael@0 78 '''
michael@0 79 Add a string flag definition.
michael@0 80 '''
michael@0 81 assert(definition.startswith(self.name))
michael@0 82 value = definition[len(self.name):]
michael@0 83 if value.startswith('='):
michael@0 84 self.values.append(('==', value[1:]))
michael@0 85 elif value.startswith('!='):
michael@0 86 self.values.append(('!=', value[2:]))
michael@0 87 else:
michael@0 88 return errors.fatal('Malformed flag: %s' % definition)
michael@0 89
michael@0 90 def matches(self, value):
michael@0 91 '''
michael@0 92 Return whether one of the string flag definitions matches the given
michael@0 93 value.
michael@0 94 For example,
michael@0 95 flag = StringFlag('foo')
michael@0 96 flag.add_definition('foo!=bar')
michael@0 97 flag.matches('bar') returns False
michael@0 98 flag.matches('qux') returns True
michael@0 99 flag = StringFlag('foo')
michael@0 100 flag.add_definition('foo=bar')
michael@0 101 flag.add_definition('foo=baz')
michael@0 102 flag.matches('bar') returns True
michael@0 103 flag.matches('baz') returns True
michael@0 104 flag.matches('qux') returns False
michael@0 105 '''
michael@0 106 if not self.values:
michael@0 107 return True
michael@0 108 for comparison, val in self.values:
michael@0 109 if eval('value %s val' % comparison):
michael@0 110 return True
michael@0 111 return False
michael@0 112
michael@0 113 def __str__(self):
michael@0 114 '''
michael@0 115 Serialize the flag definitions in the same form given to each
michael@0 116 add_definition() call.
michael@0 117 '''
michael@0 118 res = []
michael@0 119 for comparison, val in self.values:
michael@0 120 if comparison == '==':
michael@0 121 res.append('%s=%s' % (self.name, val))
michael@0 122 else:
michael@0 123 res.append('%s!=%s' % (self.name, val))
michael@0 124 return ' '.join(res)
michael@0 125
michael@0 126
michael@0 127 class VersionFlag(object):
michael@0 128 '''
michael@0 129 Class for version flags in manifest entries in the form:
michael@0 130 "flag=version"
michael@0 131 "flag<=version"
michael@0 132 "flag<version"
michael@0 133 "flag>=version"
michael@0 134 "flag>version"
michael@0 135 '''
michael@0 136 def __init__(self, name):
michael@0 137 '''
michael@0 138 Initialize a VersionFlag with the given name.
michael@0 139 '''
michael@0 140 self.name = name
michael@0 141 self.values = []
michael@0 142
michael@0 143 def add_definition(self, definition):
michael@0 144 '''
michael@0 145 Add a version flag definition.
michael@0 146 '''
michael@0 147 assert(definition.startswith(self.name))
michael@0 148 value = definition[len(self.name):]
michael@0 149 if value.startswith('='):
michael@0 150 self.values.append(('==', LooseVersion(value[1:])))
michael@0 151 elif len(value) > 1 and value[0] in ['<', '>']:
michael@0 152 if value[1] == '=':
michael@0 153 if len(value) < 3:
michael@0 154 return errors.fatal('Malformed flag: %s' % definition)
michael@0 155 self.values.append((value[0:2], LooseVersion(value[2:])))
michael@0 156 else:
michael@0 157 self.values.append((value[0], LooseVersion(value[1:])))
michael@0 158 else:
michael@0 159 return errors.fatal('Malformed flag: %s' % definition)
michael@0 160
michael@0 161 def matches(self, value):
michael@0 162 '''
michael@0 163 Return whether one of the version flag definitions matches the given
michael@0 164 value.
michael@0 165 For example,
michael@0 166 flag = VersionFlag('foo')
michael@0 167 flag.add_definition('foo>=1.0')
michael@0 168 flag.matches('1.0') returns True
michael@0 169 flag.matches('1.1') returns True
michael@0 170 flag.matches('0.9') returns False
michael@0 171 flag = VersionFlag('foo')
michael@0 172 flag.add_definition('foo>=1.0')
michael@0 173 flag.add_definition('foo<0.5')
michael@0 174 flag.matches('0.4') returns True
michael@0 175 flag.matches('1.0') returns True
michael@0 176 flag.matches('0.6') returns False
michael@0 177 '''
michael@0 178 value = LooseVersion(value)
michael@0 179 if not self.values:
michael@0 180 return True
michael@0 181 for comparison, val in self.values:
michael@0 182 if eval('value %s val' % comparison):
michael@0 183 return True
michael@0 184 return False
michael@0 185
michael@0 186 def __str__(self):
michael@0 187 '''
michael@0 188 Serialize the flag definitions in the same form given to each
michael@0 189 add_definition() call.
michael@0 190 '''
michael@0 191 res = []
michael@0 192 for comparison, val in self.values:
michael@0 193 if comparison == '==':
michael@0 194 res.append('%s=%s' % (self.name, val))
michael@0 195 else:
michael@0 196 res.append('%s%s%s' % (self.name, comparison, val))
michael@0 197 return ' '.join(res)
michael@0 198
michael@0 199
michael@0 200 class Flags(OrderedDict):
michael@0 201 '''
michael@0 202 Class to handle a set of flags definitions given on a single manifest
michael@0 203 entry.
michael@0 204 '''
michael@0 205 FLAGS = {
michael@0 206 'application': StringFlag,
michael@0 207 'appversion': VersionFlag,
michael@0 208 'platformversion': VersionFlag,
michael@0 209 'contentaccessible': Flag,
michael@0 210 'os': StringFlag,
michael@0 211 'osversion': VersionFlag,
michael@0 212 'abi': StringFlag,
michael@0 213 'platform': Flag,
michael@0 214 'xpcnativewrappers': Flag,
michael@0 215 'tablet': Flag,
michael@0 216 }
michael@0 217 RE = re.compile(r'([!<>=]+)')
michael@0 218
michael@0 219 def __init__(self, *flags):
michael@0 220 '''
michael@0 221 Initialize a set of flags given in string form.
michael@0 222 flags = Flags('contentaccessible=yes', 'appversion>=3.5')
michael@0 223 '''
michael@0 224 OrderedDict.__init__(self)
michael@0 225 for f in flags:
michael@0 226 name = self.RE.split(f)
michael@0 227 name = name[0]
michael@0 228 if not name in self.FLAGS:
michael@0 229 errors.fatal('Unknown flag: %s' % name)
michael@0 230 continue
michael@0 231 if not name in self:
michael@0 232 self[name] = self.FLAGS[name](name)
michael@0 233 self[name].add_definition(f)
michael@0 234
michael@0 235 def __str__(self):
michael@0 236 '''
michael@0 237 Serialize the set of flags.
michael@0 238 '''
michael@0 239 return ' '.join(str(self[k]) for k in self)
michael@0 240
michael@0 241 def match(self, **filter):
michael@0 242 '''
michael@0 243 Return whether the set of flags match the set of given filters.
michael@0 244 flags = Flags('contentaccessible=yes', 'appversion>=3.5',
michael@0 245 'application=foo')
michael@0 246 flags.match(application='foo') returns True
michael@0 247 flags.match(application='foo', appversion='3.5') returns True
michael@0 248 flags.match(application='foo', appversion='3.0') returns False
michael@0 249 '''
michael@0 250 for name, value in filter.iteritems():
michael@0 251 if not name in self:
michael@0 252 continue
michael@0 253 if not self[name].matches(value):
michael@0 254 return False
michael@0 255 return True

mercurial