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..7bb727a7f434d136e6bdb30c03a527fae5b4b246 |
| --- /dev/null |
| +++ b/third_party/polymer/v1_0/find_unused_elements.py |
| @@ -0,0 +1,156 @@ |
| +#!/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. |
| + |
| +# Copyright 2015 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 pyparsing |
|
stevenjb
2016/04/29 20:34:56
Used?
michaelpg
2016/05/02 19:31:45
Done.
|
| +import re |
| +import subprocess |
| +import sys |
|
stevenjb
2016/04/29 20:34:55
Used?
michaelpg
2016/05/02 19:31:45
Done.
|
| + |
| + |
| +class UnusedElementsDetector: |
|
Dan Beam
2016/05/03 19:22:08
this should probably inherit from (object)
michaelpg
2016/05/03 21:29:19
Done.
|
| + """Finds unused Polymer elements.""" |
| + |
| + # Unused elements to ignore because we plan to use them soon. |
| + __whitelist = ( |
|
Dan Beam
2016/05/03 19:22:08
nit: I think it's more common to use 4\s indent in
Dan Beam
2016/05/03 19:22:08
nit: __WHITELIST (Class contant https://google.git
michaelpg
2016/05/03 21:29:19
Done.
michaelpg
2016/05/03 21:29:19
the examples in PEP-8 use 4 spaces (as with other
|
| + # 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. |
| + """ |
| + text = open(filename).read() |
| + return re.sub('<!--.*?-->', '', text, flags=re.MULTILINE|re.DOTALL) |
|
Dan Beam
2016/05/03 19:22:08
nit: flags=re.MULTILINE | re.DOTALL)
michaelpg
2016/05/03 21:29:19
Done. Looked weird to me inside a param=value expr
|
| + |
| + @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. |
| + """ |
| + text = open(filename).read() |
| + text = re.sub('<if .*?>', '', text) |
|
Dan Beam
2016/05/03 19:22:07
nit: case-insensitive maybe?
michaelpg
2016/05/03 21:29:19
Done.
|
| + 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) |
| + |
| + unused_elements = [] |
| + for element in elements: |
| + if element in UnusedElementsDetector.__whitelist: |
| + continue |
| + |
| + relevant_src_dirs = ( |
| + os.path.join(src_dir, 'chrome'), |
| + os.path.join(src_dir, 'ui'), |
| + os.path.join(src_dir, 'components'), |
| + components_dir |
| + ) |
| + used = False |
| + for path in relevant_src_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)): |
| + continue |
| + |
| + for filename in [f for f in filenames if f.endswith('.html') or |
| + f.endswith('.js')]: |
| + # Skip generated files that may include the element source. |
| + if filename in ('crisper.js', 'vulcanized.html'): |
| + continue |
| + |
| + text = open(os.path.join(dirpath, filename)).read() |
| + if not re.search('/%s/' % element, text): |
| + continue |
| + |
| + # Check the file again, ignoring comments (e.g. example imports and |
| + # scripts). |
| + if re.search( |
| + '/%s' % element, |
|
stevenjb
2016/04/29 20:34:56
My python formatting fu is weak, but I suspect thi
michaelpg
2016/05/02 19:31:45
Done (both are valid, but your way looks better)
|
| + UnusedElementsDetector.__StripComments( |
| + os.path.join(dirpath, filename))): |
| + used = True |
| + break |
| + if used: |
| + break |
| + if used: |
| + break |
|
stevenjb
2016/04/29 20:34:55
This would be more readable if the entire for loop
michaelpg
2016/05/02 19:31:45
Meant to do that, forgot, done now. Thanks!
|
| + if not used: |
| + unused_elements.append(element) |
| + |
| + if len(unused_elements): |
| + 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__)) |
| + |
| + |
| +UnusedElementsDetector.Run() |
|
Dan Beam
2016/05/03 19:22:07
if __name__ == '__main__':
UnusedElementDetector
michaelpg
2016/05/03 21:29:19
Done.
|