Initial commit
[yaffs-website] / node_modules / node-gyp / gyp / pylib / gyp / MSVSProject.py
1 # Copyright (c) 2012 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Visual Studio project reader/writer."""
6
7 import gyp.common
8 import gyp.easy_xml as easy_xml
9
10 #------------------------------------------------------------------------------
11
12
13 class Tool(object):
14   """Visual Studio tool."""
15
16   def __init__(self, name, attrs=None):
17     """Initializes the tool.
18
19     Args:
20       name: Tool name.
21       attrs: Dict of tool attributes; may be None.
22     """
23     self._attrs = attrs or {}
24     self._attrs['Name'] = name
25
26   def _GetSpecification(self):
27     """Creates an element for the tool.
28
29     Returns:
30       A new xml.dom.Element for the tool.
31     """
32     return ['Tool', self._attrs]
33
34 class Filter(object):
35   """Visual Studio filter - that is, a virtual folder."""
36
37   def __init__(self, name, contents=None):
38     """Initializes the folder.
39
40     Args:
41       name: Filter (folder) name.
42       contents: List of filenames and/or Filter objects contained.
43     """
44     self.name = name
45     self.contents = list(contents or [])
46
47
48 #------------------------------------------------------------------------------
49
50
51 class Writer(object):
52   """Visual Studio XML project writer."""
53
54   def __init__(self, project_path, version, name, guid=None, platforms=None):
55     """Initializes the project.
56
57     Args:
58       project_path: Path to the project file.
59       version: Format version to emit.
60       name: Name of the project.
61       guid: GUID to use for project, if not None.
62       platforms: Array of string, the supported platforms.  If null, ['Win32']
63     """
64     self.project_path = project_path
65     self.version = version
66     self.name = name
67     self.guid = guid
68
69     # Default to Win32 for platforms.
70     if not platforms:
71       platforms = ['Win32']
72
73     # Initialize the specifications of the various sections.
74     self.platform_section = ['Platforms']
75     for platform in platforms:
76       self.platform_section.append(['Platform', {'Name': platform}])
77     self.tool_files_section = ['ToolFiles']
78     self.configurations_section = ['Configurations']
79     self.files_section = ['Files']
80
81     # Keep a dict keyed on filename to speed up access.
82     self.files_dict = dict()
83
84   def AddToolFile(self, path):
85     """Adds a tool file to the project.
86
87     Args:
88       path: Relative path from project to tool file.
89     """
90     self.tool_files_section.append(['ToolFile', {'RelativePath': path}])
91
92   def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools):
93     """Returns the specification for a configuration.
94
95     Args:
96       config_type: Type of configuration node.
97       config_name: Configuration name.
98       attrs: Dict of configuration attributes; may be None.
99       tools: List of tools (strings or Tool objects); may be None.
100     Returns:
101     """
102     # Handle defaults
103     if not attrs:
104       attrs = {}
105     if not tools:
106       tools = []
107
108     # Add configuration node and its attributes
109     node_attrs = attrs.copy()
110     node_attrs['Name'] = config_name
111     specification = [config_type, node_attrs]
112
113     # Add tool nodes and their attributes
114     if tools:
115       for t in tools:
116         if isinstance(t, Tool):
117           specification.append(t._GetSpecification())
118         else:
119           specification.append(Tool(t)._GetSpecification())
120     return specification
121
122
123   def AddConfig(self, name, attrs=None, tools=None):
124     """Adds a configuration to the project.
125
126     Args:
127       name: Configuration name.
128       attrs: Dict of configuration attributes; may be None.
129       tools: List of tools (strings or Tool objects); may be None.
130     """
131     spec = self._GetSpecForConfiguration('Configuration', name, attrs, tools)
132     self.configurations_section.append(spec)
133
134   def _AddFilesToNode(self, parent, files):
135     """Adds files and/or filters to the parent node.
136
137     Args:
138       parent: Destination node
139       files: A list of Filter objects and/or relative paths to files.
140
141     Will call itself recursively, if the files list contains Filter objects.
142     """
143     for f in files:
144       if isinstance(f, Filter):
145         node = ['Filter', {'Name': f.name}]
146         self._AddFilesToNode(node, f.contents)
147       else:
148         node = ['File', {'RelativePath': f}]
149         self.files_dict[f] = node
150       parent.append(node)
151
152   def AddFiles(self, files):
153     """Adds files to the project.
154
155     Args:
156       files: A list of Filter objects and/or relative paths to files.
157
158     This makes a copy of the file/filter tree at the time of this call.  If you
159     later add files to a Filter object which was passed into a previous call
160     to AddFiles(), it will not be reflected in this project.
161     """
162     self._AddFilesToNode(self.files_section, files)
163     # TODO(rspangler) This also doesn't handle adding files to an existing
164     # filter.  That is, it doesn't merge the trees.
165
166   def AddFileConfig(self, path, config, attrs=None, tools=None):
167     """Adds a configuration to a file.
168
169     Args:
170       path: Relative path to the file.
171       config: Name of configuration to add.
172       attrs: Dict of configuration attributes; may be None.
173       tools: List of tools (strings or Tool objects); may be None.
174
175     Raises:
176       ValueError: Relative path does not match any file added via AddFiles().
177     """
178     # Find the file node with the right relative path
179     parent = self.files_dict.get(path)
180     if not parent:
181       raise ValueError('AddFileConfig: file "%s" not in project.' % path)
182
183     # Add the config to the file node
184     spec = self._GetSpecForConfiguration('FileConfiguration', config, attrs,
185                                          tools)
186     parent.append(spec)
187
188   def WriteIfChanged(self):
189     """Writes the project file."""
190     # First create XML content definition
191     content = [
192         'VisualStudioProject',
193         {'ProjectType': 'Visual C++',
194          'Version': self.version.ProjectVersion(),
195          'Name': self.name,
196          'ProjectGUID': self.guid,
197          'RootNamespace': self.name,
198          'Keyword': 'Win32Proj'
199         },
200         self.platform_section,
201         self.tool_files_section,
202         self.configurations_section,
203         ['References'],  # empty section
204         self.files_section,
205         ['Globals']  # empty section
206     ]
207     easy_xml.WriteXmlIfChanged(content, self.project_path,
208                                encoding="Windows-1252")