summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py')
-rwxr-xr-xchromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py176
1 files changed, 176 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py b/chromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py
new file mode 100755
index 00000000000..fcd318f8e42
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/build/scripts/audit_runtime_enabled_features.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+
+import requests
+import re
+from in_file import InFile
+
+BRANCH_FORMAT = "https://src.chromium.org/blink/branches/chromium/%s/%s"
+TRUNK_PATH = "Source/platform/RuntimeEnabledFeatures.in"
+TRUNK_URL = "https://src.chromium.org/blink/trunk/%s" % TRUNK_PATH
+
+
+def features_path(branch):
+ # RuntimeEnabledFeatures has only existed since April 2013:
+ if branch <= 1453:
+ return None
+ # Source/core/page/RuntimeEnabledFeatures.in existed by 1547
+ # but was in an old format without status= arguments.
+ if branch <= 1547:
+ return None
+ if branch <= 1650:
+ return "Source/core/page/RuntimeEnabledFeatures.in"
+ # Modern location:
+ return TRUNK_PATH
+
+
+def parse_features_file(features_text):
+ valid_values = {
+ 'status': ['stable', 'experimental', 'test'],
+ }
+ defaults = {
+ 'condition': None,
+ 'depends_on': [],
+ 'custom': False,
+ 'status': None,
+ }
+
+ # FIXME: in_file.py manually calls str.strip so conver to str here.
+ features_lines = str(features_text).split("\n")
+ return InFile(features_lines, defaults, valid_values)
+
+
+def stable_features(in_file):
+ return [feature['name'] for feature in in_file.name_dictionaries if feature['status'] == 'stable']
+
+
+def branch_from_version(version_string):
+ # Format: 31.0.1650.63, the second digit was only ever used for M4
+ # no clue what it's actually intended for.
+ version_regexp = r"(?P<major>\d+)\.\d+\.(?P<branch>\d+)\.(?P<minor>\d+)"
+ match = re.match(version_regexp, version_string)
+ # if match == None, we'll blow up, so at least provide some debugging information:
+ if not match:
+ print version_string
+ return int(match.group('branch'))
+
+
+def print_feature_diff(added_features, removed_features):
+ for feature in added_features:
+ print "+ %s" % feature
+ for feature in removed_features:
+ print "- %s" % feature
+
+
+def historical_versions(os_string, channel):
+ url_pattern = "http://omahaproxy.appspot.com/history?os=%s&channel=%s"
+ url = url_pattern % (os_string, channel)
+ releases_csv = requests.get(url).text.strip("\n")
+ # Format: os,channel,version_string,date_string
+ lines = releases_csv.split('\n')
+ # As of June 2014, omahaproxy is now including headers:
+ assert(lines[0] == 'os,channel,version,timestamp')
+ # FIXME: We could replace this with more generic CSV parsing now that we have headers.
+ return [line.split(',')[2] for line in lines[1:]]
+
+
+def feature_file_url_for_branch(branch):
+ path = features_path(branch)
+ if not path:
+ return None
+ return BRANCH_FORMAT % (branch, path)
+
+
+def feature_file_for_branch(branch):
+ url = feature_file_url_for_branch(branch)
+ if not url:
+ return None
+ return parse_features_file(requests.get(url).text)
+
+
+def historical_feature_tuples(os_string, channel):
+ feature_tuples = []
+ version_strings = reversed(historical_versions(os_string, channel))
+ seen_branches = set()
+
+ for version in version_strings:
+ branch = branch_from_version(version)
+ if branch in seen_branches:
+ continue
+ seen_branches.add(branch)
+
+ feature_file = feature_file_for_branch(branch)
+ if not feature_file:
+ continue
+ feature_tuple = (version, feature_file)
+ feature_tuples.append(feature_tuple)
+ return feature_tuples
+
+
+class FeatureAuditor(object):
+ def __init__(self):
+ self.last_features = []
+
+ def add_version(self, version_name, feature_file):
+ features = stable_features(feature_file)
+ if self.last_features:
+ added_features = list(set(features) - set(self.last_features))
+ removed_features = list(set(self.last_features) - set(features))
+
+ print "\n%s:" % version_name
+ print_feature_diff(added_features, removed_features)
+
+ self.last_features = features
+
+
+def active_feature_tuples(os_string):
+ feature_tuples = []
+ current_releases_url = "http://omahaproxy.appspot.com/all.json"
+ trains = requests.get(current_releases_url).json()
+ train = next(train for train in trains if train['os'] == os_string)
+ # FIXME: This is depending on the ordering of the json, we could
+ # use use sorted() with true_branch, but that would put None first.
+ for version in reversed(train['versions']):
+ # FIXME: This is lame to exclude stable, the caller should
+ # ignore it if it doesn't want it.
+ if version['channel'] == 'stable':
+ continue # handled by historical_feature_tuples
+ branch = version['true_branch']
+ if branch:
+ feature_file = feature_file_for_branch(branch)
+ else:
+ feature_file = parse_features_file(requests.get(TRUNK_URL).text)
+
+ name = "%(version)s %(channel)s" % version
+ feature_tuples.append((name, feature_file))
+ return feature_tuples
+
+
+# FIXME: This only really needs feature_files.
+def stale_features(tuples):
+ last_features = None
+ can_be_removed = set()
+ for _, feature_file in tuples:
+ features = stable_features(feature_file)
+ if last_features:
+ can_be_removed.update(set(features))
+ removed_features = list(set(last_features) - set(features))
+ can_be_removed.difference_update(set(removed_features))
+ last_features = features
+ return sorted(can_be_removed)
+
+
+def main():
+ historical_tuples = historical_feature_tuples("win", "stable")
+ active_tuples = active_feature_tuples("win")
+
+ auditor = FeatureAuditor()
+ for version, feature_file in historical_tuples + active_tuples:
+ auditor.add_version(version, feature_file)
+
+ print "\nConsider for removal (have been stable for at least one release):"
+ for feature in stale_features(historical_tuples):
+ print feature
+
+
+if __name__ == "__main__":
+ main()