Index: trunk/src/tools/metrics/actions/extract_actions.py |
=================================================================== |
--- trunk/src/tools/metrics/actions/extract_actions.py (revision 255402) |
+++ trunk/src/tools/metrics/actions/extract_actions.py (working copy) |
@@ -16,32 +16,20 @@ |
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 |
-changed, a window will be prompted asking for user's consent. The old version |
-will also be saved in a backup file. |
+If run with a "--hash" argument, chromeactions.txt will be updated. |
""" |
__author__ = 'evanm (Evan Martin)' |
+import hashlib |
from HTMLParser import HTMLParser |
-import logging |
import os |
import re |
-import shutil |
import sys |
-from xml.dom import minidom |
-import print_style |
- |
sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'python')) |
from google import path_utils |
-# Import the metrics/common module for pretty print xml. |
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) |
-import diff_util |
-import pretty_print_xml |
- |
# 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 |
@@ -127,12 +115,7 @@ |
number_of_files_total = 0 |
-# Tags that need to be inserted to each 'action' tag and their default content. |
-TAGS = {'description': 'Please enter the description of the metric.', |
- 'owner': ('Please list the metric\'s owners. Add more owner tags as ' |
- 'needed.')} |
- |
def AddComputedActions(actions): |
"""Add computed actions to the actions list. |
@@ -595,193 +578,28 @@ |
actions.add('AutomaticSettingsReset_WebUIBanner_ManuallyClosed') |
actions.add('AutomaticSettingsReset_WebUIBanner_LearnMoreClicked') |
- |
-class Error(Exception): |
- pass |
- |
- |
-def _ExtractText(parent_dom, tag_name): |
- """Extract the text enclosed by |tag_name| under |parent_dom| |
- |
- Args: |
- parent_dom: The parent Element under which text node is searched for. |
- tag_name: The name of the tag which contains a text node. |
- |
- Returns: |
- A (list of) string enclosed by |tag_name| under |parent_dom|. |
- """ |
- texts = [] |
- for child_dom in parent_dom.getElementsByTagName(tag_name): |
- text_dom = child_dom.childNodes |
- if text_dom.length != 1: |
- raise Error('More than 1 child node exists under %s' % tag_name) |
- if text_dom[0].nodeType != minidom.Node.TEXT_NODE: |
- raise Error('%s\'s child node is not a text node.' % tag_name) |
- texts.append(text_dom[0].data) |
- return texts |
- |
- |
-class Action(object): |
- def __init__(self, name, description, owners, obsolete=None): |
- self.name = name |
- self.description = description |
- self.owners = owners |
- self.obsolete = obsolete |
- |
- |
-def ParseActionFile(file_content): |
- """Parse the XML data currently stored in the file. |
- |
- Args: |
- file_content: a string containing the action XML file content. |
- |
- Returns: |
- (actions, actions_dict) actions is a set with all user actions' names. |
- actions_dict is a dict from user action name to Action object. |
- """ |
- dom = minidom.parseString(file_content) |
- |
- comment_nodes = [] |
- # Get top-level comments. It is assumed that all comments are placed before |
- # <acionts> tag. Therefore the loop will stop if it encounters a non-comment |
- # node. |
- for node in dom.childNodes: |
- if node.nodeType == minidom.Node.COMMENT_NODE: |
- comment_nodes.append(node) |
- else: |
- break |
- |
+def main(argv): |
+ if '--hash' in argv: |
+ hash_output = True |
+ else: |
+ hash_output = False |
+ print >>sys.stderr, "WARNING: If you added new UMA tags, you must" + \ |
+ " use the --hash option to update chromeactions.txt." |
+ # if we do a hash output, we want to only append NEW actions, and we know |
+ # the file we want to work on |
actions = set() |
- actions_dict = {} |
- # Get each user action data. |
- for action_dom in dom.getElementsByTagName('action'): |
- action_name = action_dom.getAttribute('name') |
- actions.add(action_name) |
- owners = _ExtractText(action_dom, 'owner') |
- # There is only one description for each user action. Get the first element |
- # of the returned list. |
- description_list = _ExtractText(action_dom, 'description') |
- if len(description_list) > 1: |
- logging.error('user actions "%s" has more than one descriptions. Exactly ' |
- 'one description is needed for each user action. Please ' |
- 'fix.', action_name) |
- sys.exit(1) |
- description = description_list[0] if description_list else None |
- # There is at most one obsolete tag for each user action. |
- obsolete_list = _ExtractText(action_dom, 'obsolete') |
- if len(obsolete_list) > 1: |
- logging.error('user actions "%s" has more than one obsolete tag. At most ' |
- 'one obsolete tag can be added for each user action. Please' |
- ' fix.', action_name) |
- sys.exit(1) |
- obsolete = obsolete_list[0] if obsolete_list else None |
- actions_dict[action_name] = Action(action_name, description, owners, |
- obsolete) |
- return actions, actions_dict, comment_nodes |
+ chromeactions_path = os.path.join(path_utils.ScriptDir(), "chromeactions.txt") |
+ if hash_output: |
+ f = open(chromeactions_path) |
+ for line in f: |
+ part = line.rpartition("\t") |
+ part = part[2].strip() |
+ actions.add(part) |
+ f.close() |
-def _CreateActionTag(doc, action_name, action_object): |
- """Create a new action tag. |
- Format of an action tag: |
- <action name="name"> |
- <owner>Owner</owner> |
- <description>Description.</description> |
- <obsolete>Deprecated.</obsolete> |
- </action> |
- |
- <obsolete> is an optional tag. It's added to user actions that are no longer |
- used any more. |
- |
- If action_name is in actions_dict, the values to be inserted are based on the |
- corresponding Action object. If action_name is not in actions_dict, the |
- default value from TAGS is used. |
- |
- Args: |
- doc: The document under which the new action tag is created. |
- action_name: The name of an action. |
- action_object: An action object representing the data to be inserted. |
- |
- Returns: |
- An action tag Element with proper children elements. |
- """ |
- action_dom = doc.createElement('action') |
- action_dom.setAttribute('name', action_name) |
- |
- # Create owner tag. |
- if action_object and action_object.owners: |
- # If owners for this action is not None, use the stored value. Otherwise, |
- # use the default value. |
- for owner in action_object.owners: |
- owner_dom = doc.createElement('owner') |
- owner_dom.appendChild(doc.createTextNode(owner)) |
- action_dom.appendChild(owner_dom) |
- else: |
- # Use default value. |
- owner_dom = doc.createElement('owner') |
- owner_dom.appendChild(doc.createTextNode(TAGS.get('owner', ''))) |
- action_dom.appendChild(owner_dom) |
- |
- # Create description tag. |
- description_dom = doc.createElement('description') |
- action_dom.appendChild(description_dom) |
- if action_object and action_object.description: |
- # If description for this action is not None, use the store value. |
- # Otherwise, use the default value. |
- description_dom.appendChild(doc.createTextNode( |
- action_object.description)) |
- else: |
- description_dom.appendChild(doc.createTextNode( |
- TAGS.get('description', ''))) |
- |
- # Create obsolete tag. |
- if action_object and action_object.obsolete: |
- obsolete_dom = doc.createElement('obsolete') |
- action_dom.appendChild(obsolete_dom) |
- obsolete_dom.appendChild(doc.createTextNode( |
- action_object.obsolete)) |
- |
- return action_dom |
- |
- |
-def PrettyPrint(actions, actions_dict, comment_nodes=[]): |
- """Given a list of action data, create a well-printed minidom document. |
- |
- Args: |
- actions: A list of action names. |
- actions_dict: A mappting from action name to Action object. |
- |
- Returns: |
- A well-printed minidom document that represents the input action data. |
- """ |
- doc = minidom.Document() |
- |
- # Attach top-level comments. |
- for node in comment_nodes: |
- doc.appendChild(node) |
- |
- actions_element = doc.createElement('actions') |
- doc.appendChild(actions_element) |
- |
- # Attach action node based on updated |actions|. |
- for action in sorted(actions): |
- actions_element.appendChild( |
- _CreateActionTag(doc, action, actions_dict.get(action, None))) |
- |
- return print_style.GetPrintStyle().PrettyPrintNode(doc) |
- |
- |
-def main(argv): |
- presubmit = ('--presubmit' in argv) |
- actions_xml_path = os.path.join(path_utils.ScriptDir(), 'actions.xml') |
- |
- # Save the original file content. |
- with open(actions_xml_path, 'rb') as f: |
- original_xml = f.read() |
- |
- actions, actions_dict, comment_nodes = ParseActionFile(original_xml) |
- |
AddComputedActions(actions) |
# TODO(fmantek): bring back webkit editor actions. |
# AddWebKitEditorActions(actions) |
@@ -802,28 +620,21 @@ |
AddHistoryPageActions(actions) |
AddKeySystemSupportActions(actions) |
- pretty = PrettyPrint(actions, actions_dict, comment_nodes) |
- if original_xml == pretty: |
- print 'actions.xml is correctly pretty-printed.' |
- sys.exit(0) |
- if presubmit: |
- logging.info('actions.xml is not formatted correctly; run ' |
- 'extract_actions.py to fix.') |
- sys.exit(1) |
+ if hash_output: |
+ f = open(chromeactions_path, "wb") |
- # Prompt user to consent on the change. |
- if not diff_util.PromptUserToAcceptDiff( |
- original_xml, pretty, 'Is the new version acceptable?'): |
- logging.error('Aborting') |
- sys.exit(1) |
- print 'Creating backup file: actions.old.xml.' |
- shutil.move(actions_xml_path, 'actions.old.xml') |
+ # Print out the actions as a sorted list. |
+ for action in sorted(actions): |
+ if hash_output: |
+ hash = hashlib.md5() |
+ hash.update(action) |
+ print >>f, '0x%s\t%s' % (hash.hexdigest()[:16], action) |
+ else: |
+ print action |
- with open(actions_xml_path, 'wb') as f: |
- f.write(pretty) |
- print ('Updated %s. Don\'t forget to add it to your changelist' % |
- actions_xml_path) |
+ if hash_output: |
+ print "Done. Do not forget to add chromeactions.txt to your changelist" |
return 0 |