Subversion Repositories wimsdev

Rev

Rev 16407 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17835 bpr 1
#!/usr/bin/env python3
11744 bpr 2
# -*- coding: utf-8 -*-
11189 bpr 3
"""
11744 bpr 4
w3c-validator - Validate HTML 5 and CSS files using the WC3 validators.
11189 bpr 5
 
6
Copyright: Stuart Rackham (c) 2011
12491 obado 7
Updated for python 3 : Olivier Bado (c) 2018
11189 bpr 8
License:   MIT
9
Email:     srackham@gmail.com
10
 
11
"""
12
 
13
import os
14
import sys
15
import time
16
import json
12483 obado 17
import subprocess
18
import shlex
19
try:
20
    from urllib import quote  # Python 2.X
21
except ImportError:
22
    from urllib.parse import quote  # Python 3+
11189 bpr 23
 
16407 reyssat 24
html_validator_url = 'https://validator.w3.org/nu/'
11189 bpr 25
css_validator_url = 'http://jigsaw.w3.org/css-validator/validator'
26
 
27
verbose_option = False
28
 
29
 
30
def message(msg):
12453 obado 31
    """Send msg to the standard error output."""
12491 obado 32
    msg = msg.encode('ascii', 'ignore').decode('ascii')
12492 obado 33
    sys.stderr.write(msg + "\n")
11189 bpr 34
 
35
 
36
def verbose(msg):
12453 obado 37
    """Call the message function if verbose_option (--verbose arg) is set."""
11189 bpr 38
    if verbose_option:
39
        message(msg)
40
 
41
 
42
def validate(filename):
43
    """
44
    Validate file and return JSON result as dictionary.
45
 
46
    'filename' can be a file name or an HTTP URL.
47
    Return '' if the validator does not return valid JSON.
48
    Raise OSError if curl command returns an error status.
49
 
50
    """
12483 obado 51
    quoted_filename = quote(filename)
52
 
11189 bpr 53
    if filename.startswith('http://'):
54
        # Submit URI with GET.
55
        if filename.endswith('.css'):
56
            cmd = ('curl -sG -d uri=%s -d output=json -d warning=0 %s'
12453 obado 57
                   % (quoted_filename, css_validator_url))
11189 bpr 58
        else:
11744 bpr 59
            cmd = ('curl -sG -d doc=%s -d out=json %s'
12453 obado 60
                   % (quoted_filename, html_validator_url))
11189 bpr 61
    else:
62
        # Upload file as multipart/form-data with POST.
63
        if filename.endswith('.css'):
64
            cmd = ('curl -sF "file=@%s;type=text/css" -F output=json -F warning=0 %s'
12453 obado 65
                   % (quoted_filename, css_validator_url))
11189 bpr 66
        else:
11746 bpr 67
            cmd = ('curl -sH "Content-Type: text/html" --data-binary "@%s" %s?out=json'
12453 obado 68
                   % (quoted_filename, html_validator_url))
11189 bpr 69
    verbose(cmd)
12483 obado 70
    # status, output = commands.getstatusoutput(cmd)
71
 
72
    cmd = shlex.split(cmd)
73
    output = subprocess.check_output(cmd)
11189 bpr 74
    verbose(output)
12483 obado 75
 
11744 bpr 76
    result = json.loads(output)
12483 obado 77
 
11189 bpr 78
    time.sleep(2)   # Be nice and don't hog the free validator service.
79
    return result
80
 
81
 
82
if __name__ == '__main__':
83
    if len(sys.argv) >= 2 and sys.argv[1] == '--verbose':
84
        verbose_option = True
85
        args = sys.argv[2:]
86
    else:
87
        args = sys.argv[1:]
88
    if len(args) == 0:
89
        message('usage: %s [--verbose] FILE|URL...' % os.path.basename(sys.argv[0]))
90
        exit(1)
91
    errors = 0
92
    warnings = 0
93
    for f in args:
94
        message('validating: %s ...' % f)
95
        retrys = 0
96
        while retrys < 2:
97
            result = validate(f)
98
            if result:
99
                break
100
            retrys += 1
101
            message('retrying: %s ...' % f)
102
        else:
11744 bpr 103
            message('failed after too much tries: %s' % f)
11189 bpr 104
            errors += 1
105
            continue
106
        if f.endswith('.css'):
107
            errorcount = result['cssvalidation']['result']['errorcount']
108
            warningcount = result['cssvalidation']['result']['warningcount']
109
            errors += errorcount
110
            warnings += warningcount
111
            if errorcount > 0:
112
                message('errors: %d' % errorcount)
113
            if warningcount > 0:
114
                message('warnings: %d' % warningcount)
115
        else:
116
            for msg in result['messages']:
117
                if 'lastLine' in msg:
118
                    message('%(type)s: line %(lastLine)d: %(message)s' % msg)
119
                else:
120
                    message('%(type)s: %(message)s' % msg)
121
                if msg['type'] == 'error':
122
                    errors += 1
123
                else:
124
                    warnings += 1
125
    if errors:
126
        exit(1)