Source code
Revision control
Copy as Markdown
Other Tools
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
import os
import re
import six
from six.moves.urllib.parse import urlparse
import mozpack.path as mozpath
from mozpack.chrome.flags import Flags
from mozpack.errors import errors
class ManifestEntry(object):
"""
Base class for all manifest entry types.
Subclasses may define the following class or member variables:
- localized: indicates whether the manifest entry is used for localized
data.
- type: the manifest entry type (e.g. 'content' in
'content global content/global/')
- allowed_flags: a set of flags allowed to be defined for the given
manifest entry type.
A manifest entry is attached to a base path, defining where the manifest
entry is bound to, and that is used to find relative paths defined in
entries.
"""
localized = False
type = None
allowed_flags = [
"application",
"platformversion",
"os",
"osversion",
"abi",
"xpcnativewrappers",
"tablet",
"process",
"contentaccessible",
"backgroundtask",
]
def __init__(self, base, *flags):
"""
Initialize a manifest entry with the given base path and flags.
"""
self.base = base
self.flags = Flags(*flags)
if not all(f in self.allowed_flags for f in self.flags):
errors.fatal(
"%s unsupported for %s manifest entries"
% (
",".join(f for f in self.flags if f not in self.allowed_flags),
self.type,
)
)
def serialize(self, *args):
"""
Serialize the manifest entry.
"""
entry = [self.type] + list(args)
flags = str(self.flags)
if flags:
entry.append(flags)
return " ".join(entry)
def __eq__(self, other):
return self.base == other.base and str(self) == str(other)
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return "<%s@%s>" % (str(self), self.base)
def move(self, base):
"""
Return a new manifest entry with a different base path.
"""
return parse_manifest_line(base, str(self))
def rebase(self, base):
"""
Return a new manifest entry with all relative paths defined in the
entry relative to a new base directory.
The base class doesn't define relative paths, so it is equivalent to
move().
"""
return self.move(base)
class ManifestEntryWithRelPath(ManifestEntry):
"""
Abstract manifest entry type with a relative path definition.
"""
def __init__(self, base, relpath, *flags):
ManifestEntry.__init__(self, base, *flags)
self.relpath = relpath
def __str__(self):
return self.serialize(self.relpath)
def rebase(self, base):
"""
Return a new manifest entry with all relative paths defined in the
entry relative to a new base directory.
"""
clone = ManifestEntry.rebase(self, base)
clone.relpath = mozpath.rebase(self.base, base, self.relpath)
return clone
@property
def path(self):
return mozpath.normpath(mozpath.join(self.base, self.relpath))
class Manifest(ManifestEntryWithRelPath):
"""
Class for 'manifest' entries.
manifest some/path/to/another.manifest
"""
type = "manifest"
class ManifestChrome(ManifestEntryWithRelPath):
"""
Abstract class for chrome entries.
"""
def __init__(self, base, name, relpath, *flags):
ManifestEntryWithRelPath.__init__(self, base, relpath, *flags)
self.name = name
@property
def location(self):
return mozpath.join(self.base, self.relpath)
class ManifestContent(ManifestChrome):
"""
Class for 'content' entries.
content global content/global/
"""
type = "content"
allowed_flags = ManifestChrome.allowed_flags + [
"contentaccessible",
"platform",
]
def __str__(self):
return self.serialize(self.name, self.relpath)
class ManifestMultiContent(ManifestChrome):
"""
Abstract class for chrome entries with multiple definitions.
Used for locale and skin entries.
"""
type = None
def __init__(self, base, name, id, relpath, *flags):
ManifestChrome.__init__(self, base, name, relpath, *flags)
self.id = id
def __str__(self):
return self.serialize(self.name, self.id, self.relpath)
class ManifestLocale(ManifestMultiContent):
"""
Class for 'locale' entries.
locale global en-US content/en-US/
locale global fr content/fr/
"""
localized = True
type = "locale"
class ManifestSkin(ManifestMultiContent):
"""
Class for 'skin' entries.
skin global classic/1.0 content/skin/classic/
"""
type = "skin"
class ManifestOverload(ManifestEntry):
"""
Abstract class for chrome entries defining some kind of overloading.
Used for overlay, override or style entries.
"""
type = None
def __init__(self, base, overloaded, overload, *flags):
ManifestEntry.__init__(self, base, *flags)
self.overloaded = overloaded
self.overload = overload
def __str__(self):
return self.serialize(self.overloaded, self.overload)
class ManifestOverlay(ManifestOverload):
"""
Class for 'overlay' entries.
"""
type = "overlay"
class ManifestStyle(ManifestOverload):
"""
Class for 'style' entries.
"""
type = "style"
class ManifestOverride(ManifestOverload):
"""
Class for 'override' entries.
"""
type = "override"
class ManifestResource(ManifestEntry):
"""
Class for 'resource' entries.
resource gre-resources toolkit/res/
The target may be a relative path or a resource or chrome url.
"""
type = "resource"
def __init__(self, base, name, target, *flags):
ManifestEntry.__init__(self, base, *flags)
self.name = name
self.target = target
def __str__(self):
return self.serialize(self.name, self.target)
def rebase(self, base):
u = urlparse(self.target)
if u.scheme and u.scheme != "jar":
return ManifestEntry.rebase(self, base)
clone = ManifestEntry.rebase(self, base)
clone.target = mozpath.rebase(self.base, base, self.target)
return clone
class ManifestBinaryComponent(ManifestEntryWithRelPath):
"""
Class for 'binary-component' entries.
binary-component some/path/to/a/component.dll
"""
type = "binary-component"
class ManifestComponent(ManifestEntryWithRelPath):
"""
Class for 'component' entries.
component {b2bba4df-057d-41ea-b6b1-94a10a8ede68} foo.js
"""
type = "component"
def __init__(self, base, cid, file, *flags):
ManifestEntryWithRelPath.__init__(self, base, file, *flags)
self.cid = cid
def __str__(self):
return self.serialize(self.cid, self.relpath)
class ManifestInterfaces(ManifestEntryWithRelPath):
"""
Class for 'interfaces' entries.
interfaces foo.xpt
"""
type = "interfaces"
class ManifestCategory(ManifestEntry):
"""
Class for 'category' entries.
category command-line-handler m-browser @mozilla.org/browser/clh;
"""
type = "category"
def __init__(self, base, category, name, value, *flags):
ManifestEntry.__init__(self, base, *flags)
self.category = category
self.name = name
self.value = value
def __str__(self):
return self.serialize(self.category, self.name, self.value)
class ManifestContract(ManifestEntry):
"""
Class for 'contract' entries.
contract @mozilla.org/foo;1 {b2bba4df-057d-41ea-b6b1-94a10a8ede68}
"""
type = "contract"
def __init__(self, base, contractID, cid, *flags):
ManifestEntry.__init__(self, base, *flags)
self.contractID = contractID
self.cid = cid
def __str__(self):
return self.serialize(self.contractID, self.cid)
# All manifest classes by their type name.
MANIFESTS_TYPES = dict(
[
(c.type, c)
for c in globals().values()
if type(c) is type
and issubclass(c, ManifestEntry)
and hasattr(c, "type")
and c.type
]
)
MANIFEST_RE = re.compile(r"^#.*$")
def parse_manifest_line(base, line):
"""
Parse a line from a manifest file with the given base directory and
return the corresponding ManifestEntry instance.
"""
# Remove comments
cmd = MANIFEST_RE.sub("", line).strip().split()
if not cmd:
return None
if not cmd[0] in MANIFESTS_TYPES:
return errors.fatal("Unknown manifest directive: %s" % cmd[0])
return MANIFESTS_TYPES[cmd[0]](base, *cmd[1:])
def parse_manifest(root, path, fileobj=None):
"""
Parse a manifest file.
"""
base = mozpath.dirname(path)
if root:
path = os.path.normpath(os.path.abspath(os.path.join(root, path)))
if not fileobj:
fileobj = open(path)
linenum = 0
for line in fileobj:
line = six.ensure_text(line)
linenum += 1
with errors.context(path, linenum):
e = parse_manifest_line(base, line)
if e:
yield e
def is_manifest(path):
"""
Return whether the given path is that of a manifest file.
"""
return (
path.endswith(".manifest")
and not path.endswith(".CRT.manifest")
and not path.endswith(".exe.manifest")
and os.path.basename(path) != "cose.manifest"
)