sapling/tests/check-ext.py
Jun Wu 3d461ae600 check-ext: make checks stricter
Summary:
Enhance check-ext script to be more strict:

 - Only one foreign extension is allowed: `remotenames`
 - Require explicit path for in-repo extensions to avoid wrong extensions
   being tested

This would make the test more predicatable since system extensions
will be less likely to be imported. Explicit path is better than
setting `PYTHONPATH` since `hgext/name.py` could override
`hgext3rd/name.py` regardless of `PYTHONPATH`.

Test Plan: arc unit

Reviewers: phillco, durham, ikostia, #mercurial, stash

Reviewed By: stash

Subscribers: medson, mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D5271430

Signature: t1:5271430:1497861776:7dd35ec7c522cd9b26aa0871cb4306b4f1b8993a
2017-06-19 08:02:38 -07:00

91 lines
3.1 KiB
Python
Executable File

#!/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:]))