| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- # 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.
- """Visual Studio project reader/writer."""
- import gyp.easy_xml as easy_xml
- # ------------------------------------------------------------------------------
- class Tool:
- """Visual Studio tool."""
- def __init__(self, name, attrs=None):
- """Initializes the tool.
- Args:
- name: Tool name.
- attrs: Dict of tool attributes; may be None.
- """
- self._attrs = attrs or {}
- self._attrs["Name"] = name
- def _GetSpecification(self):
- """Creates an element for the tool.
- Returns:
- A new xml.dom.Element for the tool.
- """
- return ["Tool", self._attrs]
- class Filter:
- """Visual Studio filter - that is, a virtual folder."""
- def __init__(self, name, contents=None):
- """Initializes the folder.
- Args:
- name: Filter (folder) name.
- contents: List of filenames and/or Filter objects contained.
- """
- self.name = name
- self.contents = list(contents or [])
- # ------------------------------------------------------------------------------
- class Writer:
- """Visual Studio XML project writer."""
- def __init__(self, project_path, version, name, guid=None, platforms=None):
- """Initializes the project.
- Args:
- project_path: Path to the project file.
- version: Format version to emit.
- name: Name of the project.
- guid: GUID to use for project, if not None.
- platforms: Array of string, the supported platforms. If null, ['Win32']
- """
- self.project_path = project_path
- self.version = version
- self.name = name
- self.guid = guid
- # Default to Win32 for platforms.
- if not platforms:
- platforms = ["Win32"]
- # Initialize the specifications of the various sections.
- self.platform_section = ["Platforms"]
- for platform in platforms:
- self.platform_section.append(["Platform", {"Name": platform}])
- self.tool_files_section = ["ToolFiles"]
- self.configurations_section = ["Configurations"]
- self.files_section = ["Files"]
- # Keep a dict keyed on filename to speed up access.
- self.files_dict = dict()
- def AddToolFile(self, path):
- """Adds a tool file to the project.
- Args:
- path: Relative path from project to tool file.
- """
- self.tool_files_section.append(["ToolFile", {"RelativePath": path}])
- def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools):
- """Returns the specification for a configuration.
- Args:
- config_type: Type of configuration node.
- config_name: Configuration name.
- attrs: Dict of configuration attributes; may be None.
- tools: List of tools (strings or Tool objects); may be None.
- Returns:
- """
- # Handle defaults
- if not attrs:
- attrs = {}
- if not tools:
- tools = []
- # Add configuration node and its attributes
- node_attrs = attrs.copy()
- node_attrs["Name"] = config_name
- specification = [config_type, node_attrs]
- # Add tool nodes and their attributes
- if tools:
- for t in tools:
- if isinstance(t, Tool):
- specification.append(t._GetSpecification())
- else:
- specification.append(Tool(t)._GetSpecification())
- return specification
- def AddConfig(self, name, attrs=None, tools=None):
- """Adds a configuration to the project.
- Args:
- name: Configuration name.
- attrs: Dict of configuration attributes; may be None.
- tools: List of tools (strings or Tool objects); may be None.
- """
- spec = self._GetSpecForConfiguration("Configuration", name, attrs, tools)
- self.configurations_section.append(spec)
- def _AddFilesToNode(self, parent, files):
- """Adds files and/or filters to the parent node.
- Args:
- parent: Destination node
- files: A list of Filter objects and/or relative paths to files.
- Will call itself recursively, if the files list contains Filter objects.
- """
- for f in files:
- if isinstance(f, Filter):
- node = ["Filter", {"Name": f.name}]
- self._AddFilesToNode(node, f.contents)
- else:
- node = ["File", {"RelativePath": f}]
- self.files_dict[f] = node
- parent.append(node)
- def AddFiles(self, files):
- """Adds files to the project.
- Args:
- files: A list of Filter objects and/or relative paths to files.
- This makes a copy of the file/filter tree at the time of this call. If you
- later add files to a Filter object which was passed into a previous call
- to AddFiles(), it will not be reflected in this project.
- """
- self._AddFilesToNode(self.files_section, files)
- # TODO(rspangler) This also doesn't handle adding files to an existing
- # filter. That is, it doesn't merge the trees.
- def AddFileConfig(self, path, config, attrs=None, tools=None):
- """Adds a configuration to a file.
- Args:
- path: Relative path to the file.
- config: Name of configuration to add.
- attrs: Dict of configuration attributes; may be None.
- tools: List of tools (strings or Tool objects); may be None.
- Raises:
- ValueError: Relative path does not match any file added via AddFiles().
- """
- # Find the file node with the right relative path
- parent = self.files_dict.get(path)
- if not parent:
- raise ValueError('AddFileConfig: file "%s" not in project.' % path)
- # Add the config to the file node
- spec = self._GetSpecForConfiguration("FileConfiguration", config, attrs, tools)
- parent.append(spec)
- def WriteIfChanged(self):
- """Writes the project file."""
- # First create XML content definition
- content = [
- "VisualStudioProject",
- {
- "ProjectType": "Visual C++",
- "Version": self.version.ProjectVersion(),
- "Name": self.name,
- "ProjectGUID": self.guid,
- "RootNamespace": self.name,
- "Keyword": "Win32Proj",
- },
- self.platform_section,
- self.tool_files_section,
- self.configurations_section,
- ["References"], # empty section
- self.files_section,
- ["Globals"], # empty section
- ]
- easy_xml.WriteXmlIfChanged(content, self.project_path, encoding="Windows-1252")
|