Subversion Repositories wimsdev

Rev

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

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. w3c-validator - Validate HTML 5 and CSS files using the WC3 validators.
  5.  
  6. Copyright: Stuart Rackham (c) 2011
  7. Updated for python 3 : Olivier Bado (c) 2018
  8. License:   MIT
  9. Email:     srackham@gmail.com
  10.  
  11. """
  12.  
  13. import os
  14. import sys
  15. import time
  16. import json
  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+
  23.  
  24. html_validator_url = 'https://validator.w3.org/nu/'
  25. css_validator_url = 'http://jigsaw.w3.org/css-validator/validator'
  26.  
  27. verbose_option = False
  28.  
  29.  
  30. def message(msg):
  31.     """Send msg to the standard error output."""
  32.     msg = msg.encode('ascii', 'ignore').decode('ascii')
  33.     sys.stderr.write(msg + "\n")
  34.  
  35.  
  36. def verbose(msg):
  37.     """Call the message function if verbose_option (--verbose arg) is set."""
  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.    """
  51.     quoted_filename = quote(filename)
  52.  
  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'
  57.                    % (quoted_filename, css_validator_url))
  58.         else:
  59.             cmd = ('curl -sG -d doc=%s -d out=json %s'
  60.                    % (quoted_filename, html_validator_url))
  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'
  65.                    % (quoted_filename, css_validator_url))
  66.         else:
  67.             cmd = ('curl -sH "Content-Type: text/html" --data-binary "@%s" %s?out=json'
  68.                    % (quoted_filename, html_validator_url))
  69.     verbose(cmd)
  70.     # status, output = commands.getstatusoutput(cmd)
  71.  
  72.     cmd = shlex.split(cmd)
  73.     output = subprocess.check_output(cmd)
  74.     verbose(output)
  75.  
  76.     result = json.loads(output)
  77.  
  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:
  103.             message('failed after too much tries: %s' % f)
  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)
  127.