Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Unified Diff: tools/metrics/actions/extract_actions.py

Issue 848453002: Improve script to find user actions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/metrics/actions/extract_actions_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/metrics/actions/extract_actions.py
diff --git a/tools/metrics/actions/extract_actions.py b/tools/metrics/actions/extract_actions.py
index c7f550f6981f20f64ba124321b25639e6387a2e0..51246b55a338a99483510bb18506dea93d61733b 100755
--- a/tools/metrics/actions/extract_actions.py
+++ b/tools/metrics/actions/extract_actions.py
@@ -14,7 +14,6 @@ there are many possible actions.
See also:
base/metrics/user_metrics.h
- http://wiki.corp.google.com/twiki/bin/view/Main/ChromeUserExperienceMetrics
After extracting all actions, the content will go through a pretty print
function to make sure it's well formatted. If the file content needs to be
@@ -42,6 +41,19 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common'))
import diff_util
import pretty_print_xml
+USER_METRICS_ACTION_RE = re.compile(r"""
+ [^a-zA-Z] # Preceded by a non-alphabetical character.
+ UserMetricsAction # Name of the function.
+ \( # Opening parenthesis.
+ \s* # Any amount of whitespace, including new lines.
+ (.+?) # A sequence of characters for the param.
+ \) # Closing parenthesis.
+ """,
+ re.VERBOSE | re.DOTALL # Verbose syntax and makes . also match new lines.
Ilya Sherman 2015/01/14 19:15:20 Why does . need to match newlines? Is this behavi
Alexei Svitkine (slow) 2015/01/14 20:28:21 No, it's whether (.+?) matches newlines. Without
Ilya Sherman 2015/01/14 23:16:45 Ah, I see -- it's important for the better error m
+)
+COMPUTED_ACTION_RE = re.compile(r'RecordComputedAction')
+QUOTED_STRING_RE = re.compile(r'\"(.+?)\"')
+
# Files that are known to use content::RecordComputedAction(), which means
# they require special handling code in this script.
# To add a new file, add it to this list and add the appropriate logic to
@@ -410,6 +422,50 @@ def AddExtensionActions(actions):
# Actions sent by 'Ok Google' Hotwording.
actions.add('Hotword.HotwordTrigger')
+def _LogWarning(message):
+ print >>sys.stderr, 'WARNING: ' + message
Ilya Sherman 2015/01/14 19:15:20 Please use logging.warning() or logging.error().
Alexei Svitkine (slow) 2015/01/14 20:28:21 Done.
+
+class InvalidStatementException(Exception):
+ """Indicates an invalid statement was found."""
+
+class ActionNameFinder:
+ """Helper class to find action names in source code file."""
+
+ def __init__(self, path, contents):
+ self.path = path
+ self.pos = 0
+ self.contents = contents
Ilya Sherman 2015/01/14 19:15:20 nit: The private vars' names should all start with
Alexei Svitkine (slow) 2015/01/14 20:28:21 Done.
+
+ def FindNextAction(self):
+ """Finds the next action name in the file.
+
+ Returns:
+ The name of the action found or None if there are no more actions.
+ Raises:
+ InvalidStatementException if the next action statement is invalid
+ and could not be parsed. There may still be more actions in the file,
+ so FindNextAction() can continue to be called to find following ones.
+ """
+ match = USER_METRICS_ACTION_RE.search(self.contents, pos=self.pos)
+ if not match:
+ return None
+ match_start = match.start()
+ self.pos = match.end()
+ match = QUOTED_STRING_RE.match(match.group(1))
+ if not match:
+ self._RaiseException(match_start, self.pos)
+ return match.group(1)
+
+ def _RaiseException(self, match_start, match_end):
+ """Raises an InvalidStatementException for the specified code range."""
+ line_number = self.contents.count('\n', 0, match_start) + 1
+ # Add 1 to |match_start| since the RE checks the preceding character.
+ statement = self.contents[match_start + 1:match_end]
+ raise InvalidStatementException(
+ '%s uses UserMetricsAction incorrectly on line %d:\n%s' %
+ (self.path, line_number, statement))
+
+
def GrepForActions(path, actions):
"""Grep a source file for calls to UserMetrics functions.
@@ -419,26 +475,24 @@ def GrepForActions(path, actions):
"""
global number_of_files_total
number_of_files_total = number_of_files_total + 1
- # we look for the UserMetricsAction structure constructor
- # this should be on one line
- action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\("([^"]*)')
- malformed_action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\([^"]')
Ilya Sherman 2015/01/14 18:48:50 Hmm, if we're now in agreement to only loosen the
Alexei Svitkine (slow) 2015/01/14 18:52:19 The old code iterates line by line, so that wouldn
Ilya Sherman 2015/01/14 19:15:20 Fair enough :)
- computed_action_re = re.compile(r'RecordComputedAction')
+
+ finder = ActionNameFinder(path, open(path).read())
+ while True:
+ try:
+ action_name = finder.FindNextAction()
Ilya Sherman 2015/01/14 19:15:20 It looks like you have dropped the line to update
Alexei Svitkine (slow) 2015/01/14 20:28:22 Ack - no, this was accidentally lost when I remove
+ if not action_name:
+ break
+ except InvalidStatementException, e:
+ _LogWarning(str(e))
+
line_number = 0
for line in open(path):
line_number = line_number + 1
- match = action_re.search(line)
- if match: # Plain call to RecordAction
- actions.add(match.group(1))
- elif malformed_action_re.search(line):
- # Warn if this line is using RecordAction incorrectly.
- print >>sys.stderr, ('WARNING: %s has malformed call to RecordAction'
- ' at %d' % (path, line_number))
- elif computed_action_re.search(line):
+ if COMPUTED_ACTION_RE.search(line):
# Warn if this file shouldn't be calling RecordComputedAction.
if os.path.basename(path) not in KNOWN_COMPUTED_USERS:
- print >>sys.stderr, ('WARNING: %s has RecordComputedAction at %d' %
- (path, line_number))
+ _LogWarning('%s has RecordComputedAction statement on line %d' %
+ (path, line_number))
class WebUIActionsParser(HTMLParser):
"""Parses an HTML file, looking for all tags with a 'metric' attribute.
« no previous file with comments | « no previous file | tools/metrics/actions/extract_actions_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698