Chromium Code Reviews| Index: third_party/polymer/v1_0/find_unused_elements.py |
| diff --git a/third_party/polymer/v1_0/find_unused_elements.py b/third_party/polymer/v1_0/find_unused_elements.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..58999937f520387d0e8f1d5d0c83f3d036168e48 |
| --- /dev/null |
| +++ b/third_party/polymer/v1_0/find_unused_elements.py |
| @@ -0,0 +1,165 @@ |
| +#!/usr/bin/python2 |
| + |
| +# Copyright 2016 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""Identifies Polymer elements that downloaded but not used by Chrome. |
| + |
| +Only finds "first-order" unused elements; re-run after removing unused elements |
| +to check if other elements have become unused. |
| +""" |
| + |
| +import os |
| +import re |
| +import subprocess |
| + |
| + |
| +class UnusedElementsDetector: |
| + """Finds unused Polymer elements.""" |
| + |
| + # Unused elements to ignore because we plan to use them soon. |
| + __whitelist = ( |
| + # TODO(dschuyler): Use element or remove from whitelist. |
| + 'carbon-route', |
| + # TODO(tsergeant): Use element or remove from whitelist. |
| + 'iron-scroll-threshold', |
| + # Necessary for closure. |
| + 'polymer-externs', |
| + ) |
| + |
| + @staticmethod |
| + def __StripHtmlComments(filename): |
| + """Returns the contents of an HTML file with <!-- --> comments stripped. |
| + |
| + Not a real parser. |
| + |
| + Args: |
| + filename: The name of the file to read. |
| + |
| + Returns: |
| + A string consisting of the file contents with comments removed. |
| + """ |
| + with open(filename) as f: |
| + return re.sub('<!--.*?-->', '', f.read(), flags=re.MULTILINE|re.DOTALL) |
| + |
| + @staticmethod |
| + def __StripJsComments(filename): |
| + """Returns the minified contents of a JavaScript file with comments and |
| + grit directives removed. |
| + |
| + Args: |
| + filename: The name of the file to read. |
| + |
| + Returns: |
| + A string consisting of the minified file contents with comments and grit |
| + directives removed. |
| + """ |
| + with open(filename) as f: |
| + text = f.read() |
| + text = re.sub('<if .*?>', '', text) |
| + text = re.sub('</if>', '', text) |
| + |
| + proc = subprocess.Popen(['uglifyjs', filename], stdout=subprocess.PIPE) |
| + return proc.stdout.read() |
| + |
| + @staticmethod |
| + def __StripComments(filename): |
| + """Returns the contents of a JavaScript or HTML file with comments removed. |
| + |
| + Args: |
| + filename: The name of the file to read. |
| + |
| + Returns: |
| + A string consisting of the file contents processed via |
| + __StripHtmlComments or __StripJsComments. |
| + """ |
| + if filename.endswith('.html'): |
| + text = UnusedElementsDetector.__StripHtmlComments(filename) |
| + elif filename.endswith('.js'): |
| + text = UnusedElementsDetector.__StripJsComments(filename) |
| + else: |
| + assert False, 'Invalid filename: %s' % filename |
| + return text |
| + |
| + @staticmethod |
| + def Run(): |
| + """Finds unused Polymer elements and prints a summary.""" |
| + proc = subprocess.Popen( |
| + ['git', 'rev-parse', '--show-toplevel'], |
| + stdout=subprocess.PIPE) |
| + src_dir = proc.stdout.read().strip() |
| + polymer_dir = os.path.dirname(os.path.realpath(__file__)) |
| + components_dir = os.path.join(polymer_dir, 'components-chromium') |
| + |
| + elements = [] |
| + for name in os.listdir(components_dir): |
| + path = os.path.join(components_dir, name) |
| + if os.path.isdir(path): |
| + elements.append(name) |
| + |
| + relevant_src_dirs = ( |
| + os.path.join(src_dir, 'chrome'), |
| + os.path.join(src_dir, 'ui'), |
| + os.path.join(src_dir, 'components'), |
| + components_dir |
| + ) |
| + |
| + for element in elements: |
| + if element in UnusedElementsDetector.__whitelist: |
| + continue |
|
Dan Beam
2016/05/03 19:22:08
what does this do?
michaelpg
2016/05/03 21:29:19
removed
|
| + |
| + unused_elements = [] |
| + for element in elements: |
| + if (element not in UnusedElementsDetector.__whitelist and |
| + not UnusedElementsDetector.__IsImported(element, relevant_src_dirs)): |
| + unused_elements.append(element) |
| + |
| + if len(unused_elements): |
|
Dan Beam
2016/05/03 19:22:08
i think this can be just
if unused_elements:
michaelpg
2016/05/03 21:29:19
Done.
|
| + print 'Found unused elements: %s\nRemove from bower.json and re-run ' \ |
| + 'reproduce.sh, or add to whitelist in %s' % ( |
| + ', '.join(unused_elements), os.path.basename(__file__)) |
| + |
| + @staticmethod |
| + def __IsImported(element_dir, dirs): |
| + """Returns whether the element directory is used in HTML or JavaScript. |
| + |
| + Args: |
| + element_dir: The name of the element's directory. |
| + dirs: The directories in which to check for usage. |
| + |
| + Returns: |
| + True if the element's directory is used in |dirs|. |
| + """ |
| + polymer_dir = os.path.dirname(os.path.realpath(__file__)) |
| + components_dir = os.path.join(polymer_dir, 'components-chromium') |
| + for path in dirs: |
| + # Find an import or script referencing the tag's directory. |
| + for (dirpath, _, filenames) in os.walk(path): |
| + # Ignore the element's own files. |
| + if dirpath.startswith(os.path.join(components_dir, element_dir)): |
| + continue |
| + |
| + for filename in filenames: |
| + if not filename.endswith('.html') and not filename.endswith('.js'): |
| + continue |
| + |
| + # Skip generated files that may include the element source. |
| + if filename in ('crisper.js', 'vulcanized.html'): |
| + continue |
| + |
| + with open(os.path.join(dirpath, filename)) as f: |
| + text = f.read() |
| + if not re.search('/%s/' % element_dir, text): |
| + continue |
| + |
| + # Check the file again, ignoring comments (e.g. example imports and |
| + # scripts). |
| + if re.search('/%s' % element_dir, |
| + UnusedElementsDetector.__StripComments( |
| + os.path.join(dirpath, filename))): |
| + return True |
| + return False |
| + |
| + |
| +UnusedElementsDetector.Run() |