43b9ac1387baeadf9e363b8ae3c9efc4e745f523a7457353d43fd2b5070004889e52d30dc334062234e504e0f002f1e1735feb4e7dbc44d52b541dc3907fa3 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. """Visual Studio user preferences file writer."""
  5. import os
  6. import re
  7. import socket # for gethostname
  8. import gyp.easy_xml as easy_xml
  9. # ------------------------------------------------------------------------------
  10. def _FindCommandInPath(command):
  11. """If there are no slashes in the command given, this function
  12. searches the PATH env to find the given command, and converts it
  13. to an absolute path. We have to do this because MSVS is looking
  14. for an actual file to launch a debugger on, not just a command
  15. line. Note that this happens at GYP time, so anything needing to
  16. be built needs to have a full path."""
  17. if "/" in command or "\\" in command:
  18. # If the command already has path elements (either relative or
  19. # absolute), then assume it is constructed properly.
  20. return command
  21. else:
  22. # Search through the path list and find an existing file that
  23. # we can access.
  24. paths = os.environ.get("PATH", "").split(os.pathsep)
  25. for path in paths:
  26. item = os.path.join(path, command)
  27. if os.path.isfile(item) and os.access(item, os.X_OK):
  28. return item
  29. return command
  30. def _QuoteWin32CommandLineArgs(args):
  31. new_args = []
  32. for arg in args:
  33. # Replace all double-quotes with double-double-quotes to escape
  34. # them for cmd shell, and then quote the whole thing if there
  35. # are any.
  36. if arg.find('"') != -1:
  37. arg = '""'.join(arg.split('"'))
  38. arg = '"%s"' % arg
  39. # Otherwise, if there are any spaces, quote the whole arg.
  40. elif re.search(r"[ \t\n]", arg):
  41. arg = '"%s"' % arg
  42. new_args.append(arg)
  43. return new_args
  44. class Writer:
  45. """Visual Studio XML user user file writer."""
  46. def __init__(self, user_file_path, version, name):
  47. """Initializes the user file.
  48. Args:
  49. user_file_path: Path to the user file.
  50. version: Version info.
  51. name: Name of the user file.
  52. """
  53. self.user_file_path = user_file_path
  54. self.version = version
  55. self.name = name
  56. self.configurations = {}
  57. def AddConfig(self, name):
  58. """Adds a configuration to the project.
  59. Args:
  60. name: Configuration name.
  61. """
  62. self.configurations[name] = ["Configuration", {"Name": name}]
  63. def AddDebugSettings(
  64. self, config_name, command, environment={}, working_directory=""
  65. ):
  66. """Adds a DebugSettings node to the user file for a particular config.
  67. Args:
  68. command: command line to run. First element in the list is the
  69. executable. All elements of the command will be quoted if
  70. necessary.
  71. working_directory: other files which may trigger the rule. (optional)
  72. """
  73. command = _QuoteWin32CommandLineArgs(command)
  74. abs_command = _FindCommandInPath(command[0])
  75. if environment and isinstance(environment, dict):
  76. env_list = [f'{key}="{val}"' for (key, val) in environment.items()]
  77. environment = " ".join(env_list)
  78. else:
  79. environment = ""
  80. n_cmd = [
  81. "DebugSettings",
  82. {
  83. "Command": abs_command,
  84. "WorkingDirectory": working_directory,
  85. "CommandArguments": " ".join(command[1:]),
  86. "RemoteMachine": socket.gethostname(),
  87. "Environment": environment,
  88. "EnvironmentMerge": "true",
  89. # Currently these are all "dummy" values that we're just setting
  90. # in the default manner that MSVS does it. We could use some of
  91. # these to add additional capabilities, I suppose, but they might
  92. # not have parity with other platforms then.
  93. "Attach": "false",
  94. "DebuggerType": "3", # 'auto' debugger
  95. "Remote": "1",
  96. "RemoteCommand": "",
  97. "HttpUrl": "",
  98. "PDBPath": "",
  99. "SQLDebugging": "",
  100. "DebuggerFlavor": "0",
  101. "MPIRunCommand": "",
  102. "MPIRunArguments": "",
  103. "MPIRunWorkingDirectory": "",
  104. "ApplicationCommand": "",
  105. "ApplicationArguments": "",
  106. "ShimCommand": "",
  107. "MPIAcceptMode": "",
  108. "MPIAcceptFilter": "",
  109. },
  110. ]
  111. # Find the config, and add it if it doesn't exist.
  112. if config_name not in self.configurations:
  113. self.AddConfig(config_name)
  114. # Add the DebugSettings onto the appropriate config.
  115. self.configurations[config_name].append(n_cmd)
  116. def WriteIfChanged(self):
  117. """Writes the user file."""
  118. configs = ["Configurations"]
  119. for config, spec in sorted(self.configurations.items()):
  120. configs.append(spec)
  121. content = [
  122. "VisualStudioUserFile",
  123. {"Version": self.version.ProjectVersion(), "Name": self.name},
  124. configs,
  125. ]
  126. easy_xml.WriteXmlIfChanged(
  127. content, self.user_file_path, encoding="Windows-1252"
  128. )