11cb0ef41Sopenharmony_ci# Copyright (c) 2012 Google Inc. All rights reserved. 21cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci# found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci"""Visual Studio project reader/writer.""" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciimport gyp.easy_xml as easy_xml 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci# ------------------------------------------------------------------------------ 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ciclass Tool: 131cb0ef41Sopenharmony_ci """Visual Studio tool.""" 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci def __init__(self, name, attrs=None): 161cb0ef41Sopenharmony_ci """Initializes the tool. 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci Args: 191cb0ef41Sopenharmony_ci name: Tool name. 201cb0ef41Sopenharmony_ci attrs: Dict of tool attributes; may be None. 211cb0ef41Sopenharmony_ci """ 221cb0ef41Sopenharmony_ci self._attrs = attrs or {} 231cb0ef41Sopenharmony_ci self._attrs["Name"] = name 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci def _GetSpecification(self): 261cb0ef41Sopenharmony_ci """Creates an element for the tool. 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci Returns: 291cb0ef41Sopenharmony_ci A new xml.dom.Element for the tool. 301cb0ef41Sopenharmony_ci """ 311cb0ef41Sopenharmony_ci return ["Tool", self._attrs] 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciclass Filter: 351cb0ef41Sopenharmony_ci """Visual Studio filter - that is, a virtual folder.""" 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci def __init__(self, name, contents=None): 381cb0ef41Sopenharmony_ci """Initializes the folder. 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci Args: 411cb0ef41Sopenharmony_ci name: Filter (folder) name. 421cb0ef41Sopenharmony_ci contents: List of filenames and/or Filter objects contained. 431cb0ef41Sopenharmony_ci """ 441cb0ef41Sopenharmony_ci self.name = name 451cb0ef41Sopenharmony_ci self.contents = list(contents or []) 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci# ------------------------------------------------------------------------------ 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ciclass Writer: 521cb0ef41Sopenharmony_ci """Visual Studio XML project writer.""" 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci def __init__(self, project_path, version, name, guid=None, platforms=None): 551cb0ef41Sopenharmony_ci """Initializes the project. 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci Args: 581cb0ef41Sopenharmony_ci project_path: Path to the project file. 591cb0ef41Sopenharmony_ci version: Format version to emit. 601cb0ef41Sopenharmony_ci name: Name of the project. 611cb0ef41Sopenharmony_ci guid: GUID to use for project, if not None. 621cb0ef41Sopenharmony_ci platforms: Array of string, the supported platforms. If null, ['Win32'] 631cb0ef41Sopenharmony_ci """ 641cb0ef41Sopenharmony_ci self.project_path = project_path 651cb0ef41Sopenharmony_ci self.version = version 661cb0ef41Sopenharmony_ci self.name = name 671cb0ef41Sopenharmony_ci self.guid = guid 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci # Default to Win32 for platforms. 701cb0ef41Sopenharmony_ci if not platforms: 711cb0ef41Sopenharmony_ci platforms = ["Win32"] 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci # Initialize the specifications of the various sections. 741cb0ef41Sopenharmony_ci self.platform_section = ["Platforms"] 751cb0ef41Sopenharmony_ci for platform in platforms: 761cb0ef41Sopenharmony_ci self.platform_section.append(["Platform", {"Name": platform}]) 771cb0ef41Sopenharmony_ci self.tool_files_section = ["ToolFiles"] 781cb0ef41Sopenharmony_ci self.configurations_section = ["Configurations"] 791cb0ef41Sopenharmony_ci self.files_section = ["Files"] 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci # Keep a dict keyed on filename to speed up access. 821cb0ef41Sopenharmony_ci self.files_dict = dict() 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci def AddToolFile(self, path): 851cb0ef41Sopenharmony_ci """Adds a tool file to the project. 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci Args: 881cb0ef41Sopenharmony_ci path: Relative path from project to tool file. 891cb0ef41Sopenharmony_ci """ 901cb0ef41Sopenharmony_ci self.tool_files_section.append(["ToolFile", {"RelativePath": path}]) 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools): 931cb0ef41Sopenharmony_ci """Returns the specification for a configuration. 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci Args: 961cb0ef41Sopenharmony_ci config_type: Type of configuration node. 971cb0ef41Sopenharmony_ci config_name: Configuration name. 981cb0ef41Sopenharmony_ci attrs: Dict of configuration attributes; may be None. 991cb0ef41Sopenharmony_ci tools: List of tools (strings or Tool objects); may be None. 1001cb0ef41Sopenharmony_ci Returns: 1011cb0ef41Sopenharmony_ci """ 1021cb0ef41Sopenharmony_ci # Handle defaults 1031cb0ef41Sopenharmony_ci if not attrs: 1041cb0ef41Sopenharmony_ci attrs = {} 1051cb0ef41Sopenharmony_ci if not tools: 1061cb0ef41Sopenharmony_ci tools = [] 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci # Add configuration node and its attributes 1091cb0ef41Sopenharmony_ci node_attrs = attrs.copy() 1101cb0ef41Sopenharmony_ci node_attrs["Name"] = config_name 1111cb0ef41Sopenharmony_ci specification = [config_type, node_attrs] 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci # Add tool nodes and their attributes 1141cb0ef41Sopenharmony_ci if tools: 1151cb0ef41Sopenharmony_ci for t in tools: 1161cb0ef41Sopenharmony_ci if isinstance(t, Tool): 1171cb0ef41Sopenharmony_ci specification.append(t._GetSpecification()) 1181cb0ef41Sopenharmony_ci else: 1191cb0ef41Sopenharmony_ci specification.append(Tool(t)._GetSpecification()) 1201cb0ef41Sopenharmony_ci return specification 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci def AddConfig(self, name, attrs=None, tools=None): 1231cb0ef41Sopenharmony_ci """Adds a configuration to the project. 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci Args: 1261cb0ef41Sopenharmony_ci name: Configuration name. 1271cb0ef41Sopenharmony_ci attrs: Dict of configuration attributes; may be None. 1281cb0ef41Sopenharmony_ci tools: List of tools (strings or Tool objects); may be None. 1291cb0ef41Sopenharmony_ci """ 1301cb0ef41Sopenharmony_ci spec = self._GetSpecForConfiguration("Configuration", name, attrs, tools) 1311cb0ef41Sopenharmony_ci self.configurations_section.append(spec) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci def _AddFilesToNode(self, parent, files): 1341cb0ef41Sopenharmony_ci """Adds files and/or filters to the parent node. 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci Args: 1371cb0ef41Sopenharmony_ci parent: Destination node 1381cb0ef41Sopenharmony_ci files: A list of Filter objects and/or relative paths to files. 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci Will call itself recursively, if the files list contains Filter objects. 1411cb0ef41Sopenharmony_ci """ 1421cb0ef41Sopenharmony_ci for f in files: 1431cb0ef41Sopenharmony_ci if isinstance(f, Filter): 1441cb0ef41Sopenharmony_ci node = ["Filter", {"Name": f.name}] 1451cb0ef41Sopenharmony_ci self._AddFilesToNode(node, f.contents) 1461cb0ef41Sopenharmony_ci else: 1471cb0ef41Sopenharmony_ci node = ["File", {"RelativePath": f}] 1481cb0ef41Sopenharmony_ci self.files_dict[f] = node 1491cb0ef41Sopenharmony_ci parent.append(node) 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci def AddFiles(self, files): 1521cb0ef41Sopenharmony_ci """Adds files to the project. 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci Args: 1551cb0ef41Sopenharmony_ci files: A list of Filter objects and/or relative paths to files. 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci This makes a copy of the file/filter tree at the time of this call. If you 1581cb0ef41Sopenharmony_ci later add files to a Filter object which was passed into a previous call 1591cb0ef41Sopenharmony_ci to AddFiles(), it will not be reflected in this project. 1601cb0ef41Sopenharmony_ci """ 1611cb0ef41Sopenharmony_ci self._AddFilesToNode(self.files_section, files) 1621cb0ef41Sopenharmony_ci # TODO(rspangler) This also doesn't handle adding files to an existing 1631cb0ef41Sopenharmony_ci # filter. That is, it doesn't merge the trees. 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci def AddFileConfig(self, path, config, attrs=None, tools=None): 1661cb0ef41Sopenharmony_ci """Adds a configuration to a file. 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci Args: 1691cb0ef41Sopenharmony_ci path: Relative path to the file. 1701cb0ef41Sopenharmony_ci config: Name of configuration to add. 1711cb0ef41Sopenharmony_ci attrs: Dict of configuration attributes; may be None. 1721cb0ef41Sopenharmony_ci tools: List of tools (strings or Tool objects); may be None. 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci Raises: 1751cb0ef41Sopenharmony_ci ValueError: Relative path does not match any file added via AddFiles(). 1761cb0ef41Sopenharmony_ci """ 1771cb0ef41Sopenharmony_ci # Find the file node with the right relative path 1781cb0ef41Sopenharmony_ci parent = self.files_dict.get(path) 1791cb0ef41Sopenharmony_ci if not parent: 1801cb0ef41Sopenharmony_ci raise ValueError('AddFileConfig: file "%s" not in project.' % path) 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci # Add the config to the file node 1831cb0ef41Sopenharmony_ci spec = self._GetSpecForConfiguration("FileConfiguration", config, attrs, tools) 1841cb0ef41Sopenharmony_ci parent.append(spec) 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci def WriteIfChanged(self): 1871cb0ef41Sopenharmony_ci """Writes the project file.""" 1881cb0ef41Sopenharmony_ci # First create XML content definition 1891cb0ef41Sopenharmony_ci content = [ 1901cb0ef41Sopenharmony_ci "VisualStudioProject", 1911cb0ef41Sopenharmony_ci { 1921cb0ef41Sopenharmony_ci "ProjectType": "Visual C++", 1931cb0ef41Sopenharmony_ci "Version": self.version.ProjectVersion(), 1941cb0ef41Sopenharmony_ci "Name": self.name, 1951cb0ef41Sopenharmony_ci "ProjectGUID": self.guid, 1961cb0ef41Sopenharmony_ci "RootNamespace": self.name, 1971cb0ef41Sopenharmony_ci "Keyword": "Win32Proj", 1981cb0ef41Sopenharmony_ci }, 1991cb0ef41Sopenharmony_ci self.platform_section, 2001cb0ef41Sopenharmony_ci self.tool_files_section, 2011cb0ef41Sopenharmony_ci self.configurations_section, 2021cb0ef41Sopenharmony_ci ["References"], # empty section 2031cb0ef41Sopenharmony_ci self.files_section, 2041cb0ef41Sopenharmony_ci ["Globals"], # empty section 2051cb0ef41Sopenharmony_ci ] 2061cb0ef41Sopenharmony_ci easy_xml.WriteXmlIfChanged(content, self.project_path, encoding="Windows-1252") 207