initial import
[vuplus_webkit] / Source / ThirdParty / gyp / pylib / gyp / MSVSProject.py
1 #!/usr/bin/python2.4
2
3 # Copyright (c) 2009 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 """Visual Studio project reader/writer."""
8
9 import common
10 import xml.dom
11 import xml_fix
12
13 #------------------------------------------------------------------------------
14
15
16 class Tool(object):
17   """Visual Studio tool."""
18
19   def __init__(self, name, attrs=None):
20     """Initializes the tool.
21
22     Args:
23       name: Tool name.
24       attrs: Dict of tool attributes; may be None.
25     """
26     self.name = name
27     self.attrs = attrs or {}
28
29   def CreateElement(self, doc):
30     """Creates an element for the tool.
31
32     Args:
33       doc: xml.dom.Document object to use for node creation.
34
35     Returns:
36       A new xml.dom.Element for the tool.
37     """
38     node = doc.createElement('Tool')
39     node.setAttribute('Name', self.name)
40     for k, v in self.attrs.items():
41       node.setAttribute(k, v)
42     return node
43
44
45 class Filter(object):
46   """Visual Studio filter - that is, a virtual folder."""
47
48   def __init__(self, name, contents=None):
49     """Initializes the folder.
50
51     Args:
52       name: Filter (folder) name.
53       contents: List of filenames and/or Filter objects contained.
54     """
55     self.name = name
56     self.contents = list(contents or [])
57
58
59 #------------------------------------------------------------------------------
60
61
62 class Writer(object):
63   """Visual Studio XML project writer."""
64
65   def __init__(self, project_path, version):
66     """Initializes the project.
67
68     Args:
69       project_path: Path to the project file.
70       version: Format version to emit.
71     """
72     self.project_path = project_path
73     self.doc = None
74     self.version = version
75
76   def Create(self, name, guid=None, platforms=None):
77     """Creates the project document.
78
79     Args:
80       name: Name of the project.
81       guid: GUID to use for project, if not None.
82     """
83     self.name = name
84     self.guid = guid
85
86     # Default to Win32 for platforms.
87     if not platforms:
88       platforms = ['Win32']
89
90     # Create XML doc
91     xml_impl = xml.dom.getDOMImplementation()
92     self.doc = xml_impl.createDocument(None, 'VisualStudioProject', None)
93
94     # Add attributes to root element
95     self.n_root = self.doc.documentElement
96     self.n_root.setAttribute('ProjectType', 'Visual C++')
97     self.n_root.setAttribute('Version', self.version.ProjectVersion())
98     self.n_root.setAttribute('Name', self.name)
99     self.n_root.setAttribute('ProjectGUID', self.guid)
100     self.n_root.setAttribute('RootNamespace', self.name)
101     self.n_root.setAttribute('Keyword', 'Win32Proj')
102
103     # Add platform list
104     n_platform = self.doc.createElement('Platforms')
105     self.n_root.appendChild(n_platform)
106     for platform in platforms:
107       n = self.doc.createElement('Platform')
108       n.setAttribute('Name', platform)
109       n_platform.appendChild(n)
110
111     # Add tool files section
112     self.n_tool_files = self.doc.createElement('ToolFiles')
113     self.n_root.appendChild(self.n_tool_files)
114
115     # Add configurations section
116     self.n_configs = self.doc.createElement('Configurations')
117     self.n_root.appendChild(self.n_configs)
118
119     # Add empty References section
120     self.n_root.appendChild(self.doc.createElement('References'))
121
122     # Add files section
123     self.n_files = self.doc.createElement('Files')
124     self.n_root.appendChild(self.n_files)
125     # Keep a dict keyed on filename to speed up access.
126     self.n_files_dict = dict()
127
128     # Add empty Globals section
129     self.n_root.appendChild(self.doc.createElement('Globals'))
130
131   def AddToolFile(self, path):
132     """Adds a tool file to the project.
133
134     Args:
135       path: Relative path from project to tool file.
136     """
137     n_tool = self.doc.createElement('ToolFile')
138     n_tool.setAttribute('RelativePath', path)
139     self.n_tool_files.appendChild(n_tool)
140
141   def _AddConfigToNode(self, parent, config_type, config_name, attrs=None,
142                        tools=None):
143     """Adds a configuration to the parent node.
144
145     Args:
146       parent: Destination node.
147       config_type: Type of configuration node.
148       config_name: Configuration name.
149       attrs: Dict of configuration attributes; may be None.
150       tools: List of tools (strings or Tool objects); may be None.
151     """
152     # Handle defaults
153     if not attrs:
154       attrs = {}
155     if not tools:
156       tools = []
157
158     # Add configuration node and its attributes
159     n_config = self.doc.createElement(config_type)
160     n_config.setAttribute('Name', config_name)
161     for k, v in attrs.items():
162       n_config.setAttribute(k, v)
163     parent.appendChild(n_config)
164
165     # Add tool nodes and their attributes
166     if tools:
167       for t in tools:
168         if isinstance(t, Tool):
169           n_config.appendChild(t.CreateElement(self.doc))
170         else:
171           n_config.appendChild(Tool(t).CreateElement(self.doc))
172
173   def AddConfig(self, name, attrs=None, tools=None):
174     """Adds a configuration to the project.
175
176     Args:
177       name: Configuration name.
178       attrs: Dict of configuration attributes; may be None.
179       tools: List of tools (strings or Tool objects); may be None.
180     """
181     self._AddConfigToNode(self.n_configs, 'Configuration', name, attrs, tools)
182
183   def _AddFilesToNode(self, parent, files):
184     """Adds files and/or filters to the parent node.
185
186     Args:
187       parent: Destination node
188       files: A list of Filter objects and/or relative paths to files.
189
190     Will call itself recursively, if the files list contains Filter objects.
191     """
192     for f in files:
193       if isinstance(f, Filter):
194         node = self.doc.createElement('Filter')
195         node.setAttribute('Name', f.name)
196         self._AddFilesToNode(node, f.contents)
197       else:
198         node = self.doc.createElement('File')
199         node.setAttribute('RelativePath', f)
200         self.n_files_dict[f] = node
201       parent.appendChild(node)
202
203   def AddFiles(self, files):
204     """Adds files to the project.
205
206     Args:
207       files: A list of Filter objects and/or relative paths to files.
208
209     This makes a copy of the file/filter tree at the time of this call.  If you
210     later add files to a Filter object which was passed into a previous call
211     to AddFiles(), it will not be reflected in this project.
212     """
213     self._AddFilesToNode(self.n_files, files)
214     # TODO(rspangler) This also doesn't handle adding files to an existing
215     # filter.  That is, it doesn't merge the trees.
216
217   def AddFileConfig(self, path, config, attrs=None, tools=None):
218     """Adds a configuration to a file.
219
220     Args:
221       path: Relative path to the file.
222       config: Name of configuration to add.
223       attrs: Dict of configuration attributes; may be None.
224       tools: List of tools (strings or Tool objects); may be None.
225
226     Raises:
227       ValueError: Relative path does not match any file added via AddFiles().
228     """
229     # Find the file node with the right relative path
230     parent = self.n_files_dict.get(path)
231     if not parent:
232       raise ValueError('AddFileConfig: file "%s" not in project.' % path)
233
234     # Add the config to the file node
235     self._AddConfigToNode(parent, 'FileConfiguration', config, attrs, tools)
236
237   def Write(self, writer=common.WriteOnDiff):
238     """Writes the project file."""
239     f = writer(self.project_path)
240     fix = xml_fix.XmlFix()
241     self.doc.writexml(f, encoding='Windows-1252', addindent='  ', newl='\r\n')
242     fix.Cleanup()
243     f.close()
244
245 #------------------------------------------------------------------------------