diff --git a/requirements.txt b/requirements.txt index 471f8ae..0e3990a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ html2text==2014.12.29 lxml==3.4.1 parse==1.6.6 aiohttp==0.20.2 +pystache==0.5.4 diff --git a/validator/__init__.py b/validator/__init__.py index 850d2f5..cf1c4ef 100644 --- a/validator/__init__.py +++ b/validator/__init__.py @@ -1,11 +1,15 @@ +import logging +import sys from enum import Enum from collections import defaultdict from pathlib import Path from markdown import markdown -from . import parsers, checks, reports, fs +from . import cmd, parsers, checks, reports, fs +logger = logging.getLogger() + class Validator(object): def __init__(self, contents, parser, check, reporter=None): self.contents = contents @@ -123,3 +127,32 @@ def text(self, base, other): def parse(): return ContentBuilder() + +def validate_formatting(settings): + errors = parse().files(settings.source, lang=settings.base_locale).xml( + query='.//string').check().md().validate() + + if errors: + logger.info('Errors: %d' % len(errors)) + report_uri = reports.HtmlSummaryReporter(settings.output).report(errors).uri_path + logger.info('See %s' % report_uri) + return False + else: + return True + +def init_log(verbose): + log_level = logging.DEBUG if verbose else logging.INFO + handler = logging.StreamHandler(sys.stderr) + logger.setLevel(log_level) + logger.addHandler(handler) + + +def main(): + args = cmd.read_args() + if args.version: + result = cmd.print_version() + else: + settings = cmd.read_settings(args) + init_log(settings.verbose) + valid = validate_formatting(settings) + sys.exit(0) if not valid else sys.exit(1) diff --git a/validator/cmd.py b/validator/cmd.py new file mode 100644 index 0000000..0fbe097 --- /dev/null +++ b/validator/cmd.py @@ -0,0 +1,55 @@ +""" +Handles command line and calls the email parser with corrent options. +""" + +import argparse +import logging +from collections import namedtuple + +logger = logging.getLogger() + +Settings = namedtuple('Settings', [ + 'source', + 'base_locale', + 'output', + 'verbose' +]) + + +def default_settings(): + return Settings( + source='src/{lang}/*.xml', + base_locale='en', + output='errors/summary.html', + verbose=False + ) + + +def read_args(argsargs=argparse.ArgumentParser): + settings = default_settings() + logger.debug('reading arguments list') + args = argsargs(epilog='Brought to you by KeepSafe - www.getkeepsafe.com') + + args.add_argument('-s', '--source', help='args\'s source folder, default: %s' % settings.source) + args.add_argument('-o', '--output', + help='destination path for HTML report, default: %s' % settings.output) + args.add_argument('-l', '--base-locale', help='Base locale for comparision: %s' % settings.base_locale) + args.add_argument('-vv', '--verbose', help='Verbose', action='store_true') + args.add_argument('-v', '--version', help='Show version', action='store_true') + return args.parse_args() + + +def read_settings(args): + args = vars(args) + settings = default_settings()._asdict() + for k in settings: + if k in args and args[k] is not None: + settings[k] = args[k] + return Settings(**settings) + + +def print_version(): + import pkg_resources + version = pkg_resources.require('content-validator')[0].version + print(version) + return True diff --git a/validator/fs.py b/validator/fs.py index 768f24d..48c3499 100644 --- a/validator/fs.py +++ b/validator/fs.py @@ -1,4 +1,5 @@ from pathlib import Path +import os from string import Formatter from collections import defaultdict from enum import Enum @@ -26,6 +27,15 @@ def save_report(directory, source_path, report): with path.open('w') as fp: fp.write(report) +def save_summary_report(filepath, content): + path = Path(filepath) + try: + path.parent.mkdir(parents=True) + except FileExistsError: + pass + with path.open('w') as fp: + fp.write(content) + return Path(os.path.abspath(filepath)).as_uri() def _no_params_pattern(pattern): yield list(Path().glob(pattern)) diff --git a/validator/reports.py b/validator/reports.py index 0d47b2f..7799505 100644 --- a/validator/reports.py +++ b/validator/reports.py @@ -3,8 +3,9 @@ import sys import shutil import markdown +import pystache -from .fs import save_report, read_content +from .fs import save_report, read_content, save_summary_report from .errors import UrlDiff, MdDiff @@ -147,3 +148,117 @@ def __init__(self, reporters): def report(self, errors): for reporter in self.reporters: reporter.report(errors) + +class HtmlSummaryReporter(object): + report_template = """ + + + + + + + + KS Content-validator + + + + + + + + + + + +
+
+ + + {{#files}} +
+
+

{{name}}

+
+
+
This is how the text will look to the user
+
+
{{{details.lc}}}
+
{{{details.rc}}}
+
+ +
This is the original text
+
+
{{{details.ld}}}
+
{{{details.rd}}}
+
+ +
+
+ {{/files}} +
+
+ + + + +""" + + def __init__(self, output_filepath='errors/summary.html'): + self.output_filepath = output_filepath + self.uri_path = None + + def report(self, errors): + files = {} + for error in errors: + filename = str(error.other.original) + files[filename] = files.get(filename, {'errors':[] }) + if isinstance(error, UrlDiff): + files[filename]['errors'].append("%s returned with code %s" % (error.url, error.status_code)) + if isinstance(error, MdDiff): + files[filename]['errors'] += list(error.error_msgs) + files[filename]['lc'] = markdown.markdown(error.base.parsed) + files[filename]['rc'] = markdown.markdown(error.other.parsed) + files[filename]['ld'] = error.base.diff + files[filename]['rd'] = error.other.diff + data = [{'name': k, 'details': v} for k,v in files.items()] + for i in range(0,len(data)): + data[i]['id'] = 'file_%s' % i + content = pystache.render(self.report_template, {'files': data}) + self.uri_path = save_summary_report(self.output_filepath, content) + return self