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

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

mercurial