tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

manifest.py (10297B)


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