| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 | 
							- #!/usr/bin/env python
 
- # Copyright (c) 2012 Google Inc. All rights reserved.
 
- # Use of this source code is governed by a BSD-style license that can be
 
- # found in the LICENSE file.
 
- """Make the format of a vcproj really pretty.
 
-    This script normalize and sort an xml. It also fetches all the properties
 
-    inside linked vsprops and include them explicitly in the vcproj.
 
-    It outputs the resulting xml to stdout.
 
- """
 
- __author__ = 'nsylvain (Nicolas Sylvain)'
 
- import os
 
- import sys
 
- from xml.dom.minidom import parse
 
- from xml.dom.minidom import Node
 
- REPLACEMENTS = dict()
 
- ARGUMENTS = None
 
- class CmpTuple(object):
 
-   """Compare function between 2 tuple."""
 
-   def __call__(self, x, y):
 
-     return cmp(x[0], y[0])
 
- class CmpNode(object):
 
-   """Compare function between 2 xml nodes."""
 
-   def __call__(self, x, y):
 
-     def get_string(node):
 
-       node_string = "node"
 
-       node_string += node.nodeName
 
-       if node.nodeValue:
 
-         node_string += node.nodeValue
 
-       if node.attributes:
 
-         # We first sort by name, if present.
 
-         node_string += node.getAttribute("Name")
 
-         all_nodes = []
 
-         for (name, value) in node.attributes.items():
 
-           all_nodes.append((name, value))
 
-         all_nodes.sort(CmpTuple())
 
-         for (name, value) in all_nodes:
 
-           node_string += name
 
-           node_string += value
 
-       return node_string
 
-     return cmp(get_string(x), get_string(y))
 
- def PrettyPrintNode(node, indent=0):
 
-   if node.nodeType == Node.TEXT_NODE:
 
-     if node.data.strip():
 
-       print '%s%s' % (' '*indent, node.data.strip())
 
-     return
 
-   if node.childNodes:
 
-     node.normalize()
 
-   # Get the number of attributes
 
-   attr_count = 0
 
-   if node.attributes:
 
-     attr_count = node.attributes.length
 
-   # Print the main tag
 
-   if attr_count == 0:
 
-     print '%s<%s>' % (' '*indent, node.nodeName)
 
-   else:
 
-     print '%s<%s' % (' '*indent, node.nodeName)
 
-     all_attributes = []
 
-     for (name, value) in node.attributes.items():
 
-       all_attributes.append((name, value))
 
-       all_attributes.sort(CmpTuple())
 
-     for (name, value) in all_attributes:
 
-       print '%s  %s="%s"' % (' '*indent, name, value)
 
-     print '%s>' % (' '*indent)
 
-   if node.nodeValue:
 
-     print '%s  %s' % (' '*indent, node.nodeValue)
 
-   for sub_node in node.childNodes:
 
-     PrettyPrintNode(sub_node, indent=indent+2)
 
-   print '%s</%s>' % (' '*indent, node.nodeName)
 
- def FlattenFilter(node):
 
-   """Returns a list of all the node and sub nodes."""
 
-   node_list = []
 
-   if (node.attributes and
 
-       node.getAttribute('Name') == '_excluded_files'):
 
-       # We don't add the "_excluded_files" filter.
 
-     return []
 
-   for current in node.childNodes:
 
-     if current.nodeName == 'Filter':
 
-       node_list.extend(FlattenFilter(current))
 
-     else:
 
-       node_list.append(current)
 
-   return node_list
 
- def FixFilenames(filenames, current_directory):
 
-   new_list = []
 
-   for filename in filenames:
 
-     if filename:
 
-       for key in REPLACEMENTS:
 
-         filename = filename.replace(key, REPLACEMENTS[key])
 
-       os.chdir(current_directory)
 
-       filename = filename.strip('"\' ')
 
-       if filename.startswith('$'):
 
-         new_list.append(filename)
 
-       else:
 
-         new_list.append(os.path.abspath(filename))
 
-   return new_list
 
- def AbsoluteNode(node):
 
-   """Makes all the properties we know about in this node absolute."""
 
-   if node.attributes:
 
-     for (name, value) in node.attributes.items():
 
-       if name in ['InheritedPropertySheets', 'RelativePath',
 
-                   'AdditionalIncludeDirectories',
 
-                   'IntermediateDirectory', 'OutputDirectory',
 
-                   'AdditionalLibraryDirectories']:
 
-         # We want to fix up these paths
 
-         path_list = value.split(';')
 
-         new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
 
-         node.setAttribute(name, ';'.join(new_list))
 
-       if not value:
 
-         node.removeAttribute(name)
 
- def CleanupVcproj(node):
 
-   """For each sub node, we call recursively this function."""
 
-   for sub_node in node.childNodes:
 
-     AbsoluteNode(sub_node)
 
-     CleanupVcproj(sub_node)
 
-   # Normalize the node, and remove all extranous whitespaces.
 
-   for sub_node in node.childNodes:
 
-     if sub_node.nodeType == Node.TEXT_NODE:
 
-       sub_node.data = sub_node.data.replace("\r", "")
 
-       sub_node.data = sub_node.data.replace("\n", "")
 
-       sub_node.data = sub_node.data.rstrip()
 
-   # Fix all the semicolon separated attributes to be sorted, and we also
 
-   # remove the dups.
 
-   if node.attributes:
 
-     for (name, value) in node.attributes.items():
 
-       sorted_list = sorted(value.split(';'))
 
-       unique_list = []
 
-       for i in sorted_list:
 
-         if not unique_list.count(i):
 
-           unique_list.append(i)
 
-       node.setAttribute(name, ';'.join(unique_list))
 
-       if not value:
 
-         node.removeAttribute(name)
 
-   if node.childNodes:
 
-     node.normalize()
 
-   # For each node, take a copy, and remove it from the list.
 
-   node_array = []
 
-   while node.childNodes and node.childNodes[0]:
 
-     # Take a copy of the node and remove it from the list.
 
-     current = node.childNodes[0]
 
-     node.removeChild(current)
 
-     # If the child is a filter, we want to append all its children
 
-     # to this same list.
 
-     if current.nodeName == 'Filter':
 
-       node_array.extend(FlattenFilter(current))
 
-     else:
 
-       node_array.append(current)
 
-   # Sort the list.
 
-   node_array.sort(CmpNode())
 
-   # Insert the nodes in the correct order.
 
-   for new_node in node_array:
 
-     # But don't append empty tool node.
 
-     if new_node.nodeName == 'Tool':
 
-       if new_node.attributes and new_node.attributes.length == 1:
 
-         # This one was empty.
 
-         continue
 
-     if new_node.nodeName == 'UserMacro':
 
-       continue
 
-     node.appendChild(new_node)
 
- def GetConfiguationNodes(vcproj):
 
-   #TODO(nsylvain): Find a better way to navigate the xml.
 
-   nodes = []
 
-   for node in vcproj.childNodes:
 
-     if node.nodeName == "Configurations":
 
-       for sub_node in node.childNodes:
 
-         if sub_node.nodeName == "Configuration":
 
-           nodes.append(sub_node)
 
-   return nodes
 
- def GetChildrenVsprops(filename):
 
-   dom = parse(filename)
 
-   if dom.documentElement.attributes:
 
-     vsprops = dom.documentElement.getAttribute('InheritedPropertySheets')
 
-     return FixFilenames(vsprops.split(';'), os.path.dirname(filename))
 
-   return []
 
- def SeekToNode(node1, child2):
 
-   # A text node does not have properties.
 
-   if child2.nodeType == Node.TEXT_NODE:
 
-     return None
 
-   # Get the name of the current node.
 
-   current_name = child2.getAttribute("Name")
 
-   if not current_name:
 
-     # There is no name. We don't know how to merge.
 
-     return None
 
-   # Look through all the nodes to find a match.
 
-   for sub_node in node1.childNodes:
 
-     if sub_node.nodeName == child2.nodeName:
 
-       name = sub_node.getAttribute("Name")
 
-       if name == current_name:
 
-         return sub_node
 
-   # No match. We give up.
 
-   return None
 
- def MergeAttributes(node1, node2):
 
-   # No attributes to merge?
 
-   if not node2.attributes:
 
-     return
 
-   for (name, value2) in node2.attributes.items():
 
-     # Don't merge the 'Name' attribute.
 
-     if name == 'Name':
 
-       continue
 
-     value1 = node1.getAttribute(name)
 
-     if value1:
 
-       # The attribute exist in the main node. If it's equal, we leave it
 
-       # untouched, otherwise we concatenate it.
 
-       if value1 != value2:
 
-         node1.setAttribute(name, ';'.join([value1, value2]))
 
-     else:
 
-       # The attribute does nto exist in the main node. We append this one.
 
-       node1.setAttribute(name, value2)
 
-     # If the attribute was a property sheet attributes, we remove it, since
 
-     # they are useless.
 
-     if name == 'InheritedPropertySheets':
 
-       node1.removeAttribute(name)
 
- def MergeProperties(node1, node2):
 
-   MergeAttributes(node1, node2)
 
-   for child2 in node2.childNodes:
 
-     child1 = SeekToNode(node1, child2)
 
-     if child1:
 
-       MergeProperties(child1, child2)
 
-     else:
 
-       node1.appendChild(child2.cloneNode(True))
 
- def main(argv):
 
-   """Main function of this vcproj prettifier."""
 
-   global ARGUMENTS
 
-   ARGUMENTS = argv
 
-   # check if we have exactly 1 parameter.
 
-   if len(argv) < 2:
 
-     print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
 
-            '[key2=value2]' % argv[0])
 
-     return 1
 
-   # Parse the keys
 
-   for i in range(2, len(argv)):
 
-     (key, value) = argv[i].split('=')
 
-     REPLACEMENTS[key] = value
 
-   # Open the vcproj and parse the xml.
 
-   dom = parse(argv[1])
 
-   # First thing we need to do is find the Configuration Node and merge them
 
-   # with the vsprops they include.
 
-   for configuration_node in GetConfiguationNodes(dom.documentElement):
 
-     # Get the property sheets associated with this configuration.
 
-     vsprops = configuration_node.getAttribute('InheritedPropertySheets')
 
-     # Fix the filenames to be absolute.
 
-     vsprops_list = FixFilenames(vsprops.strip().split(';'),
 
-                                 os.path.dirname(argv[1]))
 
-     # Extend the list of vsprops with all vsprops contained in the current
 
-     # vsprops.
 
-     for current_vsprops in vsprops_list:
 
-       vsprops_list.extend(GetChildrenVsprops(current_vsprops))
 
-     # Now that we have all the vsprops, we need to merge them.
 
-     for current_vsprops in vsprops_list:
 
-       MergeProperties(configuration_node,
 
-                       parse(current_vsprops).documentElement)
 
-   # Now that everything is merged, we need to cleanup the xml.
 
-   CleanupVcproj(dom.documentElement)
 
-   # Finally, we use the prett xml function to print the vcproj back to the
 
-   # user.
 
-   #print dom.toprettyxml(newl="\n")
 
-   PrettyPrintNode(dom.documentElement)
 
-   return 0
 
- if __name__ == '__main__':
 
-   sys.exit(main(sys.argv))
 
 
  |