app-validator/validator/submain.py

210 строки
7.2 KiB
Python

import os
import zipfile
import validator.testcases as testcases
import validator.typedetection as typedetection
from validator.typedetection import detect_opensearch
from validator.xpi import XPIManager
from validator.rdf import RDFParser
from validator import decorator
from validator.constants import *
types = {0: "Unknown",
1: "Extension/Multi-Extension",
2: "Theme",
3: "Dictionary",
4: "Language Pack",
5: "Search Provider"}
assumed_extensions = {"jar": PACKAGE_THEME,
"xml": PACKAGE_SEARCHPROV}
def prepare_package(err, path, expectation=0):
"Prepares a file-based package for validation."
# Test that the package actually exists. I consider this Tier 0
# since we may not even be dealing with a real file.
if not os.path.isfile(path):
err.reject = True
return err.error(("main",
"prepare_package",
"not_found"),
"The package could not be found")
# Pop the package extension.
package_extension = os.path.splitext(path)[1]
package_extension = package_extension.lower()
if package_extension == ".xml":
return test_search(err, path, expectation)
# Test that the package is an XPI.
if package_extension not in (".xpi", ".jar"):
err.reject = True
err.error(("main",
"prepare_package",
"unrecognized"),
"The package is not of a recognized type.")
package = open(path)
output = test_package(err, package, path, expectation)
package.close()
return output
def test_search(err, package, expectation=0):
"Tests the package to see if it is a search provider."
expected_search_provider = expectation in (PACKAGE_ANY,
PACKAGE_SEARCHPROV)
# If we're not expecting a search provider, warn the user and stop
# testing it like a search provider.
if not expected_search_provider:
err.reject = True
return err.warning(("main",
"test_search",
"extension"),
"Unexpected file extension.")
# Is this a search provider?
opensearch_results = detect_opensearch(package)
if opensearch_results["failure"]:
# Failed OpenSearch validation
error_mesg = "OpenSearch: %s" % opensearch_results["error"]
err.error(("main",
"test_search",
"general_failure"),
error_mesg)
# We want this to flow back into the rest of the program if
# the error indicates that we're not sure whether it's an
# OpenSearch document or not.
if not "decided" in opensearch_results or \
opensearch_results["decided"]:
err.reject = True
return err
elif expected_search_provider:
err.set_type(PACKAGE_SEARCHPROV)
err.info(("main",
"test_search",
"confirmed"),
"OpenSearch provider confirmed.")
return err
def test_package(err, file_, name, expectation=PACKAGE_ANY):
"Begins tests for the package."
# Load up a new instance of an XPI.
package = XPIManager(file_, name)
if not package.zf:
# Die on this one because the file won't open.
return err.error(("main",
"test_package",
"unopenable"),
"The XPI could not be opened.")
# Test the XPI file for corruption.
if package.test():
err.reject = True
return err.error(("main",
"test_package",
"corrupt"),
"XPI package appears to be corrupt.")
if package.extension in assumed_extensions:
assumed_type = assumed_extensions[package.extension]
# Is the user expecting a different package type?
if not expectation in (PACKAGE_ANY, assumed_type):
err.error(("main",
"test_package",
"unexpected_type"),
"Unexpected package type (found theme)")
# Cache a copy of the package contents.
package_contents = package.get_file_data()
# Test the install.rdf file to see if we can get the type that way.
has_install_rdf = "install.rdf" in package_contents
if has_install_rdf:
_load_install_rdf(err, package, expectation)
return test_inner_package(err, package_contents, package)
def _load_install_rdf(err, package, expectation):
# Load up the install.rdf file.
install_rdf_data = package.read("install.rdf")
install_rdf = RDFParser(install_rdf_data)
if install_rdf.rdf is None or not install_rdf:
return err.error(("main",
"test_package",
"cannot_parse_installrdf"),
"Cannot Parse install.rdf",
"The install.rdf file could not be parsed.")
else:
err.save_resource("has_install_rdf", True)
err.save_resource("install_rdf", install_rdf)
# Load up the results of the type detection
results = typedetection.detect_type(err,
install_rdf,
package)
if results is None:
return err.error(("main",
"test_package",
"undeterminable_type"),
"Unable to determine addon type",
"""The type detection algorithm could not
determine the type of the add-on.""")
else:
err.set_type(results)
# Compare the results of the low-level type detection to
# that of the expectation and the assumption.
if not expectation in (PACKAGE_ANY, results):
err.reject = True
err.warning(("main",
"test_package",
"extension_type_mismatch"),
"Extension Type Mismatch",
'Type "%s" expected, found "%s")' % (
types[expectation],
types[results]))
def test_inner_package(err, package_contents, package):
"Tests a package's inner content."
# Iterate through each tier.
for tier in sorted(decorator.get_tiers()):
# Let the error bundler know what tier we're on
err.tier = tier
# Iterate through each test of our detected type
for test in decorator.get_tests(tier, err.detected_type):
test_func = test["test"]
if test["simple"]:
test_func(err)
else:
# Pass in:
# - Error Bundler
# - Package listing
# - A copy of the package itself
test_func(err, package_contents, package)
# Return any errors at the end of the tier if undetermined.
if err.failed() and not err.determined:
err.unfinished = True
return err
# Return the results.
return err