python/mozbuild/mozpack/chrome/flags.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial