source: node_modules/node-gyp/gyp/tools/pretty_vcproj.py@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 10.4 KB
Line 
1#!/usr/bin/env python3
2
3# Copyright (c) 2012 Google Inc. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Make the format of a vcproj really pretty.
8
9 This script normalize and sort an xml. It also fetches all the properties
10 inside linked vsprops and include them explicitly in the vcproj.
11
12 It outputs the resulting xml to stdout.
13"""
14
15
16import os
17import sys
18
19from xml.dom.minidom import parse
20from xml.dom.minidom import Node
21
22__author__ = "nsylvain (Nicolas Sylvain)"
23ARGUMENTS = None
24REPLACEMENTS = dict()
25
26
27def cmp(x, y):
28 return (x > y) - (x < y)
29
30
31class CmpTuple:
32 """Compare function between 2 tuple."""
33
34 def __call__(self, x, y):
35 return cmp(x[0], y[0])
36
37
38class CmpNode:
39 """Compare function between 2 xml nodes."""
40
41 def __call__(self, x, y):
42 def get_string(node):
43 node_string = "node"
44 node_string += node.nodeName
45 if node.nodeValue:
46 node_string += node.nodeValue
47
48 if node.attributes:
49 # We first sort by name, if present.
50 node_string += node.getAttribute("Name")
51
52 all_nodes = []
53 for (name, value) in node.attributes.items():
54 all_nodes.append((name, value))
55
56 all_nodes.sort(CmpTuple())
57 for (name, value) in all_nodes:
58 node_string += name
59 node_string += value
60
61 return node_string
62
63 return cmp(get_string(x), get_string(y))
64
65
66def PrettyPrintNode(node, indent=0):
67 if node.nodeType == Node.TEXT_NODE:
68 if node.data.strip():
69 print("{}{}".format(" " * indent, node.data.strip()))
70 return
71
72 if node.childNodes:
73 node.normalize()
74 # Get the number of attributes
75 attr_count = 0
76 if node.attributes:
77 attr_count = node.attributes.length
78
79 # Print the main tag
80 if attr_count == 0:
81 print("{}<{}>".format(" " * indent, node.nodeName))
82 else:
83 print("{}<{}".format(" " * indent, node.nodeName))
84
85 all_attributes = []
86 for (name, value) in node.attributes.items():
87 all_attributes.append((name, value))
88 all_attributes.sort(CmpTuple())
89 for (name, value) in all_attributes:
90 print('{} {}="{}"'.format(" " * indent, name, value))
91 print("%s>" % (" " * indent))
92 if node.nodeValue:
93 print("{} {}".format(" " * indent, node.nodeValue))
94
95 for sub_node in node.childNodes:
96 PrettyPrintNode(sub_node, indent=indent + 2)
97 print("{}</{}>".format(" " * indent, node.nodeName))
98
99
100def FlattenFilter(node):
101 """Returns a list of all the node and sub nodes."""
102 node_list = []
103
104 if node.attributes and node.getAttribute("Name") == "_excluded_files":
105 # We don't add the "_excluded_files" filter.
106 return []
107
108 for current in node.childNodes:
109 if current.nodeName == "Filter":
110 node_list.extend(FlattenFilter(current))
111 else:
112 node_list.append(current)
113
114 return node_list
115
116
117def FixFilenames(filenames, current_directory):
118 new_list = []
119 for filename in filenames:
120 if filename:
121 for key in REPLACEMENTS:
122 filename = filename.replace(key, REPLACEMENTS[key])
123 os.chdir(current_directory)
124 filename = filename.strip("\"' ")
125 if filename.startswith("$"):
126 new_list.append(filename)
127 else:
128 new_list.append(os.path.abspath(filename))
129 return new_list
130
131
132def AbsoluteNode(node):
133 """Makes all the properties we know about in this node absolute."""
134 if node.attributes:
135 for (name, value) in node.attributes.items():
136 if name in [
137 "InheritedPropertySheets",
138 "RelativePath",
139 "AdditionalIncludeDirectories",
140 "IntermediateDirectory",
141 "OutputDirectory",
142 "AdditionalLibraryDirectories",
143 ]:
144 # We want to fix up these paths
145 path_list = value.split(";")
146 new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
147 node.setAttribute(name, ";".join(new_list))
148 if not value:
149 node.removeAttribute(name)
150
151
152def CleanupVcproj(node):
153 """For each sub node, we call recursively this function."""
154 for sub_node in node.childNodes:
155 AbsoluteNode(sub_node)
156 CleanupVcproj(sub_node)
157
158 # Normalize the node, and remove all extraneous whitespaces.
159 for sub_node in node.childNodes:
160 if sub_node.nodeType == Node.TEXT_NODE:
161 sub_node.data = sub_node.data.replace("\r", "")
162 sub_node.data = sub_node.data.replace("\n", "")
163 sub_node.data = sub_node.data.rstrip()
164
165 # Fix all the semicolon separated attributes to be sorted, and we also
166 # remove the dups.
167 if node.attributes:
168 for (name, value) in node.attributes.items():
169 sorted_list = sorted(value.split(";"))
170 unique_list = []
171 for i in sorted_list:
172 if not unique_list.count(i):
173 unique_list.append(i)
174 node.setAttribute(name, ";".join(unique_list))
175 if not value:
176 node.removeAttribute(name)
177
178 if node.childNodes:
179 node.normalize()
180
181 # For each node, take a copy, and remove it from the list.
182 node_array = []
183 while node.childNodes and node.childNodes[0]:
184 # Take a copy of the node and remove it from the list.
185 current = node.childNodes[0]
186 node.removeChild(current)
187
188 # If the child is a filter, we want to append all its children
189 # to this same list.
190 if current.nodeName == "Filter":
191 node_array.extend(FlattenFilter(current))
192 else:
193 node_array.append(current)
194
195 # Sort the list.
196 node_array.sort(CmpNode())
197
198 # Insert the nodes in the correct order.
199 for new_node in node_array:
200 # But don't append empty tool node.
201 if new_node.nodeName == "Tool":
202 if new_node.attributes and new_node.attributes.length == 1:
203 # This one was empty.
204 continue
205 if new_node.nodeName == "UserMacro":
206 continue
207 node.appendChild(new_node)
208
209
210def GetConfiguationNodes(vcproj):
211 # TODO(nsylvain): Find a better way to navigate the xml.
212 nodes = []
213 for node in vcproj.childNodes:
214 if node.nodeName == "Configurations":
215 for sub_node in node.childNodes:
216 if sub_node.nodeName == "Configuration":
217 nodes.append(sub_node)
218
219 return nodes
220
221
222def GetChildrenVsprops(filename):
223 dom = parse(filename)
224 if dom.documentElement.attributes:
225 vsprops = dom.documentElement.getAttribute("InheritedPropertySheets")
226 return FixFilenames(vsprops.split(";"), os.path.dirname(filename))
227 return []
228
229
230def SeekToNode(node1, child2):
231 # A text node does not have properties.
232 if child2.nodeType == Node.TEXT_NODE:
233 return None
234
235 # Get the name of the current node.
236 current_name = child2.getAttribute("Name")
237 if not current_name:
238 # There is no name. We don't know how to merge.
239 return None
240
241 # Look through all the nodes to find a match.
242 for sub_node in node1.childNodes:
243 if sub_node.nodeName == child2.nodeName:
244 name = sub_node.getAttribute("Name")
245 if name == current_name:
246 return sub_node
247
248 # No match. We give up.
249 return None
250
251
252def MergeAttributes(node1, node2):
253 # No attributes to merge?
254 if not node2.attributes:
255 return
256
257 for (name, value2) in node2.attributes.items():
258 # Don't merge the 'Name' attribute.
259 if name == "Name":
260 continue
261 value1 = node1.getAttribute(name)
262 if value1:
263 # The attribute exist in the main node. If it's equal, we leave it
264 # untouched, otherwise we concatenate it.
265 if value1 != value2:
266 node1.setAttribute(name, ";".join([value1, value2]))
267 else:
268 # The attribute does not exist in the main node. We append this one.
269 node1.setAttribute(name, value2)
270
271 # If the attribute was a property sheet attributes, we remove it, since
272 # they are useless.
273 if name == "InheritedPropertySheets":
274 node1.removeAttribute(name)
275
276
277def MergeProperties(node1, node2):
278 MergeAttributes(node1, node2)
279 for child2 in node2.childNodes:
280 child1 = SeekToNode(node1, child2)
281 if child1:
282 MergeProperties(child1, child2)
283 else:
284 node1.appendChild(child2.cloneNode(True))
285
286
287def main(argv):
288 """Main function of this vcproj prettifier."""
289 global ARGUMENTS
290 ARGUMENTS = argv
291
292 # check if we have exactly 1 parameter.
293 if len(argv) < 2:
294 print(
295 'Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
296 "[key2=value2]" % argv[0]
297 )
298 return 1
299
300 # Parse the keys
301 for i in range(2, len(argv)):
302 (key, value) = argv[i].split("=")
303 REPLACEMENTS[key] = value
304
305 # Open the vcproj and parse the xml.
306 dom = parse(argv[1])
307
308 # First thing we need to do is find the Configuration Node and merge them
309 # with the vsprops they include.
310 for configuration_node in GetConfiguationNodes(dom.documentElement):
311 # Get the property sheets associated with this configuration.
312 vsprops = configuration_node.getAttribute("InheritedPropertySheets")
313
314 # Fix the filenames to be absolute.
315 vsprops_list = FixFilenames(
316 vsprops.strip().split(";"), os.path.dirname(argv[1])
317 )
318
319 # Extend the list of vsprops with all vsprops contained in the current
320 # vsprops.
321 for current_vsprops in vsprops_list:
322 vsprops_list.extend(GetChildrenVsprops(current_vsprops))
323
324 # Now that we have all the vsprops, we need to merge them.
325 for current_vsprops in vsprops_list:
326 MergeProperties(configuration_node, parse(current_vsprops).documentElement)
327
328 # Now that everything is merged, we need to cleanup the xml.
329 CleanupVcproj(dom.documentElement)
330
331 # Finally, we use the prett xml function to print the vcproj back to the
332 # user.
333 # print dom.toprettyxml(newl="\n")
334 PrettyPrintNode(dom.documentElement)
335 return 0
336
337
338if __name__ == "__main__":
339 sys.exit(main(sys.argv))
Note: See TracBrowser for help on using the repository browser.