From eb1dbb1044b4f63c2cf9a2fb895abbc33575b77b Mon Sep 17 00:00:00 2001 From: Jeff Balogh Date: Wed, 14 Jul 2010 11:46:24 -0700 Subject: [PATCH 1/3] move validator.py to main.py --- validator/{validator.py => main.py} | 92 ++++++++++++++--------------- 1 file changed, 45 insertions(+), 47 deletions(-) rename validator/{validator.py => main.py} (97%) mode change 100755 => 100644 diff --git a/validator/validator.py b/validator/main.py old mode 100755 new mode 100644 similarity index 97% rename from validator/validator.py rename to validator/main.py index c2ebd2b..0c63fa8 --- a/validator/validator.py +++ b/validator/main.py @@ -23,7 +23,7 @@ from constants import * def main(): "Main function. Handles delegation to other functions." - + expectations = {"any":0, "extension":1, "theme":2, @@ -31,11 +31,11 @@ def main(): "languagepack":4, "search":5, "multi":1} # A multi extension is an extension - - # Parse the arguments that + + # Parse the arguments that parser = argparse.ArgumentParser( description="Run tests on a Mozilla-type addon.") - + parser.add_argument("package", help="The path of the package you're testing") parser.add_argument("-t", @@ -73,48 +73,48 @@ def main(): help="""Indicates that the addon will not be hosted on addons.mozilla.org. This allows the element to be set.""") - + args = parser.parse_args() - + error_bundle = ErrorBundle(args.file, not args.file == sys.stdout or args.boring) - + # Emulates the "$status" variable in the original validation.php # test file. Equal to "$status == STATUS_LISTED". error_bundle.save_resource("listed", not args.selfhosted) - + # Parse out the expected add-on type and run the tests. expectation = expectations[args.type] prepare_package(error_bundle, args.package, expectation) - + # Print the output of the tests based on the requested format. if args.output == "text": error_bundle.print_summary(args.verbose) elif args.output == "json": error_bundle.print_json() - + # Close the output stream. args.file.close() - + if error_bundle.failed(): sys.exit(1) else: sys.exit(0) - + 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("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": test_search(err, path, expectation) # If it didn't bork, it must be a valid provider! @@ -125,92 +125,92 @@ def prepare_package(err, path, expectation=0): if not package_extension in (".xpi", ".jar"): err.reject = True err.error("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("Unexpected file extension.") - + # Is this a search provider? opensearch_results = \ testcases.typedetection.detect_opensearch(package) - + if opensearch_results["failure"]: # Failed OpenSearch validation error_mesg = "OpenSearch: %s" % opensearch_results["error"] err.error(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("OpenSearch provider confirmed.") - + return err - + def test_package(err, package, name, expectation=PACKAGE_ANY): "Begins tests for the package." - + types = {0: "Unknown", 1: "Extension/Multi-Extension", 2: "Theme", 3: "Dictionary", 4: "Language Pack", 5: "Search Provider"} - + # Load up a new instance of an XPI. try: package = XPIManager(package, name) if package is None: # Die on this one because the file won't open. return err.error("The XPI could not be opened.") - + except zipfile.BadZipfile: # This likely means that there is a problem with the zip file. return err.error("The XPI file that was submitted is corrupt.") - + except IOError: # This means that there was something wrong with the command. return err.error("We were unable to open the file for testing.") - + # Test the XPI file for corruption. if not package.test(): err.reject = True return err.error("XPI package appears to be corrupt.") - + assumed_extensions = {"jar": PACKAGE_THEME, "xml": PACKAGE_SEARCHPROV} - + 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("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 err.save_resource("has_install_rdf", has_install_rdf) @@ -218,20 +218,20 @@ def test_package(err, package, name, expectation=PACKAGE_ANY): # Load up the install.rdf file. install_rdf_data = package.read("install.rdf") install_rdf = RDFParser(install_rdf_data) - + # Save a copy for later tests. 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("Unable to determine addon type") 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): @@ -239,13 +239,13 @@ def test_package(err, package, name, expectation=PACKAGE_ANY): err_mesg = "Extension type mismatch (expected %s, found %s)" err_mesg = err_mesg % (types[expectation], types[results]) err.warning(err_mesg) - + return test_inner_package(err, package_contents, package) - + 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()): # Iterate through each test of our detected type @@ -259,17 +259,15 @@ def test_inner_package(err, package_contents, package): # - Package listing # - A copy of the package itself test_func(err, package_contents, package) - + # Return any errors at the end of the tier. if err.failed(): return err - - + + # Return the results. return err # Start up the testing and return the output. if __name__ == '__main__': main() - - From 6b1ca57a8ca49c185dbc54f409b85552fdf11461 Mon Sep 17 00:00:00 2001 From: Jeff Balogh Date: Wed, 14 Jul 2010 11:46:51 -0700 Subject: [PATCH 2/3] call the script addon-validator, move it out of the package --- addon-validator | 5 +++++ setup.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 addon-validator diff --git a/addon-validator b/addon-validator new file mode 100644 index 0000000..8c202b9 --- /dev/null +++ b/addon-validator @@ -0,0 +1,5 @@ +import validator.main + + +if __name__ == '__main__': + validator.main.main() diff --git a/setup.py b/setup.py index a77326e..01c14b0 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( install_requires=['nose', 'cssutils', 'rdflib'], - scripts=["validator/validator.py"], + scripts=["addon-validator"], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Web Environment', @@ -29,4 +29,4 @@ setup( 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', ] -) \ No newline at end of file +) From 4182800c306c29751e299894995e41e6baca884d Mon Sep 17 00:00:00 2001 From: Jeff Balogh Date: Wed, 14 Jul 2010 12:08:08 -0700 Subject: [PATCH 3/3] free yourself from the PYTHONPATH --- MANIFEST.in | 1 + validator/main.py | 24 ++++++++++---------- validator/testcases/conduit.py | 4 ++-- validator/testcases/content.py | 12 +++++----- hashes.txt => validator/testcases/hashes.txt | 0 validator/testcases/installrdf.py | 4 ++-- validator/testcases/l10ncompleteness.py | 12 +++++----- validator/testcases/langpack.py | 6 ++--- validator/testcases/library_blacklist.py | 6 +++-- validator/testcases/markup/markuptester.py | 6 ++--- validator/testcases/packagelayout.py | 2 +- validator/testcases/targetapplication.py | 4 ++-- validator/testcases/themes.py | 6 ++--- validator/typedetection.py | 2 +- 14 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 MANIFEST.in rename hashes.txt => validator/testcases/hashes.txt (100%) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..63a4f4a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include validator/testcases/hashes.txt diff --git a/validator/main.py b/validator/main.py index 0c63fa8..a3f8206 100644 --- a/validator/main.py +++ b/validator/main.py @@ -5,21 +5,21 @@ import zipfile from StringIO import StringIO import argparse -import decorator +from validator import decorator import typedetection -import testcases.packagelayout -import testcases.installrdf -import testcases.library_blacklist -import testcases.conduit -import testcases.langpack -import testcases.themes -import testcases.content -import testcases.targetapplication -import testcases.l10ncompleteness -from xpi import XPIManager +import validator.testcases.packagelayout +import validator.testcases.installrdf +import validator.testcases.library_blacklist +import validator.testcases.conduit +import validator.testcases.langpack +import validator.testcases.themes +import validator.testcases.content +import validator.testcases.targetapplication +import validator.testcases.l10ncompleteness +from validator.xpi import XPIManager from rdf import RDFParser from errorbundler import ErrorBundle -from constants import * +from validator.constants import * def main(): "Main function. Handles delegation to other functions." diff --git a/validator/testcases/conduit.py b/validator/testcases/conduit.py index ecd40b0..627e60d 100644 --- a/validator/testcases/conduit.py +++ b/validator/testcases/conduit.py @@ -1,7 +1,7 @@ import fnmatch -import decorator -from chromemanifest import ChromeManifest +from validator import decorator +from validator.chromemanifest import ChromeManifest @decorator.register_test(1) def test_conduittoolbar(err, package_contents=None, xpi_manager=None): diff --git a/validator/testcases/content.py b/validator/testcases/content.py index 8483e72..60cffde 100644 --- a/validator/testcases/content.py +++ b/validator/testcases/content.py @@ -1,13 +1,13 @@ from StringIO import StringIO -import decorator +from validator import decorator import validator as testendpoint_validator -import testcases.markup.markuptester as testendpoint_markup -import testcases.markup.csstester as testendpoint_css -import testcases.langpack as testendpoint_langpack -from xpi import XPIManager -from constants import PACKAGE_LANGPACK, PACKAGE_SUBPACKAGE +import validator.testcases.markup.markuptester as testendpoint_markup +import validator.testcases.markup.csstester as testendpoint_css +import validator.testcases.langpack as testendpoint_langpack +from validator.xpi import XPIManager +from validator.constants import PACKAGE_LANGPACK, PACKAGE_SUBPACKAGE @decorator.register_test(tier=2) diff --git a/hashes.txt b/validator/testcases/hashes.txt similarity index 100% rename from hashes.txt rename to validator/testcases/hashes.txt diff --git a/validator/testcases/installrdf.py b/validator/testcases/installrdf.py index d2c49dd..cc3f252 100644 --- a/validator/testcases/installrdf.py +++ b/validator/testcases/installrdf.py @@ -1,7 +1,7 @@ import re -import decorator -from constants import * +from validator import decorator +from validator.constants import * @decorator.register_test(tier=1) def test_install_rdf_params(err, diff --git a/validator/testcases/l10ncompleteness.py b/validator/testcases/l10ncompleteness.py index ba4113a..7a6d927 100644 --- a/validator/testcases/l10ncompleteness.py +++ b/validator/testcases/l10ncompleteness.py @@ -4,15 +4,15 @@ import os import json from StringIO import StringIO -import decorator -from chromemanifest import ChromeManifest -from xpi import XPIManager -from constants import PACKAGE_EXTENSION, \ +from validator import decorator +from validator.chromemanifest import ChromeManifest +from validator.xpi import XPIManager +from validator.constants import PACKAGE_EXTENSION, \ PACKAGE_THEME, \ PACKAGE_LANGPACK -import testcases.l10n.dtd as dtd -import testcases.l10n.properties as properties +import validator.testcases.l10n.dtd as dtd +import validator.testcases.l10n.properties as properties # The threshold that determines the number of entities that must not be # missing from the package. diff --git a/validator/testcases/langpack.py b/validator/testcases/langpack.py index 74da6e3..e60c829 100644 --- a/validator/testcases/langpack.py +++ b/validator/testcases/langpack.py @@ -1,9 +1,9 @@ import fnmatch import re -import decorator -from chromemanifest import ChromeManifest -from constants import PACKAGE_LANGPACK +from validator import decorator +from validator.chromemanifest import ChromeManifest +from validator.constants import PACKAGE_LANGPACK BAD_LINK = '(href|src)=["\'](?!(chrome:\/\/|#([a-z][a-z0-9\-_:\.]*)?))' diff --git a/validator/testcases/library_blacklist.py b/validator/testcases/library_blacklist.py index 6dbdee5..8072b72 100644 --- a/validator/testcases/library_blacklist.py +++ b/validator/testcases/library_blacklist.py @@ -1,6 +1,7 @@ import hashlib +import os -import decorator +from validator import decorator @decorator.register_test(tier=1) def test_library_blacklist(err, package_contents=None, xpi_package=None): @@ -16,7 +17,8 @@ def test_library_blacklist(err, package_contents=None, xpi_package=None): generated using the libhasher.py tool.""" # Generate a tuple of definition data - lines = open("hashes.txt").readlines() + path = os.path.join(os.path.dirname(__file__), 'hashes.txt') + lines = open(path).readlines() definitions = [line.strip() for line in lines] # Iterate each file diff --git a/validator/testcases/markup/markuptester.py b/validator/testcases/markup/markuptester.py index be0187a..ac8a412 100644 --- a/validator/testcases/markup/markuptester.py +++ b/validator/testcases/markup/markuptester.py @@ -4,9 +4,9 @@ try: from HTMLParser import HTMLParser except ImportError: # pragma: no cover from html.parser import HTMLParser - -from testcases.markup import csstester -from constants import * + +from validator.testcases.markup import csstester +from validator.constants import * DEBUG = False diff --git a/validator/testcases/packagelayout.py b/validator/testcases/packagelayout.py index 4cdeba9..8d7e546 100644 --- a/validator/testcases/packagelayout.py +++ b/validator/testcases/packagelayout.py @@ -1,6 +1,6 @@ import fnmatch -import decorator +from validator import decorator def test_unknown_file(err, filename): diff --git a/validator/testcases/targetapplication.py b/validator/testcases/targetapplication.py index 49289f7..0db63af 100644 --- a/validator/testcases/targetapplication.py +++ b/validator/testcases/targetapplication.py @@ -1,6 +1,6 @@ -import decorator -from constants import * +from validator import decorator +from validator.constants import * APPLICATIONS = { "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}": "firefox", diff --git a/validator/testcases/themes.py b/validator/testcases/themes.py index f86cb0f..05d57f8 100644 --- a/validator/testcases/themes.py +++ b/validator/testcases/themes.py @@ -1,6 +1,6 @@ -import decorator -from chromemanifest import ChromeManifest -from constants import PACKAGE_THEME +from validator import decorator +from validator.chromemanifest import ChromeManifest +from validator.constants import PACKAGE_THEME @decorator.register_test(tier=2, expected_type=PACKAGE_THEME) diff --git a/validator/typedetection.py b/validator/typedetection.py index 2afae51..b139b2b 100644 --- a/validator/typedetection.py +++ b/validator/typedetection.py @@ -1,5 +1,5 @@ from xml.dom.minidom import parse -from constants import * +from validator.constants import * def detect_type(err, install_rdf=None, xpi_package=None): """Determines the type of addon being validated based on