diff --git a/Makefile b/Makefile index 5ae4e9291f..33683ba16a 100644 --- a/Makefile +++ b/Makefile @@ -119,8 +119,7 @@ examples: $(BUILD_EXAMPLES) install: build/timestamps/node-modules-timestamp .PHONY: lint -lint: build/timestamps/eslint-timestamp \ - build/timestamps/check-requires-timestamp +lint: build/timestamps/eslint-timestamp .PHONY: npm-install npm-install: build/timestamps/node-modules-timestamp @@ -184,13 +183,6 @@ build/timestamps/check-%-timestamp: $(BUILD_HOSTED)/examples/%.html \ ./node_modules/.bin/phantomjs --local-to-remote-url-access=true --ssl-protocol=any --ignore-ssl-errors=true bin/check-example.js $< @touch $@ -build/timestamps/check-requires-timestamp: $(SRC_JS) $(EXAMPLES_JS) \ - $(SRC_SHADER_JS) $(SPEC_JS) \ - $(SPEC_RENDERING_JS) - @mkdir -p $(@D) - @python bin/check-requires.py $(CLOSURE_LIB) $^ - @touch $@ - build/compiled-examples/all.js: $(EXAMPLES_JS) @mkdir -p $(@D) @python bin/combine-examples.py $^ > $@ diff --git a/bin/check-requires.py b/bin/check-requires.py deleted file mode 100644 index 09503ea291..0000000000 --- a/bin/check-requires.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import logging -import re -import sys - -logging.basicConfig(format='%(asctime)s %(name)s: %(message)s', - level=logging.INFO) - -logger = logging.getLogger('check-requires') - - -class Node(object): - - def __init__(self): - self.present = False - self.children = {} - - def _build_re(self, key): - if key == '*': - assert len(self.children) == 0 - # We want to match `.doIt` but not `.SomeClass` or `.more.stuff` - return '(?=\\.[a-z]\\w*\\b(?!\\.))' - elif len(self.children) == 1: - child_key, child = next(self.children.iteritems()) - child_re = child._build_re(child_key) - if child_key != '*': - child_re = '\\.' + child_re - if self.present: - return key + '(' + child_re + ')?' - else: - return key + child_re - elif self.children: - children_re = '(?:' + '|'.join( - ('\\.' if k != '*' else '') + self.children[k]._build_re(k) - for k in sorted(self.children.keys())) + ')' - if self.present: - return key + children_re + '?' - else: - return key + children_re - else: - assert self.present - return key - - def build_re(self, key): - return re.compile('\\b' + self._build_re(key) + '\\b') - - -def ifind(*paths): - """ifind is an iterative version of os.walk, yielding all walked paths and - normalizing paths to use forward slashes.""" - for path in paths: - for dirpath, dirnames, names in os.walk(path): - for name in names: - if os.sep == '/': - yield os.path.join(dirpath, name) - else: - yield '/'.join(dirpath.split(os.sep) + [name]) - - -def _strip_comments(lines): - # FIXME this is a horribe hack, we should use a proper JavaScript parser - # here - in_multiline_comment = False - lineno = 0 - for line in lines: - lineno += 1 - if in_multiline_comment: - index = line.find('*/') - if index != -1: - in_multiline_comment = False - line = line[index + 2:] - if not in_multiline_comment: - line = re.sub(r'//[^\n]*', '', line) - line = re.sub(r'/\*.*?\*/', '', line) - index = line.find('/*') - if index != -1: - yield lineno, line[:index] - in_multiline_comment = True - else: - yield lineno, line - - -def check_requires(closure_lib, *filenames): - unused_count = 0 - all_provides = set() - - for filename in ifind(closure_lib): - if filename.endswith('.js'): - if not re.match(r'.*/closure/goog/', filename): - continue - # Skip goog.i18n because it contains so many modules that it causes - # the generated regular expression to exceed Python's limits - if re.match(r'.*/closure/goog/i18n/', filename): - continue - for line in open(filename, 'rU'): - m = re.match(r'goog.provide\(\'(.*)\'\);', line) - if m: - all_provides.add(m.group(1)) - - for filename in sorted(filenames): - require_linenos = {} - uses = set() - lines = open(filename, 'rU').readlines() - for lineno, line in _strip_comments(lines): - m = re.match(r'goog.provide\(\'(.*)\'\);', line) - if m: - all_provides.add(m.group(1)) - continue - m = re.match(r'goog.require\(\'(.*)\'\);', line) - if m: - require_linenos[m.group(1)] = lineno - continue - ignore_linenos = require_linenos.values() - for lineno, line in enumerate(lines): - if lineno in ignore_linenos: - continue - for require in require_linenos.iterkeys(): - if require in line: - uses.add(require) - for require in sorted(set(require_linenos.keys()) - uses): - logger.info('%s:%d: unused goog.require: %r' % ( - filename, require_linenos[require], require)) - unused_count += 1 - - all_provides.discard('ol') - all_provides.discard('ol.MapProperty') - - root = Node() - for provide in all_provides: - node = root - for component in provide.split('.'): - if component not in node.children: - node.children[component] = Node() - node = node.children[component] - if component[0].islower(): - # We've arrived at a namespace provide like `ol.foo`. - # In this case, we want to match uses like `ol.foo.doIt()` but - # not match things like `new ol.foo.SomeClass()`. - # For this purpose, we use the special wildcard key for the child. - node.children['*'] = Node() - else: - node.present = True - provide_res = [child.build_re(key) - for key, child in root.children.iteritems()] - missing_count = 0 - for filename in sorted(filenames): - provides = set() - requires = set() - uses = set() - uses_linenos = {} - for lineno, line in _strip_comments(open(filename, 'rU')): - m = re.match(r'goog.provide\(\'(.*)\'\);', line) - if m: - provides.add(m.group(1)) - continue - m = re.match(r'goog.require\(\'(.*)\'\);', line) - if m: - requires.add(m.group(1)) - continue - while True: - for provide_re in provide_res: - m = provide_re.search(line) - if m: - uses.add(m.group()) - uses_linenos[m.group()] = lineno - line = line[:m.start()] + line[m.end():] - break - else: - break - if filename == 'src/ol/renderer/layerrenderer.js': - uses.discard('ol.renderer.Map') - m = re.match( - r'src/ol/renderer/(\w+)/\1(\w*)layerrenderer\.js\Z', filename) - if m: - uses.discard('ol.renderer.Map') - uses.discard('ol.renderer.%s.Map' % (m.group(1),)) - missing_requires = uses - requires - provides - if missing_requires: - for missing_require in sorted(missing_requires): - logger.info("%s:%d missing goog.require('%s')" % - (filename, uses_linenos[missing_require], - missing_require)) - missing_count += 1 - - return (unused_count, missing_count) - - -if __name__ == "__main__": - unused_count, missing_count = check_requires(*sys.argv[1:]) - if unused_count > 0 or missing_count > 0: - logger.error('%d unused goog.requires, %d missing goog.requires' % - (unused_count, missing_count)) - sys.exit(1)