python/mozbuild/mozpack/chrome/manifest.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

     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 import os
     7 from urlparse import urlparse
     8 import mozpack.path
     9 from mozpack.chrome.flags import Flags
    10 from mozpack.errors import errors
    13 class ManifestEntry(object):
    14     '''
    15     Base class for all manifest entry types.
    16     Subclasses may define the following class or member variables:
    17         - localized: indicates whether the manifest entry is used for localized
    18           data.
    19         - type: the manifest entry type (e.g. 'content' in
    20           'content global content/global/')
    21         - allowed_flags: a set of flags allowed to be defined for the given
    22           manifest entry type.
    24     A manifest entry is attached to a base path, defining where the manifest
    25     entry is bound to, and that is used to find relative paths defined in
    26     entries.
    27     '''
    28     localized = False
    29     type = None
    30     allowed_flags = [
    31         'application',
    32         'platformversion',
    33         'os',
    34         'osversion',
    35         'abi',
    36         'xpcnativewrappers',
    37         'tablet',
    38     ]
    40     def __init__(self, base, *flags):
    41         '''
    42         Initialize a manifest entry with the given base path and flags.
    43         '''
    44         self.base = base
    45         self.flags = Flags(*flags)
    46         if not all(f in self.allowed_flags for f in self.flags):
    47             errors.fatal('%s unsupported for %s manifest entries' %
    48                          (','.join(f for f in self.flags
    49                           if not f in self.allowed_flags), self.type))
    51     def serialize(self, *args):
    52         '''
    53         Serialize the manifest entry.
    54         '''
    55         entry = [self.type] + list(args)
    56         flags = str(self.flags)
    57         if flags:
    58             entry.append(flags)
    59         return ' '.join(entry)
    61     def __eq__(self, other):
    62         return self.base == other.base and str(self) == str(other)
    64     def __ne__(self, other):
    65         return not self.__eq__(other)
    67     def __repr__(self):
    68         return '<%s@%s>' % (str(self), self.base)
    70     def move(self, base):
    71         '''
    72         Return a new manifest entry with a different base path.
    73         '''
    74         return parse_manifest_line(base, str(self))
    76     def rebase(self, base):
    77         '''
    78         Return a new manifest entry with all relative paths defined in the
    79         entry relative to a new base directory.
    80         The base class doesn't define relative paths, so it is equivalent to
    81         move().
    82         '''
    83         return self.move(base)
    86 class ManifestEntryWithRelPath(ManifestEntry):
    87     '''
    88     Abstract manifest entry type with a relative path definition.
    89     '''
    90     def __init__(self, base, relpath, *flags):
    91         ManifestEntry.__init__(self, base, *flags)
    92         self.relpath = relpath
    94     def __str__(self):
    95         return self.serialize(self.relpath)
    97     def rebase(self, base):
    98         '''
    99         Return a new manifest entry with all relative paths defined in the
   100         entry relative to a new base directory.
   101         '''
   102         clone = ManifestEntry.rebase(self, base)
   103         clone.relpath = mozpack.path.rebase(self.base, base, self.relpath)
   104         return clone
   106     @property
   107     def path(self):
   108         return mozpack.path.normpath(mozpack.path.join(self.base,
   109                                                        self.relpath))
   112 class Manifest(ManifestEntryWithRelPath):
   113     '''
   114     Class for 'manifest' entries.
   115         manifest some/path/to/another.manifest
   116     '''
   117     type = 'manifest'
   120 class ManifestChrome(ManifestEntryWithRelPath):
   121     '''
   122     Abstract class for chrome entries.
   123     '''
   124     def __init__(self, base, name, relpath, *flags):
   125         ManifestEntryWithRelPath.__init__(self, base, relpath, *flags)
   126         self.name = name
   128     @property
   129     def location(self):
   130         return mozpack.path.join(self.base, self.relpath)
   133 class ManifestContent(ManifestChrome):
   134     '''
   135     Class for 'content' entries.
   136         content global content/global/
   137     '''
   138     type = 'content'
   139     allowed_flags = ManifestChrome.allowed_flags + [
   140         'contentaccessible',
   141         'platform',
   142     ]
   144     def __str__(self):
   145         return self.serialize(self.name, self.relpath)
   148 class ManifestMultiContent(ManifestChrome):
   149     '''
   150     Abstract class for chrome entries with multiple definitions.
   151     Used for locale and skin entries.
   152     '''
   153     type = None
   155     def __init__(self, base, name, id, relpath, *flags):
   156         ManifestChrome.__init__(self, base, name, relpath, *flags)
   157         self.id = id
   159     def __str__(self):
   160         return self.serialize(self.name, self.id, self.relpath)
   163 class ManifestLocale(ManifestMultiContent):
   164     '''
   165     Class for 'locale' entries.
   166         locale global en-US content/en-US/
   167         locale global fr content/fr/
   168     '''
   169     localized = True
   170     type = 'locale'
   173 class ManifestSkin(ManifestMultiContent):
   174     '''
   175     Class for 'skin' entries.
   176         skin global classic/1.0 content/skin/classic/
   177     '''
   178     type = 'skin'
   181 class ManifestOverload(ManifestEntry):
   182     '''
   183     Abstract class for chrome entries defining some kind of overloading.
   184     Used for overlay, override or style entries.
   185     '''
   186     type = None
   188     def __init__(self, base, overloaded, overload, *flags):
   189         ManifestEntry.__init__(self, base, *flags)
   190         self.overloaded = overloaded
   191         self.overload = overload
   193     def __str__(self):
   194         return self.serialize(self.overloaded, self.overload)
   196     @property
   197     def localized(self):
   198         u = urlparse(self.overload)
   199         return u.scheme == 'chrome' and \
   200                u.path.split('/')[0:2] == ['', 'locale']
   203 class ManifestOverlay(ManifestOverload):
   204     '''
   205     Class for 'overlay' entries.
   206         overlay chrome://global/content/viewSource.xul \
   207             chrome://browser/content/viewSourceOverlay.xul
   208     '''
   209     type = 'overlay'
   212 class ManifestStyle(ManifestOverload):
   213     '''
   214     Class for 'style' entries.
   215         style chrome://global/content/customizeToolbar.xul \
   216             chrome://browser/skin/
   217     '''
   218     type = 'style'
   221 class ManifestOverride(ManifestOverload):
   222     '''
   223     Class for 'override' entries.
   224         override chrome://global/locale/netError.dtd \
   225             chrome://browser/locale/netError.dtd
   226     '''
   227     type = 'override'
   230 class ManifestResource(ManifestEntry):
   231     '''
   232     Class for 'resource' entries.
   233         resource gre-resources toolkit/res/
   234         resource services-sync resource://gre/modules/services-sync/
   236     The target may be a relative path or a resource or chrome url.
   237     '''
   238     type = 'resource'
   240     def __init__(self, base, name, target, *flags):
   241         ManifestEntry.__init__(self, base, *flags)
   242         self.name = name
   243         self.target = target
   245     def __str__(self):
   246         return self.serialize(self.name, self.target)
   248     def rebase(self, base):
   249         u = urlparse(self.target)
   250         if u.scheme and u.scheme != 'jar':
   251             return ManifestEntry.rebase(self, base)
   252         clone = ManifestEntry.rebase(self, base)
   253         clone.target = mozpack.path.rebase(self.base, base, self.target)
   254         return clone
   257 class ManifestBinaryComponent(ManifestEntryWithRelPath):
   258     '''
   259     Class for 'binary-component' entries.
   260         binary-component some/path/to/a/component.dll
   261     '''
   262     type = 'binary-component'
   265 class ManifestComponent(ManifestEntryWithRelPath):
   266     '''
   267     Class for 'component' entries.
   268         component {b2bba4df-057d-41ea-b6b1-94a10a8ede68} foo.js
   269     '''
   270     type = 'component'
   272     def __init__(self, base, cid, file, *flags):
   273         ManifestEntryWithRelPath.__init__(self, base, file, *flags)
   274         self.cid = cid
   276     def __str__(self):
   277         return self.serialize(self.cid, self.relpath)
   280 class ManifestInterfaces(ManifestEntryWithRelPath):
   281     '''
   282     Class for 'interfaces' entries.
   283         interfaces foo.xpt
   284     '''
   285     type = 'interfaces'
   288 class ManifestCategory(ManifestEntry):
   289     '''
   290     Class for 'category' entries.
   291         category command-line-handler m-browser @mozilla.org/browser/clh;
   292     '''
   293     type = 'category'
   295     def __init__(self, base, category, name, value, *flags):
   296         ManifestEntry.__init__(self, base, *flags)
   297         self.category = category
   298         self.name = name
   299         self.value = value
   301     def __str__(self):
   302         return self.serialize(self.category, self.name, self.value)
   305 class ManifestContract(ManifestEntry):
   306     '''
   307     Class for 'contract' entries.
   308         contract @mozilla.org/foo;1 {b2bba4df-057d-41ea-b6b1-94a10a8ede68}
   309     '''
   310     type = 'contract'
   312     def __init__(self, base, contractID, cid, *flags):
   313         ManifestEntry.__init__(self, base, *flags)
   314         self.contractID = contractID
   315         self.cid = cid
   317     def __str__(self):
   318         return self.serialize(self.contractID, self.cid)
   320 # All manifest classes by their type name.
   321 MANIFESTS_TYPES = dict([(c.type, c) for c in globals().values()
   322                        if type(c) == type and issubclass(c, ManifestEntry)
   323                        and hasattr(c, 'type') and c.type])
   325 MANIFEST_RE = re.compile(r'\s*#.*$')
   328 def parse_manifest_line(base, line):
   329     '''
   330     Parse a line from a manifest file with the given base directory and
   331     return the corresponding ManifestEntry instance.
   332     '''
   333     # Remove comments
   334     cmd = MANIFEST_RE.sub('', line).strip().split()
   335     if not cmd:
   336         return None
   337     if not cmd[0] in MANIFESTS_TYPES:
   338         return errors.fatal('Unknown manifest directive: %s' % cmd[0])
   339     return MANIFESTS_TYPES[cmd[0]](base, *cmd[1:])
   342 def parse_manifest(root, path, fileobj=None):
   343     '''
   344     Parse a manifest file.
   345     '''
   346     base = mozpack.path.dirname(path)
   347     if root:
   348         path = os.path.normpath(os.path.abspath(os.path.join(root, path)))
   349     if not fileobj:
   350         fileobj = open(path)
   351     linenum = 0
   352     for line in fileobj:
   353         linenum += 1
   354         with errors.context(path, linenum):
   355             e = parse_manifest_line(base, line)
   356             if e:
   357                 yield e
   360 def is_manifest(path):
   361     '''
   362     Return whether the given path is that of a manifest file.
   363     '''
   364     return path.endswith('.manifest') and not path.endswith('.CRT.manifest') \
   365         and not path.endswith('.exe.manifest')

mercurial