mirror of
https://github.com/ManchildProductions/UXP-Fixed.git
synced 2026-06-24 19:08:31 +00:00
86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
# 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
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import imp
|
|
import os
|
|
import sys
|
|
import uuid
|
|
|
|
from .types import supported_types
|
|
from .errors import LinterNotFound, LinterParseError
|
|
|
|
|
|
class Parser(object):
|
|
"""Reads and validates `.lint` files."""
|
|
required_attributes = (
|
|
'name',
|
|
'description',
|
|
'type',
|
|
'payload',
|
|
)
|
|
|
|
def __call__(self, path):
|
|
return self.parse(path)
|
|
|
|
def _load_linter(self, path):
|
|
# Ensure parent module is present otherwise we'll (likely) get
|
|
# an error due to unknown parent.
|
|
parent_module = 'mozlint.linters'
|
|
if parent_module not in sys.modules:
|
|
mod = imp.new_module(parent_module)
|
|
sys.modules[parent_module] = mod
|
|
|
|
write_bytecode = sys.dont_write_bytecode
|
|
sys.dont_write_bytecode = True
|
|
|
|
module_name = '{}.{}'.format(parent_module, uuid.uuid1().get_hex())
|
|
imp.load_source(module_name, path)
|
|
|
|
sys.dont_write_bytecode = write_bytecode
|
|
|
|
mod = sys.modules[module_name]
|
|
|
|
if not hasattr(mod, 'LINTER'):
|
|
raise LinterParseError(path, "No LINTER definition found!")
|
|
|
|
definition = mod.LINTER
|
|
definition['path'] = path
|
|
return definition
|
|
|
|
def _validate(self, linter):
|
|
missing_attrs = []
|
|
for attr in self.required_attributes:
|
|
if attr not in linter:
|
|
missing_attrs.append(attr)
|
|
|
|
if missing_attrs:
|
|
raise LinterParseError(linter['path'], "Missing required attribute(s): "
|
|
"{}".format(','.join(missing_attrs)))
|
|
|
|
if linter['type'] not in supported_types:
|
|
raise LinterParseError(linter['path'], "Invalid type '{}'".format(linter['type']))
|
|
|
|
for attr in ('include', 'exclude'):
|
|
if attr in linter and (not isinstance(linter[attr], list) or
|
|
not all(isinstance(a, basestring) for a in linter[attr])):
|
|
raise LinterParseError(linter['path'], "The {} directive must be a "
|
|
"list of strings!".format(attr))
|
|
|
|
def parse(self, path):
|
|
"""Read a linter and return its LINTER definition.
|
|
|
|
:param path: Path to the linter.
|
|
:returns: Linter definition (dict)
|
|
:raises: LinterNotFound, LinterParseError
|
|
"""
|
|
if not os.path.isfile(path):
|
|
raise LinterNotFound(path)
|
|
|
|
if not path.endswith('.lint'):
|
|
raise LinterParseError(path, "Invalid filename, linters must end with '.lint'!")
|
|
|
|
linter = self._load_linter(path)
|
|
self._validate(linter)
|
|
return linter
|