sapling/tests/check-ext.py

91 lines
3.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python
from __future__ import absolute_import, print_function
from glob import glob
import os
import re
import sys
"""
Check if:
- a test is using foreign extensions without proper checks
- a test is using an extension in this repo without absolute path
"""
# whitelisted foreign extensions
foreignexts = set(['remotenames'])
foreignextre = re.compile(r'(%s)' % '|'.join(foreignexts))
# extensions in this repo
repoexts = set(os.path.basename(p).split('.')[0]
for p in glob('hgext3rd/*.py*') if '__' not in p)
repoexts.update(os.path.basename(os.path.dirname(p))
for p in glob('hgext3rd/*/__init__.py'))
repoexts.update(os.path.basename(os.path.dirname(p))
for p in glob('*/__init__.py'))
repoextre = re.compile(r'(%s)' % '|'.join(repoexts))
checkres = [
(re.compile(r'^\s*>\s*%s\s*=\s*$' % foreignextre.pattern),
'use "$ . $TESTDIR/require-ext.sh %(name)s" to skip the test'
' if %(name)s is not available'),
(re.compile(r'^\s*\$.*--config[ =\']*extensions.%s='
% foreignextre.pattern),
'use "$ . $TESTDIR/require-ext.sh %(name)s" to skip the test'
' if %(name)s is not available'),
(re.compile(r'^\s*>\s*%s\s*=\s*$' % repoextre.pattern),
'use full path like $TESTDIR/../hgext3rd/%(name)s.py for extension '
'in this repo'),
(re.compile(r'^\s*\$.*--config[ =\']*extensions.%s=[ \'"]'
% repoextre.pattern),
'use full path like $TESTDIR/../hgext3rd/%(name)s.py for extension '
'in this repo'),
]
requirere = re.compile(r'require-ext\.sh (.*)$')
def checkfile(path):
errors = []
with open(path) as f:
required = set()
for i, line in enumerate(f):
msg = None
m = requirere.search(line)
if m:
requiredexts = set(m.group(1).split())
unknownexts = requiredexts - foreignexts
for e in unknownexts:
if e in repoexts:
msg = 'do not require non-foreign extension %s'
else:
# change foreignexts if this error is a false postive
msg = 'do not require non-whitelisted extension %s'
errors.append((path, i + 1, line[:-1], msg % e))
required.update(requiredexts)
for regex, msg in checkres:
m = regex.search(line)
if not m:
continue
name = m.group(1)
if name in required:
continue
# line[:-1] is to remove the last "\n"
errors.append((path, i + 1, line[:-1], msg % {'name': name}))
# only one error per extension per file
required.add(name)
return errors
def checkfiles(paths):
errors = []
for path in sys.argv[1:]:
errors += checkfile(path)
return sorted(set(errors))
def printerrors(errors):
# same format with check-code.py
for fname, lineno, line, msg in errors:
print('%s:%d:\n > %s\n %s' % (fname, lineno, line, msg))
printerrors(checkfiles(sys.argv[1:]))