Remove windows line ending from repo files.
Somehow these files got submitted with win32 line
endings. Maybe its not worth fixing?
BUG=
Review URL: https://codereview.chromium.org/10908249
git-svn-id: https://nativeclient-sdk.googlecode.com/svn/trunk/src@1419 050acbb0-2703-11df-ab0a-9f3f633ae91d
diff --git a/InstallerResources/create_ppapi_platform.py b/InstallerResources/create_ppapi_platform.py
index bee321d..252ae5a 100644
--- a/InstallerResources/create_ppapi_platform.py
+++ b/InstallerResources/create_ppapi_platform.py
@@ -1,206 +1,206 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" This script creates the PPAPI project settings template.
-
-For copyright reasons, we should not directly distribute the PPAPI template
-because it is nearly a clone of the Win32 template which is Copyrighted.
-Instead, this script copies the existing Win32 template from the user's system
-and intelligently modifies the copy to be the PPAPI template.
-"""
-
-import os
-import optparse
-import shutil
-import string
-import xml_patch
-import third_party.etree.ElementTree as ElementTree
-
-
-PEPPER_PLATFORM_NAME = 'PPAPI'
-
-DEFAULT_MS_BUILD_DIRECTORY = os.path.expandvars('%ProgramFiles(x86)%\\MSBuild')
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-
-PLATFORM_FILES = [
- ('Microsoft.Cpp.Win32.default.props',
- 'Microsoft.Cpp.[platform].default.props.patch',
- 'Microsoft.Cpp.PPAPI.default.props'),
- ('Microsoft.Cpp.Win32.props',
- 'Microsoft.Cpp.[platform].props.patch',
- 'Microsoft.Cpp.PPAPI.props'),
- ('Microsoft.Cpp.Win32.targets',
- 'Microsoft.Cpp.[platform].targets.patch',
- 'Microsoft.Cpp.PPAPI.targets'),
- ('PlatformToolsets\\v100\\Microsoft.Cpp.Win32.v100.props',
- 'PlatformToolsets\\v100\\Microsoft.Cpp.[platform].v100.props.patch',
- 'PlatformToolsets\\v100\\Microsoft.Cpp.PPAPI.v100.props'),
- ('PlatformToolsets\\v100\\Microsoft.Cpp.Win32.v100.targets',
- 'PlatformToolsets\\v100\\Microsoft.Cpp.[platform].v100.targets.patch',
- 'PlatformToolsets\\v100\\Microsoft.Cpp.PPAPI.v100.targets')]
-
-UI_FILES = [
- ('general.xml',
- 'Props\\ppapi_general.xml.patch',
- 'Props\\ppapi_general.xml'),
- ('general_ps.xml',
- 'Props\\ppapi_general_ps.xml.patch',
- 'Props\\ppapi_general_ps.xml')]
-
-COPY_FILES = [
- 'ImportAfter\\PPAPI.override.props']
-
-
-def PrependCopyright(source_file_name, dest_file_name):
- """Adds the copyright notice from source file to the dest file.
-
- Since the patch_xml function does not read comments, the copyright is skipped
- during the initial copy. This function adds it back and also attaches a
- notice that the file was based on source_file_name and slightly modified.
-
- Args:
- source_file_name: The original Win32 file.
- dest_file_name: The existing PPAPI file.
-
- Returns:
- None.
- """
- with open(source_file_name, 'r') as source_file:
- in_copyright = False
- copyright_notice = ''
- for line in source_file:
- if '<!--' in line:
- in_copyright = True
- if in_copyright:
- copyright_notice += line
- if '-->' in line:
- in_copyright = False
- break
-
- with open(dest_file_name, 'r') as original:
- xml_data = original.read()
-
- chrome_notice = ('<!-- This file has been copied and modified from %s during '
- 'the installation process. -->\n\n' % (source_file_name))
-
- with open(dest_file_name, 'w') as changed:
- changed.writelines(copyright_notice + chrome_notice + xml_data)
-
-
-def CreateTemplateFile(source, patch, dest):
- """Creates a single PPAPI template file.
-
- Args:
- source: The path source file to create from.
- patch: The path to the patch file to apply.
- dest: The path to the file to create.
- Returns:
- None.
- """
- source_xml = ElementTree.parse(source)
- patch_xml = ElementTree.parse(patch)
- modified_xml = xml_patch.PatchXML(source_xml, patch_xml)
-
- if not os.path.exists(os.path.dirname(dest)):
- os.makedirs(os.path.dirname(dest))
-
- FixAttributesNamespace(modified_xml)
- default_namespace = GetDefaultNamespace(modified_xml)
- modified_xml.write(dest, default_namespace=default_namespace)
- PrependCopyright(source, dest)
-
-
-def GetDefaultNamespace(tree):
- # Returns the uri (namespace identifier) of the root element.
- tag = tree.getroot().tag
- if tag.startswith("{"):
- uri, rest = tag[1:].rsplit("}", 1)
- return uri
- else:
- return None
-
-
-def FixAttributesNamespace(tree):
- # ElementTree's implementation seems to be broken in that attributes
- # do not inherit the default namespace of their node or parent nodes.
- # This causes issues with ElementTree.write() when using a default namespace.
- # Since the attributes do not have a namespace, the code that collects a
- # mapping between local names and qualified names (with a namespace) breaks.
- # The work-around is to give all attributes the default namespace.
- default_namespace = GetDefaultNamespace(tree)
- for elem in tree.getroot().getiterator():
- new_attrib = dict()
- for key, value in elem.attrib.items():
- # If the attribute does not have a namespace yet then give it one.
- if key[:1] != "{":
- new_key = "{%s}%s" % (default_namespace, key)
- new_attrib[new_key] = value
- else:
- new_attrib[key] = value
- elem.attrib = new_attrib
-
-
-def CreatePPAPI(msbuild_dir):
- """Creates the PPAPI template.
-
- Args:
- msbuild_dir: The path to the MSBuild installation.
-
- Returns:
- Nothing.
-
- Raises:
- Exception indicating Win32 platform was not found.
- """
- if not os.path.exists(msbuild_dir):
- raise Exception('MSBuild directory was not found!')
-
- install_dir = os.path.join(msbuild_dir, 'Microsoft.Cpp\\v4.0\\Platforms')
-
- # Note 1033 is code for the english language.
- ui_xml_dir = os.path.join(msbuild_dir, 'Microsoft.Cpp\\v4.0\\1033')
-
- win32_dir = os.path.join(install_dir, 'Win32')
- ppapi_dir = os.path.join(install_dir, PEPPER_PLATFORM_NAME)
- patch_dir = os.path.join(SCRIPT_DIR, 'PPAPI_Patch')
-
- if not os.path.exists(win32_dir):
- raise Exception('Win32 platform is not installed on this machine!')
-
- for template_creation in PLATFORM_FILES:
- CreateTemplateFile(
- os.path.join(win32_dir, template_creation[0]),
- os.path.join(patch_dir, template_creation[1]),
- os.path.join(ppapi_dir, template_creation[2]))
-
- for template_creation in UI_FILES:
- CreateTemplateFile(
- os.path.join(ui_xml_dir, template_creation[0]),
- os.path.join(patch_dir, template_creation[1]),
- os.path.join(ppapi_dir, template_creation[2]))
-
- for file_name in COPY_FILES:
- copy_from = os.path.join(patch_dir, file_name)
- copy_to = os.path.join(ppapi_dir, file_name)
- if not os.path.exists(os.path.dirname(copy_to)):
- os.makedirs(os.path.dirname(copy_to))
- shutil.copyfile(copy_from, copy_to)
-
- shutil.copyfile(
- os.path.join(win32_dir, 'Microsoft.Build.CPPTasks.Win32.dll'),
- os.path.join(ppapi_dir, 'Microsoft.Build.CPPTasks.PPAPI.dll'))
-
-
-def main():
- parser = optparse.OptionParser(usage='Usage: %prog [options]')
- parser.add_option('-b', '--msbuild-path', dest='msbuild_path',
- default=DEFAULT_MS_BUILD_DIRECTORY,
- help='Provide the path to the MSBuild directory', metavar='PATH')
- (options, args) = parser.parse_args()
- CreatePPAPI(options.msbuild_path)
-
-if __name__ == '__main__':
- main()
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" This script creates the PPAPI project settings template.
+
+For copyright reasons, we should not directly distribute the PPAPI template
+because it is nearly a clone of the Win32 template which is Copyrighted.
+Instead, this script copies the existing Win32 template from the user's system
+and intelligently modifies the copy to be the PPAPI template.
+"""
+
+import os
+import optparse
+import shutil
+import string
+import xml_patch
+import third_party.etree.ElementTree as ElementTree
+
+
+PEPPER_PLATFORM_NAME = 'PPAPI'
+
+DEFAULT_MS_BUILD_DIRECTORY = os.path.expandvars('%ProgramFiles(x86)%\\MSBuild')
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+PLATFORM_FILES = [
+ ('Microsoft.Cpp.Win32.default.props',
+ 'Microsoft.Cpp.[platform].default.props.patch',
+ 'Microsoft.Cpp.PPAPI.default.props'),
+ ('Microsoft.Cpp.Win32.props',
+ 'Microsoft.Cpp.[platform].props.patch',
+ 'Microsoft.Cpp.PPAPI.props'),
+ ('Microsoft.Cpp.Win32.targets',
+ 'Microsoft.Cpp.[platform].targets.patch',
+ 'Microsoft.Cpp.PPAPI.targets'),
+ ('PlatformToolsets\\v100\\Microsoft.Cpp.Win32.v100.props',
+ 'PlatformToolsets\\v100\\Microsoft.Cpp.[platform].v100.props.patch',
+ 'PlatformToolsets\\v100\\Microsoft.Cpp.PPAPI.v100.props'),
+ ('PlatformToolsets\\v100\\Microsoft.Cpp.Win32.v100.targets',
+ 'PlatformToolsets\\v100\\Microsoft.Cpp.[platform].v100.targets.patch',
+ 'PlatformToolsets\\v100\\Microsoft.Cpp.PPAPI.v100.targets')]
+
+UI_FILES = [
+ ('general.xml',
+ 'Props\\ppapi_general.xml.patch',
+ 'Props\\ppapi_general.xml'),
+ ('general_ps.xml',
+ 'Props\\ppapi_general_ps.xml.patch',
+ 'Props\\ppapi_general_ps.xml')]
+
+COPY_FILES = [
+ 'ImportAfter\\PPAPI.override.props']
+
+
+def PrependCopyright(source_file_name, dest_file_name):
+ """Adds the copyright notice from source file to the dest file.
+
+ Since the patch_xml function does not read comments, the copyright is skipped
+ during the initial copy. This function adds it back and also attaches a
+ notice that the file was based on source_file_name and slightly modified.
+
+ Args:
+ source_file_name: The original Win32 file.
+ dest_file_name: The existing PPAPI file.
+
+ Returns:
+ None.
+ """
+ with open(source_file_name, 'r') as source_file:
+ in_copyright = False
+ copyright_notice = ''
+ for line in source_file:
+ if '<!--' in line:
+ in_copyright = True
+ if in_copyright:
+ copyright_notice += line
+ if '-->' in line:
+ in_copyright = False
+ break
+
+ with open(dest_file_name, 'r') as original:
+ xml_data = original.read()
+
+ chrome_notice = ('<!-- This file has been copied and modified from %s during '
+ 'the installation process. -->\n\n' % (source_file_name))
+
+ with open(dest_file_name, 'w') as changed:
+ changed.writelines(copyright_notice + chrome_notice + xml_data)
+
+
+def CreateTemplateFile(source, patch, dest):
+ """Creates a single PPAPI template file.
+
+ Args:
+ source: The path source file to create from.
+ patch: The path to the patch file to apply.
+ dest: The path to the file to create.
+ Returns:
+ None.
+ """
+ source_xml = ElementTree.parse(source)
+ patch_xml = ElementTree.parse(patch)
+ modified_xml = xml_patch.PatchXML(source_xml, patch_xml)
+
+ if not os.path.exists(os.path.dirname(dest)):
+ os.makedirs(os.path.dirname(dest))
+
+ FixAttributesNamespace(modified_xml)
+ default_namespace = GetDefaultNamespace(modified_xml)
+ modified_xml.write(dest, default_namespace=default_namespace)
+ PrependCopyright(source, dest)
+
+
+def GetDefaultNamespace(tree):
+ # Returns the uri (namespace identifier) of the root element.
+ tag = tree.getroot().tag
+ if tag.startswith("{"):
+ uri, rest = tag[1:].rsplit("}", 1)
+ return uri
+ else:
+ return None
+
+
+def FixAttributesNamespace(tree):
+ # ElementTree's implementation seems to be broken in that attributes
+ # do not inherit the default namespace of their node or parent nodes.
+ # This causes issues with ElementTree.write() when using a default namespace.
+ # Since the attributes do not have a namespace, the code that collects a
+ # mapping between local names and qualified names (with a namespace) breaks.
+ # The work-around is to give all attributes the default namespace.
+ default_namespace = GetDefaultNamespace(tree)
+ for elem in tree.getroot().getiterator():
+ new_attrib = dict()
+ for key, value in elem.attrib.items():
+ # If the attribute does not have a namespace yet then give it one.
+ if key[:1] != "{":
+ new_key = "{%s}%s" % (default_namespace, key)
+ new_attrib[new_key] = value
+ else:
+ new_attrib[key] = value
+ elem.attrib = new_attrib
+
+
+def CreatePPAPI(msbuild_dir):
+ """Creates the PPAPI template.
+
+ Args:
+ msbuild_dir: The path to the MSBuild installation.
+
+ Returns:
+ Nothing.
+
+ Raises:
+ Exception indicating Win32 platform was not found.
+ """
+ if not os.path.exists(msbuild_dir):
+ raise Exception('MSBuild directory was not found!')
+
+ install_dir = os.path.join(msbuild_dir, 'Microsoft.Cpp\\v4.0\\Platforms')
+
+ # Note 1033 is code for the english language.
+ ui_xml_dir = os.path.join(msbuild_dir, 'Microsoft.Cpp\\v4.0\\1033')
+
+ win32_dir = os.path.join(install_dir, 'Win32')
+ ppapi_dir = os.path.join(install_dir, PEPPER_PLATFORM_NAME)
+ patch_dir = os.path.join(SCRIPT_DIR, 'PPAPI_Patch')
+
+ if not os.path.exists(win32_dir):
+ raise Exception('Win32 platform is not installed on this machine!')
+
+ for template_creation in PLATFORM_FILES:
+ CreateTemplateFile(
+ os.path.join(win32_dir, template_creation[0]),
+ os.path.join(patch_dir, template_creation[1]),
+ os.path.join(ppapi_dir, template_creation[2]))
+
+ for template_creation in UI_FILES:
+ CreateTemplateFile(
+ os.path.join(ui_xml_dir, template_creation[0]),
+ os.path.join(patch_dir, template_creation[1]),
+ os.path.join(ppapi_dir, template_creation[2]))
+
+ for file_name in COPY_FILES:
+ copy_from = os.path.join(patch_dir, file_name)
+ copy_to = os.path.join(ppapi_dir, file_name)
+ if not os.path.exists(os.path.dirname(copy_to)):
+ os.makedirs(os.path.dirname(copy_to))
+ shutil.copyfile(copy_from, copy_to)
+
+ shutil.copyfile(
+ os.path.join(win32_dir, 'Microsoft.Build.CPPTasks.Win32.dll'),
+ os.path.join(ppapi_dir, 'Microsoft.Build.CPPTasks.PPAPI.dll'))
+
+
+def main():
+ parser = optparse.OptionParser(usage='Usage: %prog [options]')
+ parser.add_option('-b', '--msbuild-path', dest='msbuild_path',
+ default=DEFAULT_MS_BUILD_DIRECTORY,
+ help='Provide the path to the MSBuild directory', metavar='PATH')
+ (options, args) = parser.parse_args()
+ CreatePPAPI(options.msbuild_path)
+
+if __name__ == '__main__':
+ main()
diff --git a/InstallerResources/install.py b/InstallerResources/install.py
index 0dd6d6c..efc35e4 100644
--- a/InstallerResources/install.py
+++ b/InstallerResources/install.py
@@ -1,193 +1,193 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Copies necessary add-in files into place to install the add-in.
-
-This script will copy the necessary files for the Visual Studio add-in
-to where Visual Studio can find them. It assumes the current directory
-contains the necessary files to copy.
-"""
-
-import create_ppapi_platform
-import ctypes
-import os
-import optparse
-import platform
-import shutil
-import sys
-
-NACL_PLATFORM_NAME = 'NaCl'
-PEPPER_PLATFORM_NAME = 'PPAPI'
-
-DEFAULT_VS_USER_DIRECTORY = os.path.expandvars(
- '%USERPROFILE%\\My Documents\\Visual Studio 2010')
-
-DEFAULT_MS_BUILD_DIRECTORY = os.path.expandvars('%ProgramFiles(x86)%\\MSBuild')
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-
-ADDIN_FILES = ['NativeClientVSAddIn.AddIn', 'NativeClientVSAddIn.dll']
-
-class InstallError(Exception):
- """Error class for this installer indicating a fatal but expected error."""
- pass
-
-def UninstallDirectory(directory):
- if os.path.exists(directory):
- shutil.rmtree(directory)
- print 'Removed: %s' % (directory)
- else:
- print 'Failed to remove non-existant directory: %s' % (directory)
-
-
-def UninstallFile(file_path):
- if os.path.exists(file_path):
- os.remove(file_path)
- print 'Removed: %s' % (file_path)
- else:
- print 'Failed to remove non-existant file: %s' % (file_path)
-
-
-def Uninstall(nacl_directory, pepper_directory, addin_directory):
- UninstallDirectory(nacl_directory)
- UninstallDirectory(pepper_directory)
- for file_name in ADDIN_FILES:
- UninstallFile(os.path.join(addin_directory, file_name))
-
-
-def main():
- parser = optparse.OptionParser(usage='Usage: %prog [options]')
- parser.add_option('-b', '--msbuild-path', dest='msbuild_path',
- default=DEFAULT_MS_BUILD_DIRECTORY, metavar='PATH',
- help='Provide the path to the MSBuild directory')
- parser.add_option('-a', '--vsuser-path', dest='vsuser_path',
- default=DEFAULT_VS_USER_DIRECTORY, metavar='PATH',
- help='Provide the path to the Visual Studio user directory')
- parser.add_option('-f', '--force', action="store_true", dest='overwrite',
- default=False, help='Force an overwrite of existing files')
- parser.add_option('-p', '--ppapi', action="store_true", dest='install_ppapi',
- help='Install PPAPI template without asking.')
- parser.add_option('-n', '--no-ppapi', action="store_false",
- dest='install_ppapi', help='Do not install PPAPI template and do not ask')
- parser.add_option('-u', '--uninstall', action="store_true",
- dest='uninstall', help='Remove the add-in.')
- (options, args) = parser.parse_args()
-
- print "*************************************************"
- print "Native-Client Visual Studio 2010 Add-in Installer"
- print "*************************************************\n"
- print "Please ensure Visual Studio and MSBuild are closed " \
- "during installation.\n"
-
- if platform.system() != 'Windows':
- raise InstallError('Must install to Windows system')
-
- if sys.version_info < (2, 6, 2):
- print "\n\nWARNING: Only python version 2.6.2 or greater is supported. " \
- "Current version is %s\n\n" % (sys.version_info[:3],)
-
- # Admin is needed to write to the default platform directory.
- if ctypes.windll.shell32.IsUserAnAdmin() != 1:
- raise InstallError("Not running as administrator. The install script needs "
- "write access to protected Visual Studio directories.")
-
- # Ensure install directories exist.
- if not os.path.exists(options.vsuser_path):
- raise InstallError("Could not find user Visual Studio directory: %s" % (
- options.vsuser_path))
- if not os.path.exists(options.msbuild_path):
- raise InstallError("Could not find MS Build directory: %s" % (
- options.msbuild_path))
-
- addin_directory = os.path.join(options.vsuser_path, 'Addins')
- platform_directory = os.path.join(
- options.msbuild_path, 'Microsoft.Cpp\\v4.0\\Platforms')
- nacl_directory = os.path.join(platform_directory, NACL_PLATFORM_NAME)
- pepper_directory = os.path.join(platform_directory, PEPPER_PLATFORM_NAME)
-
- # If uninstalling then redirect to uninstall program.
- if options.uninstall:
- Uninstall(nacl_directory, pepper_directory, addin_directory)
- print "\nUninstall complete!\n"
- exit(0)
-
- if not os.path.exists(platform_directory):
- raise InstallError("Could not find path: %s" % platform_directory)
- if not os.path.exists(addin_directory):
- os.mkdir(addin_directory)
-
- # Ensure environment variables are set.
- nacl_sdk_root = os.getenv('NACL_SDK_ROOT', None)
- chrome_path = os.getenv('CHROME_PATH', None)
- if nacl_sdk_root is None:
- raise InstallError('Environment Variable NACL_SDK_ROOT is not set')
- if chrome_path is None:
- raise InstallError('Environment Variable CHROME_PATH is not set')
-
- # Remove existing installation.
- if os.path.exists(nacl_directory) or os.path.exists(pepper_directory):
- # If not forced then ask user permission.
- if not options.overwrite:
- print "\nWarning: Pre-existing add-in installation will be overwritten."
- print "Continue? ((Yes))/((No))"
- remove_answer = raw_input().strip()
- if not (remove_answer.lower() == "yes" or remove_answer.lower() == "y"):
- raise InstallError('User did not allow overwrite of existing install.')
- print "Removing existing install..."
- Uninstall(nacl_directory, pepper_directory, addin_directory)
-
- # Ask user before installing PPAPI template.
- if options.install_ppapi is None:
- print "\n"
- print "Set up configuration to enable Pepper development " \
- "with Visual Studio?"
- print "((Yes)) - I want to create and copy relevant files into a " \
- "Pepper subdirectory"
- print "((No)) - I am not interested or will set up the configuration later"
- ppapi_answer = raw_input().strip()
- if ppapi_answer.lower() == "yes" or ppapi_answer.lower() == "y":
- options.install_ppapi = True
- print "Confirmed installer will include PPAPI platform."
- else:
- options.install_ppapi = False
- print "Will not install PPAPI platform during installation."
-
- print "\nBegin installing components..."
-
- try:
- # Copy the necessary files into place.
- for file_name in ADDIN_FILES:
- shutil.copy(os.path.join(SCRIPT_DIR, file_name), addin_directory)
- print "Add-in installed."
-
- shutil.copytree(os.path.join(SCRIPT_DIR, 'NaCl'), nacl_directory)
- print "NaCl platform installed."
-
- if options.install_ppapi:
- create_ppapi_platform.CreatePPAPI(options.msbuild_path)
- print "PPAPI platform installed."
- except:
- print "\nException occured! Rolling back install...\n"
- Uninstall(nacl_directory, pepper_directory, addin_directory)
- raise
- else:
- print "\nInstallation complete!\n"
-
-if __name__ == '__main__':
- try:
- main()
- except InstallError as e:
- print
- print e
- except shutil.Error as e:
- print "Error while copying file. Please ensure file is not in use."
- print e
- except WindowsError as e:
- if e.winerror == 5:
- print "Access denied error. Please ensure Visual Studio and MSBuild"
- print "processes are closed."
- else:
- raise
-
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Copies necessary add-in files into place to install the add-in.
+
+This script will copy the necessary files for the Visual Studio add-in
+to where Visual Studio can find them. It assumes the current directory
+contains the necessary files to copy.
+"""
+
+import create_ppapi_platform
+import ctypes
+import os
+import optparse
+import platform
+import shutil
+import sys
+
+NACL_PLATFORM_NAME = 'NaCl'
+PEPPER_PLATFORM_NAME = 'PPAPI'
+
+DEFAULT_VS_USER_DIRECTORY = os.path.expandvars(
+ '%USERPROFILE%\\My Documents\\Visual Studio 2010')
+
+DEFAULT_MS_BUILD_DIRECTORY = os.path.expandvars('%ProgramFiles(x86)%\\MSBuild')
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+ADDIN_FILES = ['NativeClientVSAddIn.AddIn', 'NativeClientVSAddIn.dll']
+
+class InstallError(Exception):
+ """Error class for this installer indicating a fatal but expected error."""
+ pass
+
+def UninstallDirectory(directory):
+ if os.path.exists(directory):
+ shutil.rmtree(directory)
+ print 'Removed: %s' % (directory)
+ else:
+ print 'Failed to remove non-existant directory: %s' % (directory)
+
+
+def UninstallFile(file_path):
+ if os.path.exists(file_path):
+ os.remove(file_path)
+ print 'Removed: %s' % (file_path)
+ else:
+ print 'Failed to remove non-existant file: %s' % (file_path)
+
+
+def Uninstall(nacl_directory, pepper_directory, addin_directory):
+ UninstallDirectory(nacl_directory)
+ UninstallDirectory(pepper_directory)
+ for file_name in ADDIN_FILES:
+ UninstallFile(os.path.join(addin_directory, file_name))
+
+
+def main():
+ parser = optparse.OptionParser(usage='Usage: %prog [options]')
+ parser.add_option('-b', '--msbuild-path', dest='msbuild_path',
+ default=DEFAULT_MS_BUILD_DIRECTORY, metavar='PATH',
+ help='Provide the path to the MSBuild directory')
+ parser.add_option('-a', '--vsuser-path', dest='vsuser_path',
+ default=DEFAULT_VS_USER_DIRECTORY, metavar='PATH',
+ help='Provide the path to the Visual Studio user directory')
+ parser.add_option('-f', '--force', action="store_true", dest='overwrite',
+ default=False, help='Force an overwrite of existing files')
+ parser.add_option('-p', '--ppapi', action="store_true", dest='install_ppapi',
+ help='Install PPAPI template without asking.')
+ parser.add_option('-n', '--no-ppapi', action="store_false",
+ dest='install_ppapi', help='Do not install PPAPI template and do not ask')
+ parser.add_option('-u', '--uninstall', action="store_true",
+ dest='uninstall', help='Remove the add-in.')
+ (options, args) = parser.parse_args()
+
+ print "*************************************************"
+ print "Native-Client Visual Studio 2010 Add-in Installer"
+ print "*************************************************\n"
+ print "Please ensure Visual Studio and MSBuild are closed " \
+ "during installation.\n"
+
+ if platform.system() != 'Windows':
+ raise InstallError('Must install to Windows system')
+
+ if sys.version_info < (2, 6, 2):
+ print "\n\nWARNING: Only python version 2.6.2 or greater is supported. " \
+ "Current version is %s\n\n" % (sys.version_info[:3],)
+
+ # Admin is needed to write to the default platform directory.
+ if ctypes.windll.shell32.IsUserAnAdmin() != 1:
+ raise InstallError("Not running as administrator. The install script needs "
+ "write access to protected Visual Studio directories.")
+
+ # Ensure install directories exist.
+ if not os.path.exists(options.vsuser_path):
+ raise InstallError("Could not find user Visual Studio directory: %s" % (
+ options.vsuser_path))
+ if not os.path.exists(options.msbuild_path):
+ raise InstallError("Could not find MS Build directory: %s" % (
+ options.msbuild_path))
+
+ addin_directory = os.path.join(options.vsuser_path, 'Addins')
+ platform_directory = os.path.join(
+ options.msbuild_path, 'Microsoft.Cpp\\v4.0\\Platforms')
+ nacl_directory = os.path.join(platform_directory, NACL_PLATFORM_NAME)
+ pepper_directory = os.path.join(platform_directory, PEPPER_PLATFORM_NAME)
+
+ # If uninstalling then redirect to uninstall program.
+ if options.uninstall:
+ Uninstall(nacl_directory, pepper_directory, addin_directory)
+ print "\nUninstall complete!\n"
+ exit(0)
+
+ if not os.path.exists(platform_directory):
+ raise InstallError("Could not find path: %s" % platform_directory)
+ if not os.path.exists(addin_directory):
+ os.mkdir(addin_directory)
+
+ # Ensure environment variables are set.
+ nacl_sdk_root = os.getenv('NACL_SDK_ROOT', None)
+ chrome_path = os.getenv('CHROME_PATH', None)
+ if nacl_sdk_root is None:
+ raise InstallError('Environment Variable NACL_SDK_ROOT is not set')
+ if chrome_path is None:
+ raise InstallError('Environment Variable CHROME_PATH is not set')
+
+ # Remove existing installation.
+ if os.path.exists(nacl_directory) or os.path.exists(pepper_directory):
+ # If not forced then ask user permission.
+ if not options.overwrite:
+ print "\nWarning: Pre-existing add-in installation will be overwritten."
+ print "Continue? ((Yes))/((No))"
+ remove_answer = raw_input().strip()
+ if not (remove_answer.lower() == "yes" or remove_answer.lower() == "y"):
+ raise InstallError('User did not allow overwrite of existing install.')
+ print "Removing existing install..."
+ Uninstall(nacl_directory, pepper_directory, addin_directory)
+
+ # Ask user before installing PPAPI template.
+ if options.install_ppapi is None:
+ print "\n"
+ print "Set up configuration to enable Pepper development " \
+ "with Visual Studio?"
+ print "((Yes)) - I want to create and copy relevant files into a " \
+ "Pepper subdirectory"
+ print "((No)) - I am not interested or will set up the configuration later"
+ ppapi_answer = raw_input().strip()
+ if ppapi_answer.lower() == "yes" or ppapi_answer.lower() == "y":
+ options.install_ppapi = True
+ print "Confirmed installer will include PPAPI platform."
+ else:
+ options.install_ppapi = False
+ print "Will not install PPAPI platform during installation."
+
+ print "\nBegin installing components..."
+
+ try:
+ # Copy the necessary files into place.
+ for file_name in ADDIN_FILES:
+ shutil.copy(os.path.join(SCRIPT_DIR, file_name), addin_directory)
+ print "Add-in installed."
+
+ shutil.copytree(os.path.join(SCRIPT_DIR, 'NaCl'), nacl_directory)
+ print "NaCl platform installed."
+
+ if options.install_ppapi:
+ create_ppapi_platform.CreatePPAPI(options.msbuild_path)
+ print "PPAPI platform installed."
+ except:
+ print "\nException occured! Rolling back install...\n"
+ Uninstall(nacl_directory, pepper_directory, addin_directory)
+ raise
+ else:
+ print "\nInstallation complete!\n"
+
+if __name__ == '__main__':
+ try:
+ main()
+ except InstallError as e:
+ print
+ print e
+ except shutil.Error as e:
+ print "Error while copying file. Please ensure file is not in use."
+ print e
+ except WindowsError as e:
+ if e.winerror == 5:
+ print "Access denied error. Please ensure Visual Studio and MSBuild"
+ print "processes are closed."
+ else:
+ raise
+
diff --git a/InstallerResources/third_party/__init__.py b/InstallerResources/third_party/__init__.py
index 5b6a968..93723c7 100644
--- a/InstallerResources/third_party/__init__.py
+++ b/InstallerResources/third_party/__init__.py
@@ -1,31 +1,31 @@
-"""Third party includes for the installer.
-
-Module contains:
-etree -- The ElementTree XML library. This is a subset of the full
- ElementTree XML release.
-
-"""
-
-
-__all__ = ["etree"]
-
-_MINIMUM_XMLPLUS_VERSION = (0, 8, 4)
-
-
-try:
- import _xmlplus
-except ImportError:
- pass
-else:
- try:
- v = _xmlplus.version_info
- except AttributeError:
- # _xmlplus is too old; ignore it
- pass
- else:
- if v >= _MINIMUM_XMLPLUS_VERSION:
- import sys
- _xmlplus.__path__.extend(__path__)
- sys.modules[__name__] = _xmlplus
- else:
- del v
+"""Third party includes for the installer.
+
+Module contains:
+etree -- The ElementTree XML library. This is a subset of the full
+ ElementTree XML release.
+
+"""
+
+
+__all__ = ["etree"]
+
+_MINIMUM_XMLPLUS_VERSION = (0, 8, 4)
+
+
+try:
+ import _xmlplus
+except ImportError:
+ pass
+else:
+ try:
+ v = _xmlplus.version_info
+ except AttributeError:
+ # _xmlplus is too old; ignore it
+ pass
+ else:
+ if v >= _MINIMUM_XMLPLUS_VERSION:
+ import sys
+ _xmlplus.__path__.extend(__path__)
+ sys.modules[__name__] = _xmlplus
+ else:
+ del v
diff --git a/InstallerResources/third_party/etree/ElementInclude.py b/InstallerResources/third_party/etree/ElementInclude.py
index 967d85c..84fd754 100644
--- a/InstallerResources/third_party/etree/ElementInclude.py
+++ b/InstallerResources/third_party/etree/ElementInclude.py
@@ -1,143 +1,143 @@
-#
-# ElementTree
-# $Id: ElementInclude.py 3375 2008-02-13 08:05:08Z fredrik $
-#
-# limited xinclude support for element trees
-#
-# history:
-# 2003-08-15 fl created
-# 2003-11-14 fl fixed default loader
-#
-# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2008 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/psf/license for licensing details.
-
-##
-# Limited XInclude support for the ElementTree package.
-##
-
-import copy
-from . import ElementTree
-
-XINCLUDE = "{http://www.w3.org/2001/XInclude}"
-
-XINCLUDE_INCLUDE = XINCLUDE + "include"
-XINCLUDE_FALLBACK = XINCLUDE + "fallback"
-
-##
-# Fatal include error.
-
-class FatalIncludeError(SyntaxError):
- pass
-
-##
-# Default loader. This loader reads an included resource from disk.
-#
-# @param href Resource reference.
-# @param parse Parse mode. Either "xml" or "text".
-# @param encoding Optional text encoding.
-# @return The expanded resource. If the parse mode is "xml", this
-# is an ElementTree instance. If the parse mode is "text", this
-# is a Unicode string. If the loader fails, it can return None
-# or raise an IOError exception.
-# @throws IOError If the loader fails to load the resource.
-
-def default_loader(href, parse, encoding=None):
- file = open(href)
- if parse == "xml":
- data = ElementTree.parse(file).getroot()
- else:
- data = file.read()
- if encoding:
- data = data.decode(encoding)
- file.close()
- return data
-
-##
-# Expand XInclude directives.
-#
-# @param elem Root element.
-# @param loader Optional resource loader. If omitted, it defaults
-# to {@link default_loader}. If given, it should be a callable
-# that implements the same interface as <b>default_loader</b>.
-# @throws FatalIncludeError If the function fails to include a given
-# resource, or if the tree contains malformed XInclude elements.
-# @throws IOError If the function fails to load a given resource.
-
-def include(elem, loader=None):
- if loader is None:
- loader = default_loader
- # look for xinclude elements
- i = 0
- while i < len(elem):
- e = elem[i]
- if e.tag == XINCLUDE_INCLUDE:
- # process xinclude directive
- href = e.get("href")
- parse = e.get("parse", "xml")
- if parse == "xml":
- node = loader(href, parse)
- if node is None:
- raise FatalIncludeError(
- "cannot load %r as %r" % (href, parse)
- )
- node = copy.copy(node)
- if e.tail:
- node.tail = (node.tail or "") + e.tail
- elem[i] = node
- elif parse == "text":
- text = loader(href, parse, e.get("encoding"))
- if text is None:
- raise FatalIncludeError(
- "cannot load %r as %r" % (href, parse)
- )
- if i:
- node = elem[i-1]
- node.tail = (node.tail or "") + text + (e.tail or "")
- else:
- elem.text = (elem.text or "") + text + (e.tail or "")
- del elem[i]
- continue
- else:
- raise FatalIncludeError(
- "unknown parse type in xi:include tag (%r)" % parse
- )
- elif e.tag == XINCLUDE_FALLBACK:
- raise FatalIncludeError(
- "xi:fallback tag must be child of xi:include (%r)" % e.tag
- )
- else:
- include(e, loader)
- i = i + 1
+#
+# ElementTree
+# $Id: ElementInclude.py 3375 2008-02-13 08:05:08Z fredrik $
+#
+# limited xinclude support for element trees
+#
+# history:
+# 2003-08-15 fl created
+# 2003-11-14 fl fixed default loader
+#
+# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved.
+#
+# fredrik@pythonware.com
+# http://www.pythonware.com
+#
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2008 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/psf/license for licensing details.
+
+##
+# Limited XInclude support for the ElementTree package.
+##
+
+import copy
+from . import ElementTree
+
+XINCLUDE = "{http://www.w3.org/2001/XInclude}"
+
+XINCLUDE_INCLUDE = XINCLUDE + "include"
+XINCLUDE_FALLBACK = XINCLUDE + "fallback"
+
+##
+# Fatal include error.
+
+class FatalIncludeError(SyntaxError):
+ pass
+
+##
+# Default loader. This loader reads an included resource from disk.
+#
+# @param href Resource reference.
+# @param parse Parse mode. Either "xml" or "text".
+# @param encoding Optional text encoding.
+# @return The expanded resource. If the parse mode is "xml", this
+# is an ElementTree instance. If the parse mode is "text", this
+# is a Unicode string. If the loader fails, it can return None
+# or raise an IOError exception.
+# @throws IOError If the loader fails to load the resource.
+
+def default_loader(href, parse, encoding=None):
+ file = open(href)
+ if parse == "xml":
+ data = ElementTree.parse(file).getroot()
+ else:
+ data = file.read()
+ if encoding:
+ data = data.decode(encoding)
+ file.close()
+ return data
+
+##
+# Expand XInclude directives.
+#
+# @param elem Root element.
+# @param loader Optional resource loader. If omitted, it defaults
+# to {@link default_loader}. If given, it should be a callable
+# that implements the same interface as <b>default_loader</b>.
+# @throws FatalIncludeError If the function fails to include a given
+# resource, or if the tree contains malformed XInclude elements.
+# @throws IOError If the function fails to load a given resource.
+
+def include(elem, loader=None):
+ if loader is None:
+ loader = default_loader
+ # look for xinclude elements
+ i = 0
+ while i < len(elem):
+ e = elem[i]
+ if e.tag == XINCLUDE_INCLUDE:
+ # process xinclude directive
+ href = e.get("href")
+ parse = e.get("parse", "xml")
+ if parse == "xml":
+ node = loader(href, parse)
+ if node is None:
+ raise FatalIncludeError(
+ "cannot load %r as %r" % (href, parse)
+ )
+ node = copy.copy(node)
+ if e.tail:
+ node.tail = (node.tail or "") + e.tail
+ elem[i] = node
+ elif parse == "text":
+ text = loader(href, parse, e.get("encoding"))
+ if text is None:
+ raise FatalIncludeError(
+ "cannot load %r as %r" % (href, parse)
+ )
+ if i:
+ node = elem[i-1]
+ node.tail = (node.tail or "") + text + (e.tail or "")
+ else:
+ elem.text = (elem.text or "") + text + (e.tail or "")
+ del elem[i]
+ continue
+ else:
+ raise FatalIncludeError(
+ "unknown parse type in xi:include tag (%r)" % parse
+ )
+ elif e.tag == XINCLUDE_FALLBACK:
+ raise FatalIncludeError(
+ "xi:fallback tag must be child of xi:include (%r)" % e.tag
+ )
+ else:
+ include(e, loader)
+ i = i + 1
diff --git a/InstallerResources/third_party/etree/ElementPath.py b/InstallerResources/third_party/etree/ElementPath.py
index 5c117c3..4a626d7 100644
--- a/InstallerResources/third_party/etree/ElementPath.py
+++ b/InstallerResources/third_party/etree/ElementPath.py
@@ -1,303 +1,303 @@
-#
-# ElementTree
-# $Id: ElementPath.py 3375 2008-02-13 08:05:08Z fredrik $
-#
-# limited xpath support for element trees
-#
-# history:
-# 2003-05-23 fl created
-# 2003-05-28 fl added support for // etc
-# 2003-08-27 fl fixed parsing of periods in element names
-# 2007-09-10 fl new selection engine
-# 2007-09-12 fl fixed parent selector
-# 2007-09-13 fl added iterfind; changed findall to return a list
-# 2007-11-30 fl added namespaces support
-# 2009-10-30 fl added child element value filter
-#
-# Copyright (c) 2003-2009 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2009 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/psf/license for licensing details.
-
-##
-# Implementation module for XPath support. There's usually no reason
-# to import this module directly; the <b>ElementTree</b> does this for
-# you, if needed.
-##
-
-import re
-
-xpath_tokenizer_re = re.compile(
- "("
- "'[^']*'|\"[^\"]*\"|"
- "::|"
- "//?|"
- "\.\.|"
- "\(\)|"
- "[/.*:\[\]\(\)@=])|"
- "((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|"
- "\s+"
- )
-
-def xpath_tokenizer(pattern, namespaces=None):
- for token in xpath_tokenizer_re.findall(pattern):
- tag = token[1]
- if tag and tag[0] != "{" and ":" in tag:
- try:
- prefix, uri = tag.split(":", 1)
- if not namespaces:
- raise KeyError
- yield token[0], "{%s}%s" % (namespaces[prefix], uri)
- except KeyError:
- raise SyntaxError("prefix %r not found in prefix map" % prefix)
- else:
- yield token
-
-def get_parent_map(context):
- parent_map = context.parent_map
- if parent_map is None:
- context.parent_map = parent_map = {}
- for p in context.root.iter():
- for e in p:
- parent_map[e] = p
- return parent_map
-
-def prepare_child(next, token):
- tag = token[1]
- def select(context, result):
- for elem in result:
- for e in elem:
- if e.tag == tag:
- yield e
- return select
-
-def prepare_star(next, token):
- def select(context, result):
- for elem in result:
- for e in elem:
- yield e
- return select
-
-def prepare_self(next, token):
- def select(context, result):
- for elem in result:
- yield elem
- return select
-
-def prepare_descendant(next, token):
- token = next()
- if token[0] == "*":
- tag = "*"
- elif not token[0]:
- tag = token[1]
- else:
- raise SyntaxError("invalid descendant")
- def select(context, result):
- for elem in result:
- for e in elem.iter(tag):
- if e is not elem:
- yield e
- return select
-
-def prepare_parent(next, token):
- def select(context, result):
- # FIXME: raise error if .. is applied at toplevel?
- parent_map = get_parent_map(context)
- result_map = {}
- for elem in result:
- if elem in parent_map:
- parent = parent_map[elem]
- if parent not in result_map:
- result_map[parent] = None
- yield parent
- return select
-
-def prepare_predicate(next, token):
- # FIXME: replace with real parser!!! refs:
- # http://effbot.org/zone/simple-iterator-parser.htm
- # http://javascript.crockford.com/tdop/tdop.html
- signature = []
- predicate = []
- while 1:
- token = next()
- if token[0] == "]":
- break
- if token[0] and token[0][:1] in "'\"":
- token = "'", token[0][1:-1]
- signature.append(token[0] or "-")
- predicate.append(token[1])
- signature = "".join(signature)
- # use signature to determine predicate type
- if signature == "@-":
- # [@attribute] predicate
- key = predicate[1]
- def select(context, result):
- for elem in result:
- if elem.get(key) is not None:
- yield elem
- return select
- if signature == "@-='":
- # [@attribute='value']
- key = predicate[1]
- value = predicate[-1]
- def select(context, result):
- for elem in result:
- if elem.get(key) == value:
- yield elem
- return select
- if signature == "-" and not re.match("\d+$", predicate[0]):
- # [tag]
- tag = predicate[0]
- def select(context, result):
- for elem in result:
- if elem.find(tag) is not None:
- yield elem
- return select
- if signature == "-='" and not re.match("\d+$", predicate[0]):
- # [tag='value']
- tag = predicate[0]
- value = predicate[-1]
- def select(context, result):
- for elem in result:
- for e in elem.findall(tag):
- if "".join(e.itertext()) == value:
- yield elem
- break
- return select
- if signature == "-" or signature == "-()" or signature == "-()-":
- # [index] or [last()] or [last()-index]
- if signature == "-":
- index = int(predicate[0]) - 1
- else:
- if predicate[0] != "last":
- raise SyntaxError("unsupported function")
- if signature == "-()-":
- try:
- index = int(predicate[2]) - 1
- except ValueError:
- raise SyntaxError("unsupported expression")
- else:
- index = -1
- def select(context, result):
- parent_map = get_parent_map(context)
- for elem in result:
- try:
- parent = parent_map[elem]
- # FIXME: what if the selector is "*" ?
- elems = list(parent.findall(elem.tag))
- if elems[index] is elem:
- yield elem
- except (IndexError, KeyError):
- pass
- return select
- raise SyntaxError("invalid predicate")
-
-ops = {
- "": prepare_child,
- "*": prepare_star,
- ".": prepare_self,
- "..": prepare_parent,
- "//": prepare_descendant,
- "[": prepare_predicate,
- }
-
-_cache = {}
-
-class _SelectorContext:
- parent_map = None
- def __init__(self, root):
- self.root = root
-
-# --------------------------------------------------------------------
-
-##
-# Generate all matching objects.
-
-def iterfind(elem, path, namespaces=None):
- # compile selector pattern
- if path[-1:] == "/":
- path = path + "*" # implicit all (FIXME: keep this?)
- try:
- selector = _cache[path]
- except KeyError:
- if len(_cache) > 100:
- _cache.clear()
- if path[:1] == "/":
- raise SyntaxError("cannot use absolute path on element")
- next = iter(xpath_tokenizer(path, namespaces)).next
- token = next()
- selector = []
- while 1:
- try:
- selector.append(ops[token[0]](next, token))
- except StopIteration:
- raise SyntaxError("invalid path")
- try:
- token = next()
- if token[0] == "/":
- token = next()
- except StopIteration:
- break
- _cache[path] = selector
- # execute selector pattern
- result = [elem]
- context = _SelectorContext(elem)
- for select in selector:
- result = select(context, result)
- return result
-
-##
-# Find first matching object.
-
-def find(elem, path, namespaces=None):
- try:
- return iterfind(elem, path, namespaces).next()
- except StopIteration:
- return None
-
-##
-# Find all matching objects.
-
-def findall(elem, path, namespaces=None):
- return list(iterfind(elem, path, namespaces))
-
-##
-# Find text for first matching object.
-
-def findtext(elem, path, default=None, namespaces=None):
- try:
- elem = iterfind(elem, path, namespaces).next()
- return elem.text or ""
- except StopIteration:
- return default
+#
+# ElementTree
+# $Id: ElementPath.py 3375 2008-02-13 08:05:08Z fredrik $
+#
+# limited xpath support for element trees
+#
+# history:
+# 2003-05-23 fl created
+# 2003-05-28 fl added support for // etc
+# 2003-08-27 fl fixed parsing of periods in element names
+# 2007-09-10 fl new selection engine
+# 2007-09-12 fl fixed parent selector
+# 2007-09-13 fl added iterfind; changed findall to return a list
+# 2007-11-30 fl added namespaces support
+# 2009-10-30 fl added child element value filter
+#
+# Copyright (c) 2003-2009 by Fredrik Lundh. All rights reserved.
+#
+# fredrik@pythonware.com
+# http://www.pythonware.com
+#
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2009 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/psf/license for licensing details.
+
+##
+# Implementation module for XPath support. There's usually no reason
+# to import this module directly; the <b>ElementTree</b> does this for
+# you, if needed.
+##
+
+import re
+
+xpath_tokenizer_re = re.compile(
+ "("
+ "'[^']*'|\"[^\"]*\"|"
+ "::|"
+ "//?|"
+ "\.\.|"
+ "\(\)|"
+ "[/.*:\[\]\(\)@=])|"
+ "((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|"
+ "\s+"
+ )
+
+def xpath_tokenizer(pattern, namespaces=None):
+ for token in xpath_tokenizer_re.findall(pattern):
+ tag = token[1]
+ if tag and tag[0] != "{" and ":" in tag:
+ try:
+ prefix, uri = tag.split(":", 1)
+ if not namespaces:
+ raise KeyError
+ yield token[0], "{%s}%s" % (namespaces[prefix], uri)
+ except KeyError:
+ raise SyntaxError("prefix %r not found in prefix map" % prefix)
+ else:
+ yield token
+
+def get_parent_map(context):
+ parent_map = context.parent_map
+ if parent_map is None:
+ context.parent_map = parent_map = {}
+ for p in context.root.iter():
+ for e in p:
+ parent_map[e] = p
+ return parent_map
+
+def prepare_child(next, token):
+ tag = token[1]
+ def select(context, result):
+ for elem in result:
+ for e in elem:
+ if e.tag == tag:
+ yield e
+ return select
+
+def prepare_star(next, token):
+ def select(context, result):
+ for elem in result:
+ for e in elem:
+ yield e
+ return select
+
+def prepare_self(next, token):
+ def select(context, result):
+ for elem in result:
+ yield elem
+ return select
+
+def prepare_descendant(next, token):
+ token = next()
+ if token[0] == "*":
+ tag = "*"
+ elif not token[0]:
+ tag = token[1]
+ else:
+ raise SyntaxError("invalid descendant")
+ def select(context, result):
+ for elem in result:
+ for e in elem.iter(tag):
+ if e is not elem:
+ yield e
+ return select
+
+def prepare_parent(next, token):
+ def select(context, result):
+ # FIXME: raise error if .. is applied at toplevel?
+ parent_map = get_parent_map(context)
+ result_map = {}
+ for elem in result:
+ if elem in parent_map:
+ parent = parent_map[elem]
+ if parent not in result_map:
+ result_map[parent] = None
+ yield parent
+ return select
+
+def prepare_predicate(next, token):
+ # FIXME: replace with real parser!!! refs:
+ # http://effbot.org/zone/simple-iterator-parser.htm
+ # http://javascript.crockford.com/tdop/tdop.html
+ signature = []
+ predicate = []
+ while 1:
+ token = next()
+ if token[0] == "]":
+ break
+ if token[0] and token[0][:1] in "'\"":
+ token = "'", token[0][1:-1]
+ signature.append(token[0] or "-")
+ predicate.append(token[1])
+ signature = "".join(signature)
+ # use signature to determine predicate type
+ if signature == "@-":
+ # [@attribute] predicate
+ key = predicate[1]
+ def select(context, result):
+ for elem in result:
+ if elem.get(key) is not None:
+ yield elem
+ return select
+ if signature == "@-='":
+ # [@attribute='value']
+ key = predicate[1]
+ value = predicate[-1]
+ def select(context, result):
+ for elem in result:
+ if elem.get(key) == value:
+ yield elem
+ return select
+ if signature == "-" and not re.match("\d+$", predicate[0]):
+ # [tag]
+ tag = predicate[0]
+ def select(context, result):
+ for elem in result:
+ if elem.find(tag) is not None:
+ yield elem
+ return select
+ if signature == "-='" and not re.match("\d+$", predicate[0]):
+ # [tag='value']
+ tag = predicate[0]
+ value = predicate[-1]
+ def select(context, result):
+ for elem in result:
+ for e in elem.findall(tag):
+ if "".join(e.itertext()) == value:
+ yield elem
+ break
+ return select
+ if signature == "-" or signature == "-()" or signature == "-()-":
+ # [index] or [last()] or [last()-index]
+ if signature == "-":
+ index = int(predicate[0]) - 1
+ else:
+ if predicate[0] != "last":
+ raise SyntaxError("unsupported function")
+ if signature == "-()-":
+ try:
+ index = int(predicate[2]) - 1
+ except ValueError:
+ raise SyntaxError("unsupported expression")
+ else:
+ index = -1
+ def select(context, result):
+ parent_map = get_parent_map(context)
+ for elem in result:
+ try:
+ parent = parent_map[elem]
+ # FIXME: what if the selector is "*" ?
+ elems = list(parent.findall(elem.tag))
+ if elems[index] is elem:
+ yield elem
+ except (IndexError, KeyError):
+ pass
+ return select
+ raise SyntaxError("invalid predicate")
+
+ops = {
+ "": prepare_child,
+ "*": prepare_star,
+ ".": prepare_self,
+ "..": prepare_parent,
+ "//": prepare_descendant,
+ "[": prepare_predicate,
+ }
+
+_cache = {}
+
+class _SelectorContext:
+ parent_map = None
+ def __init__(self, root):
+ self.root = root
+
+# --------------------------------------------------------------------
+
+##
+# Generate all matching objects.
+
+def iterfind(elem, path, namespaces=None):
+ # compile selector pattern
+ if path[-1:] == "/":
+ path = path + "*" # implicit all (FIXME: keep this?)
+ try:
+ selector = _cache[path]
+ except KeyError:
+ if len(_cache) > 100:
+ _cache.clear()
+ if path[:1] == "/":
+ raise SyntaxError("cannot use absolute path on element")
+ next = iter(xpath_tokenizer(path, namespaces)).next
+ token = next()
+ selector = []
+ while 1:
+ try:
+ selector.append(ops[token[0]](next, token))
+ except StopIteration:
+ raise SyntaxError("invalid path")
+ try:
+ token = next()
+ if token[0] == "/":
+ token = next()
+ except StopIteration:
+ break
+ _cache[path] = selector
+ # execute selector pattern
+ result = [elem]
+ context = _SelectorContext(elem)
+ for select in selector:
+ result = select(context, result)
+ return result
+
+##
+# Find first matching object.
+
+def find(elem, path, namespaces=None):
+ try:
+ return iterfind(elem, path, namespaces).next()
+ except StopIteration:
+ return None
+
+##
+# Find all matching objects.
+
+def findall(elem, path, namespaces=None):
+ return list(iterfind(elem, path, namespaces))
+
+##
+# Find text for first matching object.
+
+def findtext(elem, path, default=None, namespaces=None):
+ try:
+ elem = iterfind(elem, path, namespaces).next()
+ return elem.text or ""
+ except StopIteration:
+ return default
diff --git a/InstallerResources/third_party/etree/ElementTree.py b/InstallerResources/third_party/etree/ElementTree.py
index ffbe01e..2b0cf0c 100644
--- a/InstallerResources/third_party/etree/ElementTree.py
+++ b/InstallerResources/third_party/etree/ElementTree.py
@@ -1,1668 +1,1668 @@
-#
-# ElementTree
-# $Id: ElementTree.py 3440 2008-07-18 14:45:01Z fredrik $
-#
-# light-weight XML support for Python 2.3 and later.
-#
-# history (since 1.2.6):
-# 2005-11-12 fl added tostringlist/fromstringlist helpers
-# 2006-07-05 fl merged in selected changes from the 1.3 sandbox
-# 2006-07-05 fl removed support for 2.1 and earlier
-# 2007-06-21 fl added deprecation/future warnings
-# 2007-08-25 fl added doctype hook, added parser version attribute etc
-# 2007-08-26 fl added new serializer code (better namespace handling, etc)
-# 2007-08-27 fl warn for broken /tag searches on tree level
-# 2007-09-02 fl added html/text methods to serializer (experimental)
-# 2007-09-05 fl added method argument to tostring/tostringlist
-# 2007-09-06 fl improved error handling
-# 2007-09-13 fl added itertext, iterfind; assorted cleanups
-# 2007-12-15 fl added C14N hooks, copy method (experimental)
-#
-# Copyright (c) 1999-2008 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2008 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/psf/license for licensing details.
-
-__all__ = [
- # public symbols
- "Comment",
- "dump",
- "Element", "ElementTree",
- "fromstring", "fromstringlist",
- "iselement", "iterparse",
- "parse", "ParseError",
- "PI", "ProcessingInstruction",
- "QName",
- "SubElement",
- "tostring", "tostringlist",
- "TreeBuilder",
- "VERSION",
- "XML",
- "XMLParser", "XMLTreeBuilder",
- ]
-
-VERSION = "1.3.0"
-
-##
-# The <b>Element</b> type is a flexible container object, designed to
-# store hierarchical data structures in memory. The type can be
-# described as a cross between a list and a dictionary.
-# <p>
-# Each element has a number of properties associated with it:
-# <ul>
-# <li>a <i>tag</i>. This is a string identifying what kind of data
-# this element represents (the element type, in other words).</li>
-# <li>a number of <i>attributes</i>, stored in a Python dictionary.</li>
-# <li>a <i>text</i> string.</li>
-# <li>an optional <i>tail</i> string.</li>
-# <li>a number of <i>child elements</i>, stored in a Python sequence</li>
-# </ul>
-#
-# To create an element instance, use the {@link #Element} constructor
-# or the {@link #SubElement} factory function.
-# <p>
-# The {@link #ElementTree} class can be used to wrap an element
-# structure, and convert it from and to XML.
-##
-
-import sys
-import re
-import warnings
-
-
-class _SimpleElementPath(object):
- # emulate pre-1.2 find/findtext/findall behaviour
- def find(self, element, tag, namespaces=None):
- for elem in element:
- if elem.tag == tag:
- return elem
- return None
- def findtext(self, element, tag, default=None, namespaces=None):
- elem = self.find(element, tag)
- if elem is None:
- return default
- return elem.text or ""
- def iterfind(self, element, tag, namespaces=None):
- if tag[:3] == ".//":
- for elem in element.iter(tag[3:]):
- yield elem
- for elem in element:
- if elem.tag == tag:
- yield elem
- def findall(self, element, tag, namespaces=None):
- return list(self.iterfind(element, tag, namespaces))
-
-try:
- from . import ElementPath
-except ImportError:
- ElementPath = _SimpleElementPath()
-
-##
-# Parser error. This is a subclass of <b>SyntaxError</b>.
-# <p>
-# In addition to the exception value, an exception instance contains a
-# specific exception code in the <b>code</b> attribute, and the line and
-# column of the error in the <b>position</b> attribute.
-
-class ParseError(SyntaxError):
- pass
-
-# --------------------------------------------------------------------
-
-##
-# Checks if an object appears to be a valid element object.
-#
-# @param An element instance.
-# @return A true value if this is an element object.
-# @defreturn flag
-
-def iselement(element):
- # FIXME: not sure about this; might be a better idea to look
- # for tag/attrib/text attributes
- return isinstance(element, Element) or hasattr(element, "tag")
-
-##
-# Element class. This class defines the Element interface, and
-# provides a reference implementation of this interface.
-# <p>
-# The element name, attribute names, and attribute values can be
-# either ASCII strings (ordinary Python strings containing only 7-bit
-# ASCII characters) or Unicode strings.
-#
-# @param tag The element name.
-# @param attrib An optional dictionary, containing element attributes.
-# @param **extra Additional attributes, given as keyword arguments.
-# @see Element
-# @see SubElement
-# @see Comment
-# @see ProcessingInstruction
-
-class Element(object):
- # <tag attrib>text<child/>...</tag>tail
-
- ##
- # (Attribute) Element tag.
-
- tag = None
-
- ##
- # (Attribute) Element attribute dictionary. Where possible, use
- # {@link #Element.get},
- # {@link #Element.set},
- # {@link #Element.keys}, and
- # {@link #Element.items} to access
- # element attributes.
-
- attrib = None
-
- ##
- # (Attribute) Text before first subelement. This is either a
- # string or the value None. Note that if there was no text, this
- # attribute may be either None or an empty string, depending on
- # the parser.
-
- text = None
-
- ##
- # (Attribute) Text after this element's end tag, but before the
- # next sibling element's start tag. This is either a string or
- # the value None. Note that if there was no text, this attribute
- # may be either None or an empty string, depending on the parser.
-
- tail = None # text after end tag, if any
-
- # constructor
-
- def __init__(self, tag, attrib={}, **extra):
- attrib = attrib.copy()
- attrib.update(extra)
- self.tag = tag
- self.attrib = attrib
- self._children = []
-
- def __repr__(self):
- return "<Element %s at 0x%x>" % (repr(self.tag), id(self))
-
- ##
- # Creates a new element object of the same type as this element.
- #
- # @param tag Element tag.
- # @param attrib Element attributes, given as a dictionary.
- # @return A new element instance.
-
- def makeelement(self, tag, attrib):
- return self.__class__(tag, attrib)
-
- ##
- # (Experimental) Copies the current element. This creates a
- # shallow copy; subelements will be shared with the original tree.
- #
- # @return A new element instance.
-
- def copy(self):
- elem = self.makeelement(self.tag, self.attrib)
- elem.text = self.text
- elem.tail = self.tail
- elem[:] = self
- return elem
-
- ##
- # Returns the number of subelements. Note that this only counts
- # full elements; to check if there's any content in an element, you
- # have to check both the length and the <b>text</b> attribute.
- #
- # @return The number of subelements.
-
- def __len__(self):
- return len(self._children)
-
- def __nonzero__(self):
- warnings.warn(
- "The behavior of this method will change in future versions. "
- "Use specific 'len(elem)' or 'elem is not None' test instead.",
- FutureWarning, stacklevel=2
- )
- return len(self._children) != 0 # emulate old behaviour, for now
-
- ##
- # Returns the given subelement, by index.
- #
- # @param index What subelement to return.
- # @return The given subelement.
- # @exception IndexError If the given element does not exist.
-
- def __getitem__(self, index):
- return self._children[index]
-
- ##
- # Replaces the given subelement, by index.
- #
- # @param index What subelement to replace.
- # @param element The new element value.
- # @exception IndexError If the given element does not exist.
-
- def __setitem__(self, index, element):
- # if isinstance(index, slice):
- # for elt in element:
- # assert iselement(elt)
- # else:
- # assert iselement(element)
- self._children[index] = element
-
- ##
- # Deletes the given subelement, by index.
- #
- # @param index What subelement to delete.
- # @exception IndexError If the given element does not exist.
-
- def __delitem__(self, index):
- del self._children[index]
-
- ##
- # Adds a subelement to the end of this element. In document order,
- # the new element will appear after the last existing subelement (or
- # directly after the text, if it's the first subelement), but before
- # the end tag for this element.
- #
- # @param element The element to add.
-
- def append(self, element):
- # assert iselement(element)
- self._children.append(element)
-
- ##
- # Appends subelements from a sequence.
- #
- # @param elements A sequence object with zero or more elements.
- # @since 1.3
-
- def extend(self, elements):
- # for element in elements:
- # assert iselement(element)
- self._children.extend(elements)
-
- ##
- # Inserts a subelement at the given position in this element.
- #
- # @param index Where to insert the new subelement.
-
- def insert(self, index, element):
- # assert iselement(element)
- self._children.insert(index, element)
-
- ##
- # Removes a matching subelement. Unlike the <b>find</b> methods,
- # this method compares elements based on identity, not on tag
- # value or contents. To remove subelements by other means, the
- # easiest way is often to use a list comprehension to select what
- # elements to keep, and use slice assignment to update the parent
- # element.
- #
- # @param element What element to remove.
- # @exception ValueError If a matching element could not be found.
-
- def remove(self, element):
- # assert iselement(element)
- self._children.remove(element)
-
- ##
- # (Deprecated) Returns all subelements. The elements are returned
- # in document order.
- #
- # @return A list of subelements.
- # @defreturn list of Element instances
-
- def getchildren(self):
- warnings.warn(
- "This method will be removed in future versions. "
- "Use 'list(elem)' or iteration over elem instead.",
- DeprecationWarning, stacklevel=2
- )
- return self._children
-
- ##
- # Finds the first matching subelement, by tag name or path.
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return The first matching element, or None if no element was found.
- # @defreturn Element or None
-
- def find(self, path, namespaces=None):
- return ElementPath.find(self, path, namespaces)
-
- ##
- # Finds text for the first matching subelement, by tag name or path.
- #
- # @param path What element to look for.
- # @param default What to return if the element was not found.
- # @keyparam namespaces Optional namespace prefix map.
- # @return The text content of the first matching element, or the
- # default value no element was found. Note that if the element
- # is found, but has no text content, this method returns an
- # empty string.
- # @defreturn string
-
- def findtext(self, path, default=None, namespaces=None):
- return ElementPath.findtext(self, path, default, namespaces)
-
- ##
- # Finds all matching subelements, by tag name or path.
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return A list or other sequence containing all matching elements,
- # in document order.
- # @defreturn list of Element instances
-
- def findall(self, path, namespaces=None):
- return ElementPath.findall(self, path, namespaces)
-
- ##
- # Finds all matching subelements, by tag name or path.
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return An iterator or sequence containing all matching elements,
- # in document order.
- # @defreturn a generated sequence of Element instances
-
- def iterfind(self, path, namespaces=None):
- return ElementPath.iterfind(self, path, namespaces)
-
- ##
- # Resets an element. This function removes all subelements, clears
- # all attributes, and sets the <b>text</b> and <b>tail</b> attributes
- # to None.
-
- def clear(self):
- self.attrib.clear()
- self._children = []
- self.text = self.tail = None
-
- ##
- # Gets an element attribute. Equivalent to <b>attrib.get</b>, but
- # some implementations may handle this a bit more efficiently.
- #
- # @param key What attribute to look for.
- # @param default What to return if the attribute was not found.
- # @return The attribute value, or the default value, if the
- # attribute was not found.
- # @defreturn string or None
-
- def get(self, key, default=None):
- return self.attrib.get(key, default)
-
- ##
- # Sets an element attribute. Equivalent to <b>attrib[key] = value</b>,
- # but some implementations may handle this a bit more efficiently.
- #
- # @param key What attribute to set.
- # @param value The attribute value.
-
- def set(self, key, value):
- self.attrib[key] = value
-
- ##
- # Gets a list of attribute names. The names are returned in an
- # arbitrary order (just like for an ordinary Python dictionary).
- # Equivalent to <b>attrib.keys()</b>.
- #
- # @return A list of element attribute names.
- # @defreturn list of strings
-
- def keys(self):
- return self.attrib.keys()
-
- ##
- # Gets element attributes, as a sequence. The attributes are
- # returned in an arbitrary order. Equivalent to <b>attrib.items()</b>.
- #
- # @return A list of (name, value) tuples for all attributes.
- # @defreturn list of (string, string) tuples
-
- def items(self):
- return self.attrib.items()
-
- ##
- # Creates a tree iterator. The iterator loops over this element
- # and all subelements, in document order, and returns all elements
- # with a matching tag.
- # <p>
- # If the tree structure is modified during iteration, new or removed
- # elements may or may not be included. To get a stable set, use the
- # list() function on the iterator, and loop over the resulting list.
- #
- # @param tag What tags to look for (default is to return all elements).
- # @return An iterator containing all the matching elements.
- # @defreturn iterator
-
- def iter(self, tag=None):
- if tag == "*":
- tag = None
- if tag is None or self.tag == tag:
- yield self
- for e in self._children:
- for e in e.iter(tag):
- yield e
-
- # compatibility
- def getiterator(self, tag=None):
- # Change for a DeprecationWarning in 1.4
- warnings.warn(
- "This method will be removed in future versions. "
- "Use 'elem.iter()' or 'list(elem.iter())' instead.",
- PendingDeprecationWarning, stacklevel=2
- )
- return list(self.iter(tag))
-
- ##
- # Creates a text iterator. The iterator loops over this element
- # and all subelements, in document order, and returns all inner
- # text.
- #
- # @return An iterator containing all inner text.
- # @defreturn iterator
-
- def itertext(self):
- tag = self.tag
- if not isinstance(tag, basestring) and tag is not None:
- return
- if self.text:
- yield self.text
- for e in self:
- for s in e.itertext():
- yield s
- if e.tail:
- yield e.tail
-
-# compatibility
-_Element = _ElementInterface = Element
-
-##
-# Subelement factory. This function creates an element instance, and
-# appends it to an existing element.
-# <p>
-# The element name, attribute names, and attribute values can be
-# either 8-bit ASCII strings or Unicode strings.
-#
-# @param parent The parent element.
-# @param tag The subelement name.
-# @param attrib An optional dictionary, containing element attributes.
-# @param **extra Additional attributes, given as keyword arguments.
-# @return An element instance.
-# @defreturn Element
-
-def SubElement(parent, tag, attrib={}, **extra):
- attrib = attrib.copy()
- attrib.update(extra)
- element = parent.makeelement(tag, attrib)
- parent.append(element)
- return element
-
-##
-# Comment element factory. This factory function creates a special
-# element that will be serialized as an XML comment by the standard
-# serializer.
-# <p>
-# The comment string can be either an 8-bit ASCII string or a Unicode
-# string.
-#
-# @param text A string containing the comment string.
-# @return An element instance, representing a comment.
-# @defreturn Element
-
-def Comment(text=None):
- element = Element(Comment)
- element.text = text
- return element
-
-##
-# PI element factory. This factory function creates a special element
-# that will be serialized as an XML processing instruction by the standard
-# serializer.
-#
-# @param target A string containing the PI target.
-# @param text A string containing the PI contents, if any.
-# @return An element instance, representing a PI.
-# @defreturn Element
-
-def ProcessingInstruction(target, text=None):
- element = Element(ProcessingInstruction)
- element.text = target
- if text:
- element.text = element.text + " " + text
- return element
-
-PI = ProcessingInstruction
-
-##
-# QName wrapper. This can be used to wrap a QName attribute value, in
-# order to get proper namespace handling on output.
-#
-# @param text A string containing the QName value, in the form {uri}local,
-# or, if the tag argument is given, the URI part of a QName.
-# @param tag Optional tag. If given, the first argument is interpreted as
-# an URI, and this argument is interpreted as a local name.
-# @return An opaque object, representing the QName.
-
-class QName(object):
- def __init__(self, text_or_uri, tag=None):
- if tag:
- text_or_uri = "{%s}%s" % (text_or_uri, tag)
- self.text = text_or_uri
- def __str__(self):
- return self.text
- def __hash__(self):
- return hash(self.text)
- def __cmp__(self, other):
- if isinstance(other, QName):
- return cmp(self.text, other.text)
- return cmp(self.text, other)
-
-# --------------------------------------------------------------------
-
-##
-# ElementTree wrapper class. This class represents an entire element
-# hierarchy, and adds some extra support for serialization to and from
-# standard XML.
-#
-# @param element Optional root element.
-# @keyparam file Optional file handle or file name. If given, the
-# tree is initialized with the contents of this XML file.
-
-class ElementTree(object):
-
- def __init__(self, element=None, file=None):
- # assert element is None or iselement(element)
- self._root = element # first node
- if file:
- self.parse(file)
-
- ##
- # Gets the root element for this tree.
- #
- # @return An element instance.
- # @defreturn Element
-
- def getroot(self):
- return self._root
-
- ##
- # Replaces the root element for this tree. This discards the
- # current contents of the tree, and replaces it with the given
- # element. Use with care.
- #
- # @param element An element instance.
-
- def _setroot(self, element):
- # assert iselement(element)
- self._root = element
-
- ##
- # Loads an external XML document into this element tree.
- #
- # @param source A file name or file object. If a file object is
- # given, it only has to implement a <b>read(n)</b> method.
- # @keyparam parser An optional parser instance. If not given, the
- # standard {@link XMLParser} parser is used.
- # @return The document root element.
- # @defreturn Element
- # @exception ParseError If the parser fails to parse the document.
-
- def parse(self, source, parser=None):
- close_source = False
- if not hasattr(source, "read"):
- source = open(source, "rb")
- close_source = True
- try:
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- while 1:
- data = source.read(65536)
- if not data:
- break
- parser.feed(data)
- self._root = parser.close()
- return self._root
- finally:
- if close_source:
- source.close()
-
- ##
- # Creates a tree iterator for the root element. The iterator loops
- # over all elements in this tree, in document order.
- #
- # @param tag What tags to look for (default is to return all elements)
- # @return An iterator.
- # @defreturn iterator
-
- def iter(self, tag=None):
- # assert self._root is not None
- return self._root.iter(tag)
-
- # compatibility
- def getiterator(self, tag=None):
- # Change for a DeprecationWarning in 1.4
- warnings.warn(
- "This method will be removed in future versions. "
- "Use 'tree.iter()' or 'list(tree.iter())' instead.",
- PendingDeprecationWarning, stacklevel=2
- )
- return list(self.iter(tag))
-
- ##
- # Finds the first toplevel element with given tag.
- # Same as getroot().find(path).
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return The first matching element, or None if no element was found.
- # @defreturn Element or None
-
- def find(self, path, namespaces=None):
- # assert self._root is not None
- if path[:1] == "/":
- path = "." + path
- warnings.warn(
- "This search is broken in 1.3 and earlier, and will be "
- "fixed in a future version. If you rely on the current "
- "behaviour, change it to %r" % path,
- FutureWarning, stacklevel=2
- )
- return self._root.find(path, namespaces)
-
- ##
- # Finds the element text for the first toplevel element with given
- # tag. Same as getroot().findtext(path).
- #
- # @param path What toplevel element to look for.
- # @param default What to return if the element was not found.
- # @keyparam namespaces Optional namespace prefix map.
- # @return The text content of the first matching element, or the
- # default value no element was found. Note that if the element
- # is found, but has no text content, this method returns an
- # empty string.
- # @defreturn string
-
- def findtext(self, path, default=None, namespaces=None):
- # assert self._root is not None
- if path[:1] == "/":
- path = "." + path
- warnings.warn(
- "This search is broken in 1.3 and earlier, and will be "
- "fixed in a future version. If you rely on the current "
- "behaviour, change it to %r" % path,
- FutureWarning, stacklevel=2
- )
- return self._root.findtext(path, default, namespaces)
-
- ##
- # Finds all toplevel elements with the given tag.
- # Same as getroot().findall(path).
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return A list or iterator containing all matching elements,
- # in document order.
- # @defreturn list of Element instances
-
- def findall(self, path, namespaces=None):
- # assert self._root is not None
- if path[:1] == "/":
- path = "." + path
- warnings.warn(
- "This search is broken in 1.3 and earlier, and will be "
- "fixed in a future version. If you rely on the current "
- "behaviour, change it to %r" % path,
- FutureWarning, stacklevel=2
- )
- return self._root.findall(path, namespaces)
-
- ##
- # Finds all matching subelements, by tag name or path.
- # Same as getroot().iterfind(path).
- #
- # @param path What element to look for.
- # @keyparam namespaces Optional namespace prefix map.
- # @return An iterator or sequence containing all matching elements,
- # in document order.
- # @defreturn a generated sequence of Element instances
-
- def iterfind(self, path, namespaces=None):
- # assert self._root is not None
- if path[:1] == "/":
- path = "." + path
- warnings.warn(
- "This search is broken in 1.3 and earlier, and will be "
- "fixed in a future version. If you rely on the current "
- "behaviour, change it to %r" % path,
- FutureWarning, stacklevel=2
- )
- return self._root.iterfind(path, namespaces)
-
- ##
- # Writes the element tree to a file, as XML.
- #
- # @def write(file, **options)
- # @param file A file name, or a file object opened for writing.
- # @param **options Options, given as keyword arguments.
- # @keyparam encoding Optional output encoding (default is US-ASCII).
- # @keyparam method Optional output method ("xml", "html", "text" or
- # "c14n"; default is "xml").
- # @keyparam xml_declaration Controls if an XML declaration should
- # be added to the file. Use False for never, True for always,
- # None for only if not US-ASCII or UTF-8. None is default.
-
- def write(self, file_or_filename,
- # keyword arguments
- encoding=None,
- xml_declaration=None,
- default_namespace=None,
- method=None):
- # assert self._root is not None
- if not method:
- method = "xml"
- elif method not in _serialize:
- # FIXME: raise an ImportError for c14n if ElementC14N is missing?
- raise ValueError("unknown method %r" % method)
- if hasattr(file_or_filename, "write"):
- file = file_or_filename
- else:
- file = open(file_or_filename, "wb")
- write = file.write
- if not encoding:
- if method == "c14n":
- encoding = "utf-8"
- else:
- encoding = "us-ascii"
- elif xml_declaration or (xml_declaration is None and
- encoding not in ("utf-8", "us-ascii")):
- if method == "xml":
- write("<?xml version='1.0' encoding='%s'?>\n" % encoding)
- if method == "text":
- _serialize_text(write, self._root, encoding)
- else:
- qnames, namespaces = _namespaces(
- self._root, encoding, default_namespace
- )
- serialize = _serialize[method]
- serialize(write, self._root, encoding, qnames, namespaces)
- if file_or_filename is not file:
- file.close()
-
- def write_c14n(self, file):
- # lxml.etree compatibility. use output method instead
- return self.write(file, method="c14n")
-
-# --------------------------------------------------------------------
-# serialization support
-
-def _namespaces(elem, encoding, default_namespace=None):
- # identify namespaces used in this tree
-
- # maps qnames to *encoded* prefix:local names
- qnames = {None: None}
-
- # maps uri:s to prefixes
- namespaces = {}
- if default_namespace:
- namespaces[default_namespace] = ""
-
- def encode(text):
- return text.encode(encoding)
-
- def add_qname(qname):
- # calculate serialized qname representation
- try:
- if qname[:1] == "{":
- uri, tag = qname[1:].rsplit("}", 1)
- prefix = namespaces.get(uri)
- if prefix is None:
- prefix = _namespace_map.get(uri)
- if prefix is None:
- prefix = "ns%d" % len(namespaces)
- if prefix != "xml":
- namespaces[uri] = prefix
- if prefix:
- qnames[qname] = encode("%s:%s" % (prefix, tag))
- else:
- qnames[qname] = encode(tag) # default element
- else:
- if default_namespace:
- # FIXME: can this be handled in XML 1.0?
- raise ValueError(
- "cannot use non-qualified names with "
- "default_namespace option"
- )
- qnames[qname] = encode(qname)
- except TypeError:
- _raise_serialization_error(qname)
-
- # populate qname and namespaces table
- try:
- iterate = elem.iter
- except AttributeError:
- iterate = elem.getiterator # cET compatibility
- for elem in iterate():
- tag = elem.tag
- if isinstance(tag, QName):
- if tag.text not in qnames:
- add_qname(tag.text)
- elif isinstance(tag, basestring):
- if tag not in qnames:
- add_qname(tag)
- elif tag is not None and tag is not Comment and tag is not PI:
- _raise_serialization_error(tag)
- for key, value in elem.items():
- if isinstance(key, QName):
- key = key.text
- if key not in qnames:
- add_qname(key)
- if isinstance(value, QName) and value.text not in qnames:
- add_qname(value.text)
- text = elem.text
- if isinstance(text, QName) and text.text not in qnames:
- add_qname(text.text)
- return qnames, namespaces
-
-def _serialize_xml(write, elem, encoding, qnames, namespaces):
- tag = elem.tag
- text = elem.text
- if tag is Comment:
- write("<!--%s-->" % _encode(text, encoding))
- elif tag is ProcessingInstruction:
- write("<?%s?>" % _encode(text, encoding))
- else:
- tag = qnames[tag]
- if tag is None:
- if text:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_xml(write, e, encoding, qnames, None)
- else:
- write("<" + tag)
- items = elem.items()
- if items or namespaces:
- if namespaces:
- for v, k in sorted(namespaces.items(),
- key=lambda x: x[1]): # sort on prefix
- if k:
- k = ":" + k
- write(" xmlns%s=\"%s\"" % (
- k.encode(encoding),
- _escape_attrib(v, encoding)
- ))
- for k, v in sorted(items): # lexical order
- if isinstance(k, QName):
- k = k.text
- if isinstance(v, QName):
- v = qnames[v.text]
- else:
- v = _escape_attrib(v, encoding)
- write(" %s=\"%s\"" % (qnames[k], v))
- if text or len(elem):
- write(">")
- if text:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_xml(write, e, encoding, qnames, None)
- write("</" + tag + ">")
- else:
- write(" />")
- if elem.tail:
- write(_escape_cdata(elem.tail, encoding))
-
-HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
- "img", "input", "isindex", "link", "meta" "param")
-
-try:
- HTML_EMPTY = set(HTML_EMPTY)
-except NameError:
- pass
-
-def _serialize_html(write, elem, encoding, qnames, namespaces):
- tag = elem.tag
- text = elem.text
- if tag is Comment:
- write("<!--%s-->" % _escape_cdata(text, encoding))
- elif tag is ProcessingInstruction:
- write("<?%s?>" % _escape_cdata(text, encoding))
- else:
- tag = qnames[tag]
- if tag is None:
- if text:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_html(write, e, encoding, qnames, None)
- else:
- write("<" + tag)
- items = elem.items()
- if items or namespaces:
- if namespaces:
- for v, k in sorted(namespaces.items(),
- key=lambda x: x[1]): # sort on prefix
- if k:
- k = ":" + k
- write(" xmlns%s=\"%s\"" % (
- k.encode(encoding),
- _escape_attrib(v, encoding)
- ))
- for k, v in sorted(items): # lexical order
- if isinstance(k, QName):
- k = k.text
- if isinstance(v, QName):
- v = qnames[v.text]
- else:
- v = _escape_attrib_html(v, encoding)
- # FIXME: handle boolean attributes
- write(" %s=\"%s\"" % (qnames[k], v))
- write(">")
- tag = tag.lower()
- if text:
- if tag == "script" or tag == "style":
- write(_encode(text, encoding))
- else:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_html(write, e, encoding, qnames, None)
- if tag not in HTML_EMPTY:
- write("</" + tag + ">")
- if elem.tail:
- write(_escape_cdata(elem.tail, encoding))
-
-def _serialize_text(write, elem, encoding):
- for part in elem.itertext():
- write(part.encode(encoding))
- if elem.tail:
- write(elem.tail.encode(encoding))
-
-_serialize = {
- "xml": _serialize_xml,
- "html": _serialize_html,
- "text": _serialize_text,
-# this optional method is imported at the end of the module
-# "c14n": _serialize_c14n,
-}
-
-##
-# Registers a namespace prefix. The registry is global, and any
-# existing mapping for either the given prefix or the namespace URI
-# will be removed.
-#
-# @param prefix Namespace prefix.
-# @param uri Namespace uri. Tags and attributes in this namespace
-# will be serialized with the given prefix, if at all possible.
-# @exception ValueError If the prefix is reserved, or is otherwise
-# invalid.
-
-def register_namespace(prefix, uri):
- if re.match("ns\d+$", prefix):
- raise ValueError("Prefix format reserved for internal use")
- for k, v in _namespace_map.items():
- if k == uri or v == prefix:
- del _namespace_map[k]
- _namespace_map[uri] = prefix
-
-_namespace_map = {
- # "well-known" namespace prefixes
- "http://www.w3.org/XML/1998/namespace": "xml",
- "http://www.w3.org/1999/xhtml": "html",
- "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
- "http://schemas.xmlsoap.org/wsdl/": "wsdl",
- # xml schema
- "http://www.w3.org/2001/XMLSchema": "xs",
- "http://www.w3.org/2001/XMLSchema-instance": "xsi",
- # dublin core
- "http://purl.org/dc/elements/1.1/": "dc",
-}
-
-def _raise_serialization_error(text):
- raise TypeError(
- "cannot serialize %r (type %s)" % (text, type(text).__name__)
- )
-
-def _encode(text, encoding):
- try:
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_cdata(text, encoding):
- # escape character data
- try:
- # it's worth avoiding do-nothing calls for strings that are
- # shorter than 500 character, or so. assume that's, by far,
- # the most common case in most applications.
- if "&" in text:
- text = text.replace("&", "&")
- if "<" in text:
- text = text.replace("<", "<")
- if ">" in text:
- text = text.replace(">", ">")
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_attrib(text, encoding):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&")
- if "<" in text:
- text = text.replace("<", "<")
- if ">" in text:
- text = text.replace(">", ">")
- if "\"" in text:
- text = text.replace("\"", """)
- if "\n" in text:
- text = text.replace("\n", " ")
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_attrib_html(text, encoding):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&")
- if ">" in text:
- text = text.replace(">", ">")
- if "\"" in text:
- text = text.replace("\"", """)
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-# --------------------------------------------------------------------
-
-##
-# Generates a string representation of an XML element, including all
-# subelements.
-#
-# @param element An Element instance.
-# @keyparam encoding Optional output encoding (default is US-ASCII).
-# @keyparam method Optional output method ("xml", "html", "text" or
-# "c14n"; default is "xml").
-# @return An encoded string containing the XML data.
-# @defreturn string
-
-def tostring(element, encoding=None, method=None):
- class dummy:
- pass
- data = []
- file = dummy()
- file.write = data.append
- ElementTree(element).write(file, encoding, method=method)
- return "".join(data)
-
-##
-# Generates a string representation of an XML element, including all
-# subelements. The string is returned as a sequence of string fragments.
-#
-# @param element An Element instance.
-# @keyparam encoding Optional output encoding (default is US-ASCII).
-# @keyparam method Optional output method ("xml", "html", "text" or
-# "c14n"; default is "xml").
-# @return A sequence object containing the XML data.
-# @defreturn sequence
-# @since 1.3
-
-def tostringlist(element, encoding=None, method=None):
- class dummy:
- pass
- data = []
- file = dummy()
- file.write = data.append
- ElementTree(element).write(file, encoding, method=method)
- # FIXME: merge small fragments into larger parts
- return data
-
-##
-# Writes an element tree or element structure to sys.stdout. This
-# function should be used for debugging only.
-# <p>
-# The exact output format is implementation dependent. In this
-# version, it's written as an ordinary XML file.
-#
-# @param elem An element tree or an individual element.
-
-def dump(elem):
- # debugging
- if not isinstance(elem, ElementTree):
- elem = ElementTree(elem)
- elem.write(sys.stdout)
- tail = elem.getroot().tail
- if not tail or tail[-1] != "\n":
- sys.stdout.write("\n")
-
-# --------------------------------------------------------------------
-# parsing
-
-##
-# Parses an XML document into an element tree.
-#
-# @param source A filename or file object containing XML data.
-# @param parser An optional parser instance. If not given, the
-# standard {@link XMLParser} parser is used.
-# @return An ElementTree instance
-
-def parse(source, parser=None):
- tree = ElementTree()
- tree.parse(source, parser)
- return tree
-
-##
-# Parses an XML document into an element tree incrementally, and reports
-# what's going on to the user.
-#
-# @param source A filename or file object containing XML data.
-# @param events A list of events to report back. If omitted, only "end"
-# events are reported.
-# @param parser An optional parser instance. If not given, the
-# standard {@link XMLParser} parser is used.
-# @return A (event, elem) iterator.
-
-def iterparse(source, events=None, parser=None):
- close_source = False
- if not hasattr(source, "read"):
- source = open(source, "rb")
- close_source = True
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- return _IterParseIterator(source, events, parser, close_source)
-
-class _IterParseIterator(object):
-
- def __init__(self, source, events, parser, close_source=False):
- self._file = source
- self._close_file = close_source
- self._events = []
- self._index = 0
- self._error = None
- self.root = self._root = None
- self._parser = parser
- # wire up the parser for event reporting
- parser = self._parser._parser
- append = self._events.append
- if events is None:
- events = ["end"]
- for event in events:
- if event == "start":
- try:
- parser.ordered_attributes = 1
- parser.specified_attributes = 1
- def handler(tag, attrib_in, event=event, append=append,
- start=self._parser._start_list):
- append((event, start(tag, attrib_in)))
- parser.StartElementHandler = handler
- except AttributeError:
- def handler(tag, attrib_in, event=event, append=append,
- start=self._parser._start):
- append((event, start(tag, attrib_in)))
- parser.StartElementHandler = handler
- elif event == "end":
- def handler(tag, event=event, append=append,
- end=self._parser._end):
- append((event, end(tag)))
- parser.EndElementHandler = handler
- elif event == "start-ns":
- def handler(prefix, uri, event=event, append=append):
- try:
- uri = (uri or "").encode("ascii")
- except UnicodeError:
- pass
- append((event, (prefix or "", uri or "")))
- parser.StartNamespaceDeclHandler = handler
- elif event == "end-ns":
- def handler(prefix, event=event, append=append):
- append((event, None))
- parser.EndNamespaceDeclHandler = handler
- else:
- raise ValueError("unknown event %r" % event)
-
- def next(self):
- while 1:
- try:
- item = self._events[self._index]
- self._index += 1
- return item
- except IndexError:
- pass
- if self._error:
- e = self._error
- self._error = None
- raise e
- if self._parser is None:
- self.root = self._root
- if self._close_file:
- self._file.close()
- raise StopIteration
- # load event buffer
- del self._events[:]
- self._index = 0
- data = self._file.read(16384)
- if data:
- try:
- self._parser.feed(data)
- except SyntaxError as exc:
- self._error = exc
- else:
- self._root = self._parser.close()
- self._parser = None
-
- def __iter__(self):
- return self
-
-##
-# Parses an XML document from a string constant. This function can
-# be used to embed "XML literals" in Python code.
-#
-# @param source A string containing XML data.
-# @param parser An optional parser instance. If not given, the
-# standard {@link XMLParser} parser is used.
-# @return An Element instance.
-# @defreturn Element
-
-def XML(text, parser=None):
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- parser.feed(text)
- return parser.close()
-
-##
-# Parses an XML document from a string constant, and also returns
-# a dictionary which maps from element id:s to elements.
-#
-# @param source A string containing XML data.
-# @param parser An optional parser instance. If not given, the
-# standard {@link XMLParser} parser is used.
-# @return A tuple containing an Element instance and a dictionary.
-# @defreturn (Element, dictionary)
-
-def XMLID(text, parser=None):
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- parser.feed(text)
- tree = parser.close()
- ids = {}
- for elem in tree.iter():
- id = elem.get("id")
- if id:
- ids[id] = elem
- return tree, ids
-
-##
-# Parses an XML document from a string constant. Same as {@link #XML}.
-#
-# @def fromstring(text)
-# @param source A string containing XML data.
-# @return An Element instance.
-# @defreturn Element
-
-fromstring = XML
-
-##
-# Parses an XML document from a sequence of string fragments.
-#
-# @param sequence A list or other sequence containing XML data fragments.
-# @param parser An optional parser instance. If not given, the
-# standard {@link XMLParser} parser is used.
-# @return An Element instance.
-# @defreturn Element
-# @since 1.3
-
-def fromstringlist(sequence, parser=None):
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- for text in sequence:
- parser.feed(text)
- return parser.close()
-
-# --------------------------------------------------------------------
-
-##
-# Generic element structure builder. This builder converts a sequence
-# of {@link #TreeBuilder.start}, {@link #TreeBuilder.data}, and {@link
-# #TreeBuilder.end} method calls to a well-formed element structure.
-# <p>
-# You can use this class to build an element structure using a custom XML
-# parser, or a parser for some other XML-like format.
-#
-# @param element_factory Optional element factory. This factory
-# is called to create new Element instances, as necessary.
-
-class TreeBuilder(object):
-
- def __init__(self, element_factory=None):
- self._data = [] # data collector
- self._elem = [] # element stack
- self._last = None # last element
- self._tail = None # true if we're after an end tag
- if element_factory is None:
- element_factory = Element
- self._factory = element_factory
-
- ##
- # Flushes the builder buffers, and returns the toplevel document
- # element.
- #
- # @return An Element instance.
- # @defreturn Element
-
- def close(self):
- assert len(self._elem) == 0, "missing end tags"
- assert self._last is not None, "missing toplevel element"
- return self._last
-
- def _flush(self):
- if self._data:
- if self._last is not None:
- text = "".join(self._data)
- if self._tail:
- assert self._last.tail is None, "internal error (tail)"
- self._last.tail = text
- else:
- assert self._last.text is None, "internal error (text)"
- self._last.text = text
- self._data = []
-
- ##
- # Adds text to the current element.
- #
- # @param data A string. This should be either an 8-bit string
- # containing ASCII text, or a Unicode string.
-
- def data(self, data):
- self._data.append(data)
-
- ##
- # Opens a new element.
- #
- # @param tag The element name.
- # @param attrib A dictionary containing element attributes.
- # @return The opened element.
- # @defreturn Element
-
- def start(self, tag, attrs):
- self._flush()
- self._last = elem = self._factory(tag, attrs)
- if self._elem:
- self._elem[-1].append(elem)
- self._elem.append(elem)
- self._tail = 0
- return elem
-
- ##
- # Closes the current element.
- #
- # @param tag The element name.
- # @return The closed element.
- # @defreturn Element
-
- def end(self, tag):
- self._flush()
- self._last = self._elem.pop()
- assert self._last.tag == tag,\
- "end tag mismatch (expected %s, got %s)" % (
- self._last.tag, tag)
- self._tail = 1
- return self._last
-
-##
-# Element structure builder for XML source data, based on the
-# <b>expat</b> parser.
-#
-# @keyparam target Target object. If omitted, the builder uses an
-# instance of the standard {@link #TreeBuilder} class.
-# @keyparam html Predefine HTML entities. This flag is not supported
-# by the current implementation.
-# @keyparam encoding Optional encoding. If given, the value overrides
-# the encoding specified in the XML file.
-# @see #ElementTree
-# @see #TreeBuilder
-
-class XMLParser(object):
-
- def __init__(self, html=0, target=None, encoding=None):
- try:
- from xml.parsers import expat
- except ImportError:
- try:
- import pyexpat as expat
- except ImportError:
- raise ImportError(
- "No module named expat; use SimpleXMLTreeBuilder instead"
- )
- parser = expat.ParserCreate(encoding, "}")
- if target is None:
- target = TreeBuilder()
- # underscored names are provided for compatibility only
- self.parser = self._parser = parser
- self.target = self._target = target
- self._error = expat.error
- self._names = {} # name memo cache
- # callbacks
- parser.DefaultHandlerExpand = self._default
- parser.StartElementHandler = self._start
- parser.EndElementHandler = self._end
- parser.CharacterDataHandler = self._data
- # optional callbacks
- parser.CommentHandler = self._comment
- parser.ProcessingInstructionHandler = self._pi
- # let expat do the buffering, if supported
- try:
- self._parser.buffer_text = 1
- except AttributeError:
- pass
- # use new-style attribute handling, if supported
- try:
- self._parser.ordered_attributes = 1
- self._parser.specified_attributes = 1
- parser.StartElementHandler = self._start_list
- except AttributeError:
- pass
- self._doctype = None
- self.entity = {}
- try:
- self.version = "Expat %d.%d.%d" % expat.version_info
- except AttributeError:
- pass # unknown
-
- def _raiseerror(self, value):
- err = ParseError(value)
- err.code = value.code
- err.position = value.lineno, value.offset
- raise err
-
- def _fixtext(self, text):
- # convert text string to ascii, if possible
- try:
- return text.encode("ascii")
- except UnicodeError:
- return text
-
- def _fixname(self, key):
- # expand qname, and convert name string to ascii, if possible
- try:
- name = self._names[key]
- except KeyError:
- name = key
- if "}" in name:
- name = "{" + name
- self._names[key] = name = self._fixtext(name)
- return name
-
- def _start(self, tag, attrib_in):
- fixname = self._fixname
- fixtext = self._fixtext
- tag = fixname(tag)
- attrib = {}
- for key, value in attrib_in.items():
- attrib[fixname(key)] = fixtext(value)
- return self.target.start(tag, attrib)
-
- def _start_list(self, tag, attrib_in):
- fixname = self._fixname
- fixtext = self._fixtext
- tag = fixname(tag)
- attrib = {}
- if attrib_in:
- for i in range(0, len(attrib_in), 2):
- attrib[fixname(attrib_in[i])] = fixtext(attrib_in[i+1])
- return self.target.start(tag, attrib)
-
- def _data(self, text):
- return self.target.data(self._fixtext(text))
-
- def _end(self, tag):
- return self.target.end(self._fixname(tag))
-
- def _comment(self, data):
- try:
- comment = self.target.comment
- except AttributeError:
- pass
- else:
- return comment(self._fixtext(data))
-
- def _pi(self, target, data):
- try:
- pi = self.target.pi
- except AttributeError:
- pass
- else:
- return pi(self._fixtext(target), self._fixtext(data))
-
- def _default(self, text):
- prefix = text[:1]
- if prefix == "&":
- # deal with undefined entities
- try:
- self.target.data(self.entity[text[1:-1]])
- except KeyError:
- from xml.parsers import expat
- err = expat.error(
- "undefined entity %s: line %d, column %d" %
- (text, self._parser.ErrorLineNumber,
- self._parser.ErrorColumnNumber)
- )
- err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
- err.lineno = self._parser.ErrorLineNumber
- err.offset = self._parser.ErrorColumnNumber
- raise err
- elif prefix == "<" and text[:9] == "<!DOCTYPE":
- self._doctype = [] # inside a doctype declaration
- elif self._doctype is not None:
- # parse doctype contents
- if prefix == ">":
- self._doctype = None
- return
- text = text.strip()
- if not text:
- return
- self._doctype.append(text)
- n = len(self._doctype)
- if n > 2:
- type = self._doctype[1]
- if type == "PUBLIC" and n == 4:
- name, type, pubid, system = self._doctype
- elif type == "SYSTEM" and n == 3:
- name, type, system = self._doctype
- pubid = None
- else:
- return
- if pubid:
- pubid = pubid[1:-1]
- if hasattr(self.target, "doctype"):
- self.target.doctype(name, pubid, system[1:-1])
- elif self.doctype is not self._XMLParser__doctype:
- # warn about deprecated call
- self._XMLParser__doctype(name, pubid, system[1:-1])
- self.doctype(name, pubid, system[1:-1])
- self._doctype = None
-
- ##
- # (Deprecated) Handles a doctype declaration.
- #
- # @param name Doctype name.
- # @param pubid Public identifier.
- # @param system System identifier.
-
- def doctype(self, name, pubid, system):
- """This method of XMLParser is deprecated."""
- warnings.warn(
- "This method of XMLParser is deprecated. Define doctype() "
- "method on the TreeBuilder target.",
- DeprecationWarning,
- )
-
- # sentinel, if doctype is redefined in a subclass
- __doctype = doctype
-
- ##
- # Feeds data to the parser.
- #
- # @param data Encoded data.
-
- def feed(self, data):
- try:
- self._parser.Parse(data, 0)
- except self._error, v:
- self._raiseerror(v)
-
- ##
- # Finishes feeding data to the parser.
- #
- # @return An element structure.
- # @defreturn Element
-
- def close(self):
- try:
- self._parser.Parse("", 1) # end of data
- except self._error, v:
- self._raiseerror(v)
- tree = self.target.close()
- del self.target, self._parser # get rid of circular references
- return tree
-
-# compatibility
-XMLTreeBuilder = XMLParser
-
-# workaround circular import.
-try:
- from ElementC14N import _serialize_c14n
- _serialize["c14n"] = _serialize_c14n
-except ImportError:
- pass
+#
+# ElementTree
+# $Id: ElementTree.py 3440 2008-07-18 14:45:01Z fredrik $
+#
+# light-weight XML support for Python 2.3 and later.
+#
+# history (since 1.2.6):
+# 2005-11-12 fl added tostringlist/fromstringlist helpers
+# 2006-07-05 fl merged in selected changes from the 1.3 sandbox
+# 2006-07-05 fl removed support for 2.1 and earlier
+# 2007-06-21 fl added deprecation/future warnings
+# 2007-08-25 fl added doctype hook, added parser version attribute etc
+# 2007-08-26 fl added new serializer code (better namespace handling, etc)
+# 2007-08-27 fl warn for broken /tag searches on tree level
+# 2007-09-02 fl added html/text methods to serializer (experimental)
+# 2007-09-05 fl added method argument to tostring/tostringlist
+# 2007-09-06 fl improved error handling
+# 2007-09-13 fl added itertext, iterfind; assorted cleanups
+# 2007-12-15 fl added C14N hooks, copy method (experimental)
+#
+# Copyright (c) 1999-2008 by Fredrik Lundh. All rights reserved.
+#
+# fredrik@pythonware.com
+# http://www.pythonware.com
+#
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2008 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/psf/license for licensing details.
+
+__all__ = [
+ # public symbols
+ "Comment",
+ "dump",
+ "Element", "ElementTree",
+ "fromstring", "fromstringlist",
+ "iselement", "iterparse",
+ "parse", "ParseError",
+ "PI", "ProcessingInstruction",
+ "QName",
+ "SubElement",
+ "tostring", "tostringlist",
+ "TreeBuilder",
+ "VERSION",
+ "XML",
+ "XMLParser", "XMLTreeBuilder",
+ ]
+
+VERSION = "1.3.0"
+
+##
+# The <b>Element</b> type is a flexible container object, designed to
+# store hierarchical data structures in memory. The type can be
+# described as a cross between a list and a dictionary.
+# <p>
+# Each element has a number of properties associated with it:
+# <ul>
+# <li>a <i>tag</i>. This is a string identifying what kind of data
+# this element represents (the element type, in other words).</li>
+# <li>a number of <i>attributes</i>, stored in a Python dictionary.</li>
+# <li>a <i>text</i> string.</li>
+# <li>an optional <i>tail</i> string.</li>
+# <li>a number of <i>child elements</i>, stored in a Python sequence</li>
+# </ul>
+#
+# To create an element instance, use the {@link #Element} constructor
+# or the {@link #SubElement} factory function.
+# <p>
+# The {@link #ElementTree} class can be used to wrap an element
+# structure, and convert it from and to XML.
+##
+
+import sys
+import re
+import warnings
+
+
+class _SimpleElementPath(object):
+ # emulate pre-1.2 find/findtext/findall behaviour
+ def find(self, element, tag, namespaces=None):
+ for elem in element:
+ if elem.tag == tag:
+ return elem
+ return None
+ def findtext(self, element, tag, default=None, namespaces=None):
+ elem = self.find(element, tag)
+ if elem is None:
+ return default
+ return elem.text or ""
+ def iterfind(self, element, tag, namespaces=None):
+ if tag[:3] == ".//":
+ for elem in element.iter(tag[3:]):
+ yield elem
+ for elem in element:
+ if elem.tag == tag:
+ yield elem
+ def findall(self, element, tag, namespaces=None):
+ return list(self.iterfind(element, tag, namespaces))
+
+try:
+ from . import ElementPath
+except ImportError:
+ ElementPath = _SimpleElementPath()
+
+##
+# Parser error. This is a subclass of <b>SyntaxError</b>.
+# <p>
+# In addition to the exception value, an exception instance contains a
+# specific exception code in the <b>code</b> attribute, and the line and
+# column of the error in the <b>position</b> attribute.
+
+class ParseError(SyntaxError):
+ pass
+
+# --------------------------------------------------------------------
+
+##
+# Checks if an object appears to be a valid element object.
+#
+# @param An element instance.
+# @return A true value if this is an element object.
+# @defreturn flag
+
+def iselement(element):
+ # FIXME: not sure about this; might be a better idea to look
+ # for tag/attrib/text attributes
+ return isinstance(element, Element) or hasattr(element, "tag")
+
+##
+# Element class. This class defines the Element interface, and
+# provides a reference implementation of this interface.
+# <p>
+# The element name, attribute names, and attribute values can be
+# either ASCII strings (ordinary Python strings containing only 7-bit
+# ASCII characters) or Unicode strings.
+#
+# @param tag The element name.
+# @param attrib An optional dictionary, containing element attributes.
+# @param **extra Additional attributes, given as keyword arguments.
+# @see Element
+# @see SubElement
+# @see Comment
+# @see ProcessingInstruction
+
+class Element(object):
+ # <tag attrib>text<child/>...</tag>tail
+
+ ##
+ # (Attribute) Element tag.
+
+ tag = None
+
+ ##
+ # (Attribute) Element attribute dictionary. Where possible, use
+ # {@link #Element.get},
+ # {@link #Element.set},
+ # {@link #Element.keys}, and
+ # {@link #Element.items} to access
+ # element attributes.
+
+ attrib = None
+
+ ##
+ # (Attribute) Text before first subelement. This is either a
+ # string or the value None. Note that if there was no text, this
+ # attribute may be either None or an empty string, depending on
+ # the parser.
+
+ text = None
+
+ ##
+ # (Attribute) Text after this element's end tag, but before the
+ # next sibling element's start tag. This is either a string or
+ # the value None. Note that if there was no text, this attribute
+ # may be either None or an empty string, depending on the parser.
+
+ tail = None # text after end tag, if any
+
+ # constructor
+
+ def __init__(self, tag, attrib={}, **extra):
+ attrib = attrib.copy()
+ attrib.update(extra)
+ self.tag = tag
+ self.attrib = attrib
+ self._children = []
+
+ def __repr__(self):
+ return "<Element %s at 0x%x>" % (repr(self.tag), id(self))
+
+ ##
+ # Creates a new element object of the same type as this element.
+ #
+ # @param tag Element tag.
+ # @param attrib Element attributes, given as a dictionary.
+ # @return A new element instance.
+
+ def makeelement(self, tag, attrib):
+ return self.__class__(tag, attrib)
+
+ ##
+ # (Experimental) Copies the current element. This creates a
+ # shallow copy; subelements will be shared with the original tree.
+ #
+ # @return A new element instance.
+
+ def copy(self):
+ elem = self.makeelement(self.tag, self.attrib)
+ elem.text = self.text
+ elem.tail = self.tail
+ elem[:] = self
+ return elem
+
+ ##
+ # Returns the number of subelements. Note that this only counts
+ # full elements; to check if there's any content in an element, you
+ # have to check both the length and the <b>text</b> attribute.
+ #
+ # @return The number of subelements.
+
+ def __len__(self):
+ return len(self._children)
+
+ def __nonzero__(self):
+ warnings.warn(
+ "The behavior of this method will change in future versions. "
+ "Use specific 'len(elem)' or 'elem is not None' test instead.",
+ FutureWarning, stacklevel=2
+ )
+ return len(self._children) != 0 # emulate old behaviour, for now
+
+ ##
+ # Returns the given subelement, by index.
+ #
+ # @param index What subelement to return.
+ # @return The given subelement.
+ # @exception IndexError If the given element does not exist.
+
+ def __getitem__(self, index):
+ return self._children[index]
+
+ ##
+ # Replaces the given subelement, by index.
+ #
+ # @param index What subelement to replace.
+ # @param element The new element value.
+ # @exception IndexError If the given element does not exist.
+
+ def __setitem__(self, index, element):
+ # if isinstance(index, slice):
+ # for elt in element:
+ # assert iselement(elt)
+ # else:
+ # assert iselement(element)
+ self._children[index] = element
+
+ ##
+ # Deletes the given subelement, by index.
+ #
+ # @param index What subelement to delete.
+ # @exception IndexError If the given element does not exist.
+
+ def __delitem__(self, index):
+ del self._children[index]
+
+ ##
+ # Adds a subelement to the end of this element. In document order,
+ # the new element will appear after the last existing subelement (or
+ # directly after the text, if it's the first subelement), but before
+ # the end tag for this element.
+ #
+ # @param element The element to add.
+
+ def append(self, element):
+ # assert iselement(element)
+ self._children.append(element)
+
+ ##
+ # Appends subelements from a sequence.
+ #
+ # @param elements A sequence object with zero or more elements.
+ # @since 1.3
+
+ def extend(self, elements):
+ # for element in elements:
+ # assert iselement(element)
+ self._children.extend(elements)
+
+ ##
+ # Inserts a subelement at the given position in this element.
+ #
+ # @param index Where to insert the new subelement.
+
+ def insert(self, index, element):
+ # assert iselement(element)
+ self._children.insert(index, element)
+
+ ##
+ # Removes a matching subelement. Unlike the <b>find</b> methods,
+ # this method compares elements based on identity, not on tag
+ # value or contents. To remove subelements by other means, the
+ # easiest way is often to use a list comprehension to select what
+ # elements to keep, and use slice assignment to update the parent
+ # element.
+ #
+ # @param element What element to remove.
+ # @exception ValueError If a matching element could not be found.
+
+ def remove(self, element):
+ # assert iselement(element)
+ self._children.remove(element)
+
+ ##
+ # (Deprecated) Returns all subelements. The elements are returned
+ # in document order.
+ #
+ # @return A list of subelements.
+ # @defreturn list of Element instances
+
+ def getchildren(self):
+ warnings.warn(
+ "This method will be removed in future versions. "
+ "Use 'list(elem)' or iteration over elem instead.",
+ DeprecationWarning, stacklevel=2
+ )
+ return self._children
+
+ ##
+ # Finds the first matching subelement, by tag name or path.
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return The first matching element, or None if no element was found.
+ # @defreturn Element or None
+
+ def find(self, path, namespaces=None):
+ return ElementPath.find(self, path, namespaces)
+
+ ##
+ # Finds text for the first matching subelement, by tag name or path.
+ #
+ # @param path What element to look for.
+ # @param default What to return if the element was not found.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return The text content of the first matching element, or the
+ # default value no element was found. Note that if the element
+ # is found, but has no text content, this method returns an
+ # empty string.
+ # @defreturn string
+
+ def findtext(self, path, default=None, namespaces=None):
+ return ElementPath.findtext(self, path, default, namespaces)
+
+ ##
+ # Finds all matching subelements, by tag name or path.
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return A list or other sequence containing all matching elements,
+ # in document order.
+ # @defreturn list of Element instances
+
+ def findall(self, path, namespaces=None):
+ return ElementPath.findall(self, path, namespaces)
+
+ ##
+ # Finds all matching subelements, by tag name or path.
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return An iterator or sequence containing all matching elements,
+ # in document order.
+ # @defreturn a generated sequence of Element instances
+
+ def iterfind(self, path, namespaces=None):
+ return ElementPath.iterfind(self, path, namespaces)
+
+ ##
+ # Resets an element. This function removes all subelements, clears
+ # all attributes, and sets the <b>text</b> and <b>tail</b> attributes
+ # to None.
+
+ def clear(self):
+ self.attrib.clear()
+ self._children = []
+ self.text = self.tail = None
+
+ ##
+ # Gets an element attribute. Equivalent to <b>attrib.get</b>, but
+ # some implementations may handle this a bit more efficiently.
+ #
+ # @param key What attribute to look for.
+ # @param default What to return if the attribute was not found.
+ # @return The attribute value, or the default value, if the
+ # attribute was not found.
+ # @defreturn string or None
+
+ def get(self, key, default=None):
+ return self.attrib.get(key, default)
+
+ ##
+ # Sets an element attribute. Equivalent to <b>attrib[key] = value</b>,
+ # but some implementations may handle this a bit more efficiently.
+ #
+ # @param key What attribute to set.
+ # @param value The attribute value.
+
+ def set(self, key, value):
+ self.attrib[key] = value
+
+ ##
+ # Gets a list of attribute names. The names are returned in an
+ # arbitrary order (just like for an ordinary Python dictionary).
+ # Equivalent to <b>attrib.keys()</b>.
+ #
+ # @return A list of element attribute names.
+ # @defreturn list of strings
+
+ def keys(self):
+ return self.attrib.keys()
+
+ ##
+ # Gets element attributes, as a sequence. The attributes are
+ # returned in an arbitrary order. Equivalent to <b>attrib.items()</b>.
+ #
+ # @return A list of (name, value) tuples for all attributes.
+ # @defreturn list of (string, string) tuples
+
+ def items(self):
+ return self.attrib.items()
+
+ ##
+ # Creates a tree iterator. The iterator loops over this element
+ # and all subelements, in document order, and returns all elements
+ # with a matching tag.
+ # <p>
+ # If the tree structure is modified during iteration, new or removed
+ # elements may or may not be included. To get a stable set, use the
+ # list() function on the iterator, and loop over the resulting list.
+ #
+ # @param tag What tags to look for (default is to return all elements).
+ # @return An iterator containing all the matching elements.
+ # @defreturn iterator
+
+ def iter(self, tag=None):
+ if tag == "*":
+ tag = None
+ if tag is None or self.tag == tag:
+ yield self
+ for e in self._children:
+ for e in e.iter(tag):
+ yield e
+
+ # compatibility
+ def getiterator(self, tag=None):
+ # Change for a DeprecationWarning in 1.4
+ warnings.warn(
+ "This method will be removed in future versions. "
+ "Use 'elem.iter()' or 'list(elem.iter())' instead.",
+ PendingDeprecationWarning, stacklevel=2
+ )
+ return list(self.iter(tag))
+
+ ##
+ # Creates a text iterator. The iterator loops over this element
+ # and all subelements, in document order, and returns all inner
+ # text.
+ #
+ # @return An iterator containing all inner text.
+ # @defreturn iterator
+
+ def itertext(self):
+ tag = self.tag
+ if not isinstance(tag, basestring) and tag is not None:
+ return
+ if self.text:
+ yield self.text
+ for e in self:
+ for s in e.itertext():
+ yield s
+ if e.tail:
+ yield e.tail
+
+# compatibility
+_Element = _ElementInterface = Element
+
+##
+# Subelement factory. This function creates an element instance, and
+# appends it to an existing element.
+# <p>
+# The element name, attribute names, and attribute values can be
+# either 8-bit ASCII strings or Unicode strings.
+#
+# @param parent The parent element.
+# @param tag The subelement name.
+# @param attrib An optional dictionary, containing element attributes.
+# @param **extra Additional attributes, given as keyword arguments.
+# @return An element instance.
+# @defreturn Element
+
+def SubElement(parent, tag, attrib={}, **extra):
+ attrib = attrib.copy()
+ attrib.update(extra)
+ element = parent.makeelement(tag, attrib)
+ parent.append(element)
+ return element
+
+##
+# Comment element factory. This factory function creates a special
+# element that will be serialized as an XML comment by the standard
+# serializer.
+# <p>
+# The comment string can be either an 8-bit ASCII string or a Unicode
+# string.
+#
+# @param text A string containing the comment string.
+# @return An element instance, representing a comment.
+# @defreturn Element
+
+def Comment(text=None):
+ element = Element(Comment)
+ element.text = text
+ return element
+
+##
+# PI element factory. This factory function creates a special element
+# that will be serialized as an XML processing instruction by the standard
+# serializer.
+#
+# @param target A string containing the PI target.
+# @param text A string containing the PI contents, if any.
+# @return An element instance, representing a PI.
+# @defreturn Element
+
+def ProcessingInstruction(target, text=None):
+ element = Element(ProcessingInstruction)
+ element.text = target
+ if text:
+ element.text = element.text + " " + text
+ return element
+
+PI = ProcessingInstruction
+
+##
+# QName wrapper. This can be used to wrap a QName attribute value, in
+# order to get proper namespace handling on output.
+#
+# @param text A string containing the QName value, in the form {uri}local,
+# or, if the tag argument is given, the URI part of a QName.
+# @param tag Optional tag. If given, the first argument is interpreted as
+# an URI, and this argument is interpreted as a local name.
+# @return An opaque object, representing the QName.
+
+class QName(object):
+ def __init__(self, text_or_uri, tag=None):
+ if tag:
+ text_or_uri = "{%s}%s" % (text_or_uri, tag)
+ self.text = text_or_uri
+ def __str__(self):
+ return self.text
+ def __hash__(self):
+ return hash(self.text)
+ def __cmp__(self, other):
+ if isinstance(other, QName):
+ return cmp(self.text, other.text)
+ return cmp(self.text, other)
+
+# --------------------------------------------------------------------
+
+##
+# ElementTree wrapper class. This class represents an entire element
+# hierarchy, and adds some extra support for serialization to and from
+# standard XML.
+#
+# @param element Optional root element.
+# @keyparam file Optional file handle or file name. If given, the
+# tree is initialized with the contents of this XML file.
+
+class ElementTree(object):
+
+ def __init__(self, element=None, file=None):
+ # assert element is None or iselement(element)
+ self._root = element # first node
+ if file:
+ self.parse(file)
+
+ ##
+ # Gets the root element for this tree.
+ #
+ # @return An element instance.
+ # @defreturn Element
+
+ def getroot(self):
+ return self._root
+
+ ##
+ # Replaces the root element for this tree. This discards the
+ # current contents of the tree, and replaces it with the given
+ # element. Use with care.
+ #
+ # @param element An element instance.
+
+ def _setroot(self, element):
+ # assert iselement(element)
+ self._root = element
+
+ ##
+ # Loads an external XML document into this element tree.
+ #
+ # @param source A file name or file object. If a file object is
+ # given, it only has to implement a <b>read(n)</b> method.
+ # @keyparam parser An optional parser instance. If not given, the
+ # standard {@link XMLParser} parser is used.
+ # @return The document root element.
+ # @defreturn Element
+ # @exception ParseError If the parser fails to parse the document.
+
+ def parse(self, source, parser=None):
+ close_source = False
+ if not hasattr(source, "read"):
+ source = open(source, "rb")
+ close_source = True
+ try:
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ while 1:
+ data = source.read(65536)
+ if not data:
+ break
+ parser.feed(data)
+ self._root = parser.close()
+ return self._root
+ finally:
+ if close_source:
+ source.close()
+
+ ##
+ # Creates a tree iterator for the root element. The iterator loops
+ # over all elements in this tree, in document order.
+ #
+ # @param tag What tags to look for (default is to return all elements)
+ # @return An iterator.
+ # @defreturn iterator
+
+ def iter(self, tag=None):
+ # assert self._root is not None
+ return self._root.iter(tag)
+
+ # compatibility
+ def getiterator(self, tag=None):
+ # Change for a DeprecationWarning in 1.4
+ warnings.warn(
+ "This method will be removed in future versions. "
+ "Use 'tree.iter()' or 'list(tree.iter())' instead.",
+ PendingDeprecationWarning, stacklevel=2
+ )
+ return list(self.iter(tag))
+
+ ##
+ # Finds the first toplevel element with given tag.
+ # Same as getroot().find(path).
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return The first matching element, or None if no element was found.
+ # @defreturn Element or None
+
+ def find(self, path, namespaces=None):
+ # assert self._root is not None
+ if path[:1] == "/":
+ path = "." + path
+ warnings.warn(
+ "This search is broken in 1.3 and earlier, and will be "
+ "fixed in a future version. If you rely on the current "
+ "behaviour, change it to %r" % path,
+ FutureWarning, stacklevel=2
+ )
+ return self._root.find(path, namespaces)
+
+ ##
+ # Finds the element text for the first toplevel element with given
+ # tag. Same as getroot().findtext(path).
+ #
+ # @param path What toplevel element to look for.
+ # @param default What to return if the element was not found.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return The text content of the first matching element, or the
+ # default value no element was found. Note that if the element
+ # is found, but has no text content, this method returns an
+ # empty string.
+ # @defreturn string
+
+ def findtext(self, path, default=None, namespaces=None):
+ # assert self._root is not None
+ if path[:1] == "/":
+ path = "." + path
+ warnings.warn(
+ "This search is broken in 1.3 and earlier, and will be "
+ "fixed in a future version. If you rely on the current "
+ "behaviour, change it to %r" % path,
+ FutureWarning, stacklevel=2
+ )
+ return self._root.findtext(path, default, namespaces)
+
+ ##
+ # Finds all toplevel elements with the given tag.
+ # Same as getroot().findall(path).
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return A list or iterator containing all matching elements,
+ # in document order.
+ # @defreturn list of Element instances
+
+ def findall(self, path, namespaces=None):
+ # assert self._root is not None
+ if path[:1] == "/":
+ path = "." + path
+ warnings.warn(
+ "This search is broken in 1.3 and earlier, and will be "
+ "fixed in a future version. If you rely on the current "
+ "behaviour, change it to %r" % path,
+ FutureWarning, stacklevel=2
+ )
+ return self._root.findall(path, namespaces)
+
+ ##
+ # Finds all matching subelements, by tag name or path.
+ # Same as getroot().iterfind(path).
+ #
+ # @param path What element to look for.
+ # @keyparam namespaces Optional namespace prefix map.
+ # @return An iterator or sequence containing all matching elements,
+ # in document order.
+ # @defreturn a generated sequence of Element instances
+
+ def iterfind(self, path, namespaces=None):
+ # assert self._root is not None
+ if path[:1] == "/":
+ path = "." + path
+ warnings.warn(
+ "This search is broken in 1.3 and earlier, and will be "
+ "fixed in a future version. If you rely on the current "
+ "behaviour, change it to %r" % path,
+ FutureWarning, stacklevel=2
+ )
+ return self._root.iterfind(path, namespaces)
+
+ ##
+ # Writes the element tree to a file, as XML.
+ #
+ # @def write(file, **options)
+ # @param file A file name, or a file object opened for writing.
+ # @param **options Options, given as keyword arguments.
+ # @keyparam encoding Optional output encoding (default is US-ASCII).
+ # @keyparam method Optional output method ("xml", "html", "text" or
+ # "c14n"; default is "xml").
+ # @keyparam xml_declaration Controls if an XML declaration should
+ # be added to the file. Use False for never, True for always,
+ # None for only if not US-ASCII or UTF-8. None is default.
+
+ def write(self, file_or_filename,
+ # keyword arguments
+ encoding=None,
+ xml_declaration=None,
+ default_namespace=None,
+ method=None):
+ # assert self._root is not None
+ if not method:
+ method = "xml"
+ elif method not in _serialize:
+ # FIXME: raise an ImportError for c14n if ElementC14N is missing?
+ raise ValueError("unknown method %r" % method)
+ if hasattr(file_or_filename, "write"):
+ file = file_or_filename
+ else:
+ file = open(file_or_filename, "wb")
+ write = file.write
+ if not encoding:
+ if method == "c14n":
+ encoding = "utf-8"
+ else:
+ encoding = "us-ascii"
+ elif xml_declaration or (xml_declaration is None and
+ encoding not in ("utf-8", "us-ascii")):
+ if method == "xml":
+ write("<?xml version='1.0' encoding='%s'?>\n" % encoding)
+ if method == "text":
+ _serialize_text(write, self._root, encoding)
+ else:
+ qnames, namespaces = _namespaces(
+ self._root, encoding, default_namespace
+ )
+ serialize = _serialize[method]
+ serialize(write, self._root, encoding, qnames, namespaces)
+ if file_or_filename is not file:
+ file.close()
+
+ def write_c14n(self, file):
+ # lxml.etree compatibility. use output method instead
+ return self.write(file, method="c14n")
+
+# --------------------------------------------------------------------
+# serialization support
+
+def _namespaces(elem, encoding, default_namespace=None):
+ # identify namespaces used in this tree
+
+ # maps qnames to *encoded* prefix:local names
+ qnames = {None: None}
+
+ # maps uri:s to prefixes
+ namespaces = {}
+ if default_namespace:
+ namespaces[default_namespace] = ""
+
+ def encode(text):
+ return text.encode(encoding)
+
+ def add_qname(qname):
+ # calculate serialized qname representation
+ try:
+ if qname[:1] == "{":
+ uri, tag = qname[1:].rsplit("}", 1)
+ prefix = namespaces.get(uri)
+ if prefix is None:
+ prefix = _namespace_map.get(uri)
+ if prefix is None:
+ prefix = "ns%d" % len(namespaces)
+ if prefix != "xml":
+ namespaces[uri] = prefix
+ if prefix:
+ qnames[qname] = encode("%s:%s" % (prefix, tag))
+ else:
+ qnames[qname] = encode(tag) # default element
+ else:
+ if default_namespace:
+ # FIXME: can this be handled in XML 1.0?
+ raise ValueError(
+ "cannot use non-qualified names with "
+ "default_namespace option"
+ )
+ qnames[qname] = encode(qname)
+ except TypeError:
+ _raise_serialization_error(qname)
+
+ # populate qname and namespaces table
+ try:
+ iterate = elem.iter
+ except AttributeError:
+ iterate = elem.getiterator # cET compatibility
+ for elem in iterate():
+ tag = elem.tag
+ if isinstance(tag, QName):
+ if tag.text not in qnames:
+ add_qname(tag.text)
+ elif isinstance(tag, basestring):
+ if tag not in qnames:
+ add_qname(tag)
+ elif tag is not None and tag is not Comment and tag is not PI:
+ _raise_serialization_error(tag)
+ for key, value in elem.items():
+ if isinstance(key, QName):
+ key = key.text
+ if key not in qnames:
+ add_qname(key)
+ if isinstance(value, QName) and value.text not in qnames:
+ add_qname(value.text)
+ text = elem.text
+ if isinstance(text, QName) and text.text not in qnames:
+ add_qname(text.text)
+ return qnames, namespaces
+
+def _serialize_xml(write, elem, encoding, qnames, namespaces):
+ tag = elem.tag
+ text = elem.text
+ if tag is Comment:
+ write("<!--%s-->" % _encode(text, encoding))
+ elif tag is ProcessingInstruction:
+ write("<?%s?>" % _encode(text, encoding))
+ else:
+ tag = qnames[tag]
+ if tag is None:
+ if text:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_xml(write, e, encoding, qnames, None)
+ else:
+ write("<" + tag)
+ items = elem.items()
+ if items or namespaces:
+ if namespaces:
+ for v, k in sorted(namespaces.items(),
+ key=lambda x: x[1]): # sort on prefix
+ if k:
+ k = ":" + k
+ write(" xmlns%s=\"%s\"" % (
+ k.encode(encoding),
+ _escape_attrib(v, encoding)
+ ))
+ for k, v in sorted(items): # lexical order
+ if isinstance(k, QName):
+ k = k.text
+ if isinstance(v, QName):
+ v = qnames[v.text]
+ else:
+ v = _escape_attrib(v, encoding)
+ write(" %s=\"%s\"" % (qnames[k], v))
+ if text or len(elem):
+ write(">")
+ if text:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_xml(write, e, encoding, qnames, None)
+ write("</" + tag + ">")
+ else:
+ write(" />")
+ if elem.tail:
+ write(_escape_cdata(elem.tail, encoding))
+
+HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
+ "img", "input", "isindex", "link", "meta" "param")
+
+try:
+ HTML_EMPTY = set(HTML_EMPTY)
+except NameError:
+ pass
+
+def _serialize_html(write, elem, encoding, qnames, namespaces):
+ tag = elem.tag
+ text = elem.text
+ if tag is Comment:
+ write("<!--%s-->" % _escape_cdata(text, encoding))
+ elif tag is ProcessingInstruction:
+ write("<?%s?>" % _escape_cdata(text, encoding))
+ else:
+ tag = qnames[tag]
+ if tag is None:
+ if text:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_html(write, e, encoding, qnames, None)
+ else:
+ write("<" + tag)
+ items = elem.items()
+ if items or namespaces:
+ if namespaces:
+ for v, k in sorted(namespaces.items(),
+ key=lambda x: x[1]): # sort on prefix
+ if k:
+ k = ":" + k
+ write(" xmlns%s=\"%s\"" % (
+ k.encode(encoding),
+ _escape_attrib(v, encoding)
+ ))
+ for k, v in sorted(items): # lexical order
+ if isinstance(k, QName):
+ k = k.text
+ if isinstance(v, QName):
+ v = qnames[v.text]
+ else:
+ v = _escape_attrib_html(v, encoding)
+ # FIXME: handle boolean attributes
+ write(" %s=\"%s\"" % (qnames[k], v))
+ write(">")
+ tag = tag.lower()
+ if text:
+ if tag == "script" or tag == "style":
+ write(_encode(text, encoding))
+ else:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_html(write, e, encoding, qnames, None)
+ if tag not in HTML_EMPTY:
+ write("</" + tag + ">")
+ if elem.tail:
+ write(_escape_cdata(elem.tail, encoding))
+
+def _serialize_text(write, elem, encoding):
+ for part in elem.itertext():
+ write(part.encode(encoding))
+ if elem.tail:
+ write(elem.tail.encode(encoding))
+
+_serialize = {
+ "xml": _serialize_xml,
+ "html": _serialize_html,
+ "text": _serialize_text,
+# this optional method is imported at the end of the module
+# "c14n": _serialize_c14n,
+}
+
+##
+# Registers a namespace prefix. The registry is global, and any
+# existing mapping for either the given prefix or the namespace URI
+# will be removed.
+#
+# @param prefix Namespace prefix.
+# @param uri Namespace uri. Tags and attributes in this namespace
+# will be serialized with the given prefix, if at all possible.
+# @exception ValueError If the prefix is reserved, or is otherwise
+# invalid.
+
+def register_namespace(prefix, uri):
+ if re.match("ns\d+$", prefix):
+ raise ValueError("Prefix format reserved for internal use")
+ for k, v in _namespace_map.items():
+ if k == uri or v == prefix:
+ del _namespace_map[k]
+ _namespace_map[uri] = prefix
+
+_namespace_map = {
+ # "well-known" namespace prefixes
+ "http://www.w3.org/XML/1998/namespace": "xml",
+ "http://www.w3.org/1999/xhtml": "html",
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
+ "http://schemas.xmlsoap.org/wsdl/": "wsdl",
+ # xml schema
+ "http://www.w3.org/2001/XMLSchema": "xs",
+ "http://www.w3.org/2001/XMLSchema-instance": "xsi",
+ # dublin core
+ "http://purl.org/dc/elements/1.1/": "dc",
+}
+
+def _raise_serialization_error(text):
+ raise TypeError(
+ "cannot serialize %r (type %s)" % (text, type(text).__name__)
+ )
+
+def _encode(text, encoding):
+ try:
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+def _escape_cdata(text, encoding):
+ # escape character data
+ try:
+ # it's worth avoiding do-nothing calls for strings that are
+ # shorter than 500 character, or so. assume that's, by far,
+ # the most common case in most applications.
+ if "&" in text:
+ text = text.replace("&", "&")
+ if "<" in text:
+ text = text.replace("<", "<")
+ if ">" in text:
+ text = text.replace(">", ">")
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+def _escape_attrib(text, encoding):
+ # escape attribute value
+ try:
+ if "&" in text:
+ text = text.replace("&", "&")
+ if "<" in text:
+ text = text.replace("<", "<")
+ if ">" in text:
+ text = text.replace(">", ">")
+ if "\"" in text:
+ text = text.replace("\"", """)
+ if "\n" in text:
+ text = text.replace("\n", " ")
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+def _escape_attrib_html(text, encoding):
+ # escape attribute value
+ try:
+ if "&" in text:
+ text = text.replace("&", "&")
+ if ">" in text:
+ text = text.replace(">", ">")
+ if "\"" in text:
+ text = text.replace("\"", """)
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+# --------------------------------------------------------------------
+
+##
+# Generates a string representation of an XML element, including all
+# subelements.
+#
+# @param element An Element instance.
+# @keyparam encoding Optional output encoding (default is US-ASCII).
+# @keyparam method Optional output method ("xml", "html", "text" or
+# "c14n"; default is "xml").
+# @return An encoded string containing the XML data.
+# @defreturn string
+
+def tostring(element, encoding=None, method=None):
+ class dummy:
+ pass
+ data = []
+ file = dummy()
+ file.write = data.append
+ ElementTree(element).write(file, encoding, method=method)
+ return "".join(data)
+
+##
+# Generates a string representation of an XML element, including all
+# subelements. The string is returned as a sequence of string fragments.
+#
+# @param element An Element instance.
+# @keyparam encoding Optional output encoding (default is US-ASCII).
+# @keyparam method Optional output method ("xml", "html", "text" or
+# "c14n"; default is "xml").
+# @return A sequence object containing the XML data.
+# @defreturn sequence
+# @since 1.3
+
+def tostringlist(element, encoding=None, method=None):
+ class dummy:
+ pass
+ data = []
+ file = dummy()
+ file.write = data.append
+ ElementTree(element).write(file, encoding, method=method)
+ # FIXME: merge small fragments into larger parts
+ return data
+
+##
+# Writes an element tree or element structure to sys.stdout. This
+# function should be used for debugging only.
+# <p>
+# The exact output format is implementation dependent. In this
+# version, it's written as an ordinary XML file.
+#
+# @param elem An element tree or an individual element.
+
+def dump(elem):
+ # debugging
+ if not isinstance(elem, ElementTree):
+ elem = ElementTree(elem)
+ elem.write(sys.stdout)
+ tail = elem.getroot().tail
+ if not tail or tail[-1] != "\n":
+ sys.stdout.write("\n")
+
+# --------------------------------------------------------------------
+# parsing
+
+##
+# Parses an XML document into an element tree.
+#
+# @param source A filename or file object containing XML data.
+# @param parser An optional parser instance. If not given, the
+# standard {@link XMLParser} parser is used.
+# @return An ElementTree instance
+
+def parse(source, parser=None):
+ tree = ElementTree()
+ tree.parse(source, parser)
+ return tree
+
+##
+# Parses an XML document into an element tree incrementally, and reports
+# what's going on to the user.
+#
+# @param source A filename or file object containing XML data.
+# @param events A list of events to report back. If omitted, only "end"
+# events are reported.
+# @param parser An optional parser instance. If not given, the
+# standard {@link XMLParser} parser is used.
+# @return A (event, elem) iterator.
+
+def iterparse(source, events=None, parser=None):
+ close_source = False
+ if not hasattr(source, "read"):
+ source = open(source, "rb")
+ close_source = True
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ return _IterParseIterator(source, events, parser, close_source)
+
+class _IterParseIterator(object):
+
+ def __init__(self, source, events, parser, close_source=False):
+ self._file = source
+ self._close_file = close_source
+ self._events = []
+ self._index = 0
+ self._error = None
+ self.root = self._root = None
+ self._parser = parser
+ # wire up the parser for event reporting
+ parser = self._parser._parser
+ append = self._events.append
+ if events is None:
+ events = ["end"]
+ for event in events:
+ if event == "start":
+ try:
+ parser.ordered_attributes = 1
+ parser.specified_attributes = 1
+ def handler(tag, attrib_in, event=event, append=append,
+ start=self._parser._start_list):
+ append((event, start(tag, attrib_in)))
+ parser.StartElementHandler = handler
+ except AttributeError:
+ def handler(tag, attrib_in, event=event, append=append,
+ start=self._parser._start):
+ append((event, start(tag, attrib_in)))
+ parser.StartElementHandler = handler
+ elif event == "end":
+ def handler(tag, event=event, append=append,
+ end=self._parser._end):
+ append((event, end(tag)))
+ parser.EndElementHandler = handler
+ elif event == "start-ns":
+ def handler(prefix, uri, event=event, append=append):
+ try:
+ uri = (uri or "").encode("ascii")
+ except UnicodeError:
+ pass
+ append((event, (prefix or "", uri or "")))
+ parser.StartNamespaceDeclHandler = handler
+ elif event == "end-ns":
+ def handler(prefix, event=event, append=append):
+ append((event, None))
+ parser.EndNamespaceDeclHandler = handler
+ else:
+ raise ValueError("unknown event %r" % event)
+
+ def next(self):
+ while 1:
+ try:
+ item = self._events[self._index]
+ self._index += 1
+ return item
+ except IndexError:
+ pass
+ if self._error:
+ e = self._error
+ self._error = None
+ raise e
+ if self._parser is None:
+ self.root = self._root
+ if self._close_file:
+ self._file.close()
+ raise StopIteration
+ # load event buffer
+ del self._events[:]
+ self._index = 0
+ data = self._file.read(16384)
+ if data:
+ try:
+ self._parser.feed(data)
+ except SyntaxError as exc:
+ self._error = exc
+ else:
+ self._root = self._parser.close()
+ self._parser = None
+
+ def __iter__(self):
+ return self
+
+##
+# Parses an XML document from a string constant. This function can
+# be used to embed "XML literals" in Python code.
+#
+# @param source A string containing XML data.
+# @param parser An optional parser instance. If not given, the
+# standard {@link XMLParser} parser is used.
+# @return An Element instance.
+# @defreturn Element
+
+def XML(text, parser=None):
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ parser.feed(text)
+ return parser.close()
+
+##
+# Parses an XML document from a string constant, and also returns
+# a dictionary which maps from element id:s to elements.
+#
+# @param source A string containing XML data.
+# @param parser An optional parser instance. If not given, the
+# standard {@link XMLParser} parser is used.
+# @return A tuple containing an Element instance and a dictionary.
+# @defreturn (Element, dictionary)
+
+def XMLID(text, parser=None):
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ parser.feed(text)
+ tree = parser.close()
+ ids = {}
+ for elem in tree.iter():
+ id = elem.get("id")
+ if id:
+ ids[id] = elem
+ return tree, ids
+
+##
+# Parses an XML document from a string constant. Same as {@link #XML}.
+#
+# @def fromstring(text)
+# @param source A string containing XML data.
+# @return An Element instance.
+# @defreturn Element
+
+fromstring = XML
+
+##
+# Parses an XML document from a sequence of string fragments.
+#
+# @param sequence A list or other sequence containing XML data fragments.
+# @param parser An optional parser instance. If not given, the
+# standard {@link XMLParser} parser is used.
+# @return An Element instance.
+# @defreturn Element
+# @since 1.3
+
+def fromstringlist(sequence, parser=None):
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ for text in sequence:
+ parser.feed(text)
+ return parser.close()
+
+# --------------------------------------------------------------------
+
+##
+# Generic element structure builder. This builder converts a sequence
+# of {@link #TreeBuilder.start}, {@link #TreeBuilder.data}, and {@link
+# #TreeBuilder.end} method calls to a well-formed element structure.
+# <p>
+# You can use this class to build an element structure using a custom XML
+# parser, or a parser for some other XML-like format.
+#
+# @param element_factory Optional element factory. This factory
+# is called to create new Element instances, as necessary.
+
+class TreeBuilder(object):
+
+ def __init__(self, element_factory=None):
+ self._data = [] # data collector
+ self._elem = [] # element stack
+ self._last = None # last element
+ self._tail = None # true if we're after an end tag
+ if element_factory is None:
+ element_factory = Element
+ self._factory = element_factory
+
+ ##
+ # Flushes the builder buffers, and returns the toplevel document
+ # element.
+ #
+ # @return An Element instance.
+ # @defreturn Element
+
+ def close(self):
+ assert len(self._elem) == 0, "missing end tags"
+ assert self._last is not None, "missing toplevel element"
+ return self._last
+
+ def _flush(self):
+ if self._data:
+ if self._last is not None:
+ text = "".join(self._data)
+ if self._tail:
+ assert self._last.tail is None, "internal error (tail)"
+ self._last.tail = text
+ else:
+ assert self._last.text is None, "internal error (text)"
+ self._last.text = text
+ self._data = []
+
+ ##
+ # Adds text to the current element.
+ #
+ # @param data A string. This should be either an 8-bit string
+ # containing ASCII text, or a Unicode string.
+
+ def data(self, data):
+ self._data.append(data)
+
+ ##
+ # Opens a new element.
+ #
+ # @param tag The element name.
+ # @param attrib A dictionary containing element attributes.
+ # @return The opened element.
+ # @defreturn Element
+
+ def start(self, tag, attrs):
+ self._flush()
+ self._last = elem = self._factory(tag, attrs)
+ if self._elem:
+ self._elem[-1].append(elem)
+ self._elem.append(elem)
+ self._tail = 0
+ return elem
+
+ ##
+ # Closes the current element.
+ #
+ # @param tag The element name.
+ # @return The closed element.
+ # @defreturn Element
+
+ def end(self, tag):
+ self._flush()
+ self._last = self._elem.pop()
+ assert self._last.tag == tag,\
+ "end tag mismatch (expected %s, got %s)" % (
+ self._last.tag, tag)
+ self._tail = 1
+ return self._last
+
+##
+# Element structure builder for XML source data, based on the
+# <b>expat</b> parser.
+#
+# @keyparam target Target object. If omitted, the builder uses an
+# instance of the standard {@link #TreeBuilder} class.
+# @keyparam html Predefine HTML entities. This flag is not supported
+# by the current implementation.
+# @keyparam encoding Optional encoding. If given, the value overrides
+# the encoding specified in the XML file.
+# @see #ElementTree
+# @see #TreeBuilder
+
+class XMLParser(object):
+
+ def __init__(self, html=0, target=None, encoding=None):
+ try:
+ from xml.parsers import expat
+ except ImportError:
+ try:
+ import pyexpat as expat
+ except ImportError:
+ raise ImportError(
+ "No module named expat; use SimpleXMLTreeBuilder instead"
+ )
+ parser = expat.ParserCreate(encoding, "}")
+ if target is None:
+ target = TreeBuilder()
+ # underscored names are provided for compatibility only
+ self.parser = self._parser = parser
+ self.target = self._target = target
+ self._error = expat.error
+ self._names = {} # name memo cache
+ # callbacks
+ parser.DefaultHandlerExpand = self._default
+ parser.StartElementHandler = self._start
+ parser.EndElementHandler = self._end
+ parser.CharacterDataHandler = self._data
+ # optional callbacks
+ parser.CommentHandler = self._comment
+ parser.ProcessingInstructionHandler = self._pi
+ # let expat do the buffering, if supported
+ try:
+ self._parser.buffer_text = 1
+ except AttributeError:
+ pass
+ # use new-style attribute handling, if supported
+ try:
+ self._parser.ordered_attributes = 1
+ self._parser.specified_attributes = 1
+ parser.StartElementHandler = self._start_list
+ except AttributeError:
+ pass
+ self._doctype = None
+ self.entity = {}
+ try:
+ self.version = "Expat %d.%d.%d" % expat.version_info
+ except AttributeError:
+ pass # unknown
+
+ def _raiseerror(self, value):
+ err = ParseError(value)
+ err.code = value.code
+ err.position = value.lineno, value.offset
+ raise err
+
+ def _fixtext(self, text):
+ # convert text string to ascii, if possible
+ try:
+ return text.encode("ascii")
+ except UnicodeError:
+ return text
+
+ def _fixname(self, key):
+ # expand qname, and convert name string to ascii, if possible
+ try:
+ name = self._names[key]
+ except KeyError:
+ name = key
+ if "}" in name:
+ name = "{" + name
+ self._names[key] = name = self._fixtext(name)
+ return name
+
+ def _start(self, tag, attrib_in):
+ fixname = self._fixname
+ fixtext = self._fixtext
+ tag = fixname(tag)
+ attrib = {}
+ for key, value in attrib_in.items():
+ attrib[fixname(key)] = fixtext(value)
+ return self.target.start(tag, attrib)
+
+ def _start_list(self, tag, attrib_in):
+ fixname = self._fixname
+ fixtext = self._fixtext
+ tag = fixname(tag)
+ attrib = {}
+ if attrib_in:
+ for i in range(0, len(attrib_in), 2):
+ attrib[fixname(attrib_in[i])] = fixtext(attrib_in[i+1])
+ return self.target.start(tag, attrib)
+
+ def _data(self, text):
+ return self.target.data(self._fixtext(text))
+
+ def _end(self, tag):
+ return self.target.end(self._fixname(tag))
+
+ def _comment(self, data):
+ try:
+ comment = self.target.comment
+ except AttributeError:
+ pass
+ else:
+ return comment(self._fixtext(data))
+
+ def _pi(self, target, data):
+ try:
+ pi = self.target.pi
+ except AttributeError:
+ pass
+ else:
+ return pi(self._fixtext(target), self._fixtext(data))
+
+ def _default(self, text):
+ prefix = text[:1]
+ if prefix == "&":
+ # deal with undefined entities
+ try:
+ self.target.data(self.entity[text[1:-1]])
+ except KeyError:
+ from xml.parsers import expat
+ err = expat.error(
+ "undefined entity %s: line %d, column %d" %
+ (text, self._parser.ErrorLineNumber,
+ self._parser.ErrorColumnNumber)
+ )
+ err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
+ err.lineno = self._parser.ErrorLineNumber
+ err.offset = self._parser.ErrorColumnNumber
+ raise err
+ elif prefix == "<" and text[:9] == "<!DOCTYPE":
+ self._doctype = [] # inside a doctype declaration
+ elif self._doctype is not None:
+ # parse doctype contents
+ if prefix == ">":
+ self._doctype = None
+ return
+ text = text.strip()
+ if not text:
+ return
+ self._doctype.append(text)
+ n = len(self._doctype)
+ if n > 2:
+ type = self._doctype[1]
+ if type == "PUBLIC" and n == 4:
+ name, type, pubid, system = self._doctype
+ elif type == "SYSTEM" and n == 3:
+ name, type, system = self._doctype
+ pubid = None
+ else:
+ return
+ if pubid:
+ pubid = pubid[1:-1]
+ if hasattr(self.target, "doctype"):
+ self.target.doctype(name, pubid, system[1:-1])
+ elif self.doctype is not self._XMLParser__doctype:
+ # warn about deprecated call
+ self._XMLParser__doctype(name, pubid, system[1:-1])
+ self.doctype(name, pubid, system[1:-1])
+ self._doctype = None
+
+ ##
+ # (Deprecated) Handles a doctype declaration.
+ #
+ # @param name Doctype name.
+ # @param pubid Public identifier.
+ # @param system System identifier.
+
+ def doctype(self, name, pubid, system):
+ """This method of XMLParser is deprecated."""
+ warnings.warn(
+ "This method of XMLParser is deprecated. Define doctype() "
+ "method on the TreeBuilder target.",
+ DeprecationWarning,
+ )
+
+ # sentinel, if doctype is redefined in a subclass
+ __doctype = doctype
+
+ ##
+ # Feeds data to the parser.
+ #
+ # @param data Encoded data.
+
+ def feed(self, data):
+ try:
+ self._parser.Parse(data, 0)
+ except self._error, v:
+ self._raiseerror(v)
+
+ ##
+ # Finishes feeding data to the parser.
+ #
+ # @return An element structure.
+ # @defreturn Element
+
+ def close(self):
+ try:
+ self._parser.Parse("", 1) # end of data
+ except self._error, v:
+ self._raiseerror(v)
+ tree = self.target.close()
+ del self.target, self._parser # get rid of circular references
+ return tree
+
+# compatibility
+XMLTreeBuilder = XMLParser
+
+# workaround circular import.
+try:
+ from ElementC14N import _serialize_c14n
+ _serialize["c14n"] = _serialize_c14n
+except ImportError:
+ pass
diff --git a/InstallerResources/third_party/etree/__init__.py b/InstallerResources/third_party/etree/__init__.py
index 1fd62da..27fd8f6 100644
--- a/InstallerResources/third_party/etree/__init__.py
+++ b/InstallerResources/third_party/etree/__init__.py
@@ -1,33 +1,33 @@
-# $Id: __init__.py 3375 2008-02-13 08:05:08Z fredrik $
-# elementtree package
-
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2008 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/psf/license for licensing details.
+# $Id: __init__.py 3375 2008-02-13 08:05:08Z fredrik $
+# elementtree package
+
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2008 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/psf/license for licensing details.
diff --git a/InstallerResources/third_party/etree/cElementTree.py b/InstallerResources/third_party/etree/cElementTree.py
index db12fde..a6f127a 100644
--- a/InstallerResources/third_party/etree/cElementTree.py
+++ b/InstallerResources/third_party/etree/cElementTree.py
@@ -1,3 +1,3 @@
-# Wrapper module for _elementtree
-
-from _elementtree import *
+# Wrapper module for _elementtree
+
+from _elementtree import *
diff --git a/InstallerResources/xml_patch.py b/InstallerResources/xml_patch.py
index 256e838..5665500 100644
--- a/InstallerResources/xml_patch.py
+++ b/InstallerResources/xml_patch.py
@@ -1,174 +1,174 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" This module is a utility for applying an xml patch to an xml file.
-
-The format of the patch is described in the documentation for
-the patch_xml() function.
-"""
-
-import collections
-import copy
-import third_party.etree.ElementTree as ElementTree
-
-
-def PatchXML(source_xml_tree, patch_xml_tree):
- """Applies a patch to the source xml and returns a new merged xml tree.
-
- Given a patch xml tree, it applies the patch to the source xml tree
- and returns the resulting modified xml tree.
-
- Patching is done by reading the patch_xml_tree for an element and then
- finding the in-order matching element in the source_xml_tree. Both elements
- are entered to look for matching sub-elements recursively.
-
- Patching occurs when a <PatchRemove> or <PatchAdd> element is encountered
- in the patch xml tree. For a remove operation, the first element in the
- source_xml_tree from the current read position that matches the contents of
- the <PatchRemove> element is removed. The read pointer is updated accordingly.
- For an add operation, the contents of the <PatchAdd> element is added at the
- current reading location.
-
- If for example, an add operation needs to be done after certain elements,
- the elements can be listed before the <PatchAdd> operation so that they are
- matched first before the add operation.
-
- Example:
- Source file:
- <a>
- <b></b>
- <c></c>
- </a>
-
- Patch file:
- <a>
- <b></b>
- <PatchAdd><zzz></zzz></PatchAdd>
- </a>
-
- Result:
- <a>
- <b></b>
- <zzz></zzz>
- <c></c>
- </a>
-
-
- Args:
- source_xml_tree: An ElementTree object with base xml to change.
- patch_xml_tree: An ElementTree object with xml to apply. See above notes
- for the xml structure of a patch.
-
- Returns:
- A new xml tree based on source with the patch applied.
-
- Raises:
- General Exception indicating a merge error has occured.
- """
- source = source_xml_tree.getroot()
- patch = patch_xml_tree.getroot()
- if not ElementMatch(source, patch):
- raise Exception('Root nodes do not match, cannot merge')
- return ElementTree.ElementTree(MergeElement(source, patch))
-
-
-def MergeElement(source_elem, patch_elem):
- """Applies a single patch element to a single source element.
-
- The merge is applied recursively for sub-elements. See the documentation
- for patch_xml() for a description of how patching is done.
-
- Args:
- source_elem: An Element object with xml to change.
- patch_elem: An Element object with xml to apply.
-
- Returns:
- A new xml Element with the patch_elem applied to source_elem.
-
- Raises:
- General Exception indicating a merge error has occured.
- """
- assert ElementMatch(source_elem, patch_elem), 'Mismatched merge'
-
- # Create a new element by copying tags from source. Below we will merge
- # the subelements of source with the patch and put them in new_element.
- new_element = ElementTree.Element(source_elem.tag, source_elem.attrib)
-
- patch_children = list(patch_elem)
- patch_index = 0
- remove_targets = collections.deque()
- find_target = None
- for source_child in source_elem:
- # If we have no current patch operation then read the next patch element.
- while (len(remove_targets) == 0 and find_target is None and
- patch_index < len(patch_children)):
-
- # PatchAdd operation.
- if IsPatchAddTag(patch_children[patch_index].tag):
- for addition in patch_children[patch_index]:
- new_element.append(copy.deepcopy(addition))
-
- # Start a remove operation by creating a list of elements to skip adding.
- elif IsPatchRemoveTag(patch_children[patch_index].tag):
- remove_targets = collections.deque(
- patch_children[patch_index])
-
- # Not an Add or Remove, must be a find target (find operation).
- else:
- find_target = patch_children[patch_index]
- patch_index += 1
-
- # A remove operation means skipping adding the element to new_element.
- if (len(remove_targets) > 0 and
- ElementMatch(source_child, remove_targets[0])):
- remove_targets.popleft()
-
- # A matching find target means we must merge the sub-elements.
- elif find_target is not None and ElementMatch(source_child, find_target):
- merge = MergeElement(source_child, find_target)
- new_element.append(copy.deepcopy(merge))
- find_target = None
-
- # Otherwise this source element doesn't match any patch operations, add it.
- else:
- new_element.append(copy.deepcopy(source_child))
-
- # Raise exceptions if find/remove didn't finish before the end of the source.
- if find_target is not None:
- raise Exception('Find operation never matched:' + find_target.tag)
- elif len(remove_targets) != 0:
- raise Exception('Remove operation never matched: ' + remove_targets)
-
- # We may have more add operations after source has run empty:
- while patch_index < len(patch_children):
- if IsPatchAddTag(patch_children[patch_index].tag):
- for addition in patch_children[patch_index]:
- new_element.append(copy.deepcopy(addition))
- patch_index += 1
- else:
- raise Exception('Non-add operation attempted after source end. ' +
- 'Tag: %s, Children %s' %
- (patch_children[patch_index].tag,
- list(patch_children[patch_index])))
-
- return new_element
-
-
-def ElementMatch(elem1, elem2):
- return elem1.tag == elem2.tag and elem1.attrib == elem2.attrib
-
-
-def IsPatchAddTag(tag):
- # We look at the end of the tag because we need to ignore the namespace.
- # Because the tag can be a sub-element of arbitrary elements it could inherit
- # any default namespace.
- return tag.endswith('PatchAdd')
-
-
-def IsPatchRemoveTag(tag):
- # We look at the end of the tag because we need to ignore the namespace.
- # Because the tag can be a sub-element of arbitrary elements it could inherit
- # any default namespace.
- return tag.endswith('PatchRemove')
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" This module is a utility for applying an xml patch to an xml file.
+
+The format of the patch is described in the documentation for
+the patch_xml() function.
+"""
+
+import collections
+import copy
+import third_party.etree.ElementTree as ElementTree
+
+
+def PatchXML(source_xml_tree, patch_xml_tree):
+ """Applies a patch to the source xml and returns a new merged xml tree.
+
+ Given a patch xml tree, it applies the patch to the source xml tree
+ and returns the resulting modified xml tree.
+
+ Patching is done by reading the patch_xml_tree for an element and then
+ finding the in-order matching element in the source_xml_tree. Both elements
+ are entered to look for matching sub-elements recursively.
+
+ Patching occurs when a <PatchRemove> or <PatchAdd> element is encountered
+ in the patch xml tree. For a remove operation, the first element in the
+ source_xml_tree from the current read position that matches the contents of
+ the <PatchRemove> element is removed. The read pointer is updated accordingly.
+ For an add operation, the contents of the <PatchAdd> element is added at the
+ current reading location.
+
+ If for example, an add operation needs to be done after certain elements,
+ the elements can be listed before the <PatchAdd> operation so that they are
+ matched first before the add operation.
+
+ Example:
+ Source file:
+ <a>
+ <b></b>
+ <c></c>
+ </a>
+
+ Patch file:
+ <a>
+ <b></b>
+ <PatchAdd><zzz></zzz></PatchAdd>
+ </a>
+
+ Result:
+ <a>
+ <b></b>
+ <zzz></zzz>
+ <c></c>
+ </a>
+
+
+ Args:
+ source_xml_tree: An ElementTree object with base xml to change.
+ patch_xml_tree: An ElementTree object with xml to apply. See above notes
+ for the xml structure of a patch.
+
+ Returns:
+ A new xml tree based on source with the patch applied.
+
+ Raises:
+ General Exception indicating a merge error has occured.
+ """
+ source = source_xml_tree.getroot()
+ patch = patch_xml_tree.getroot()
+ if not ElementMatch(source, patch):
+ raise Exception('Root nodes do not match, cannot merge')
+ return ElementTree.ElementTree(MergeElement(source, patch))
+
+
+def MergeElement(source_elem, patch_elem):
+ """Applies a single patch element to a single source element.
+
+ The merge is applied recursively for sub-elements. See the documentation
+ for patch_xml() for a description of how patching is done.
+
+ Args:
+ source_elem: An Element object with xml to change.
+ patch_elem: An Element object with xml to apply.
+
+ Returns:
+ A new xml Element with the patch_elem applied to source_elem.
+
+ Raises:
+ General Exception indicating a merge error has occured.
+ """
+ assert ElementMatch(source_elem, patch_elem), 'Mismatched merge'
+
+ # Create a new element by copying tags from source. Below we will merge
+ # the subelements of source with the patch and put them in new_element.
+ new_element = ElementTree.Element(source_elem.tag, source_elem.attrib)
+
+ patch_children = list(patch_elem)
+ patch_index = 0
+ remove_targets = collections.deque()
+ find_target = None
+ for source_child in source_elem:
+ # If we have no current patch operation then read the next patch element.
+ while (len(remove_targets) == 0 and find_target is None and
+ patch_index < len(patch_children)):
+
+ # PatchAdd operation.
+ if IsPatchAddTag(patch_children[patch_index].tag):
+ for addition in patch_children[patch_index]:
+ new_element.append(copy.deepcopy(addition))
+
+ # Start a remove operation by creating a list of elements to skip adding.
+ elif IsPatchRemoveTag(patch_children[patch_index].tag):
+ remove_targets = collections.deque(
+ patch_children[patch_index])
+
+ # Not an Add or Remove, must be a find target (find operation).
+ else:
+ find_target = patch_children[patch_index]
+ patch_index += 1
+
+ # A remove operation means skipping adding the element to new_element.
+ if (len(remove_targets) > 0 and
+ ElementMatch(source_child, remove_targets[0])):
+ remove_targets.popleft()
+
+ # A matching find target means we must merge the sub-elements.
+ elif find_target is not None and ElementMatch(source_child, find_target):
+ merge = MergeElement(source_child, find_target)
+ new_element.append(copy.deepcopy(merge))
+ find_target = None
+
+ # Otherwise this source element doesn't match any patch operations, add it.
+ else:
+ new_element.append(copy.deepcopy(source_child))
+
+ # Raise exceptions if find/remove didn't finish before the end of the source.
+ if find_target is not None:
+ raise Exception('Find operation never matched:' + find_target.tag)
+ elif len(remove_targets) != 0:
+ raise Exception('Remove operation never matched: ' + remove_targets)
+
+ # We may have more add operations after source has run empty:
+ while patch_index < len(patch_children):
+ if IsPatchAddTag(patch_children[patch_index].tag):
+ for addition in patch_children[patch_index]:
+ new_element.append(copy.deepcopy(addition))
+ patch_index += 1
+ else:
+ raise Exception('Non-add operation attempted after source end. ' +
+ 'Tag: %s, Children %s' %
+ (patch_children[patch_index].tag,
+ list(patch_children[patch_index])))
+
+ return new_element
+
+
+def ElementMatch(elem1, elem2):
+ return elem1.tag == elem2.tag and elem1.attrib == elem2.attrib
+
+
+def IsPatchAddTag(tag):
+ # We look at the end of the tag because we need to ignore the namespace.
+ # Because the tag can be a sub-element of arbitrary elements it could inherit
+ # any default namespace.
+ return tag.endswith('PatchAdd')
+
+
+def IsPatchRemoveTag(tag):
+ # We look at the end of the tag because we need to ignore the namespace.
+ # Because the tag can be a sub-element of arbitrary elements it could inherit
+ # any default namespace.
+ return tag.endswith('PatchRemove')
diff --git a/NaCl.Build.CPPTasks/DependencyParser.cs b/NaCl.Build.CPPTasks/DependencyParser.cs
index 9a51660..ab39f6e 100644
--- a/NaCl.Build.CPPTasks/DependencyParser.cs
+++ b/NaCl.Build.CPPTasks/DependencyParser.cs
@@ -1,53 +1,53 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using System.IO;
-
-namespace NaCl.Build.CPPTasks
-{
- class DependencyParser
- {
- private static char[] elementEndings = new char[] { ' ', '\n', '\\' };
- private List<string> m_dependencies;
- public List<String> Dependencies
- {
- get
- {
- return m_dependencies;
- }
- }
-
- public DependencyParser(string filename)
- {
- m_dependencies = new List<string>();
-
- using (StreamReader reader = new StreamReader(filename, Encoding.ASCII))
- {
- while (!reader.EndOfStream)
- {
- string str = reader.ReadLine();
- ParseLine(str);
- }
- reader.Close();
- }
- }
-
- private void ParseLine(string line)
- {
- string[] paths = line.Split(elementEndings, StringSplitOptions.RemoveEmptyEntries);
-
- foreach (string path in paths)
- {
- // ignore the source object file
- // assumes .o file is only possible file ending with 'o'
- if (path.ElementAt(path.Length - 1) != 'o' && path.ElementAt(path.Length - 1) != ':')
- {
- string newDependency = GCCUtilities.Convert_Path_Posix_To_Windows(path);
- m_dependencies.Add(newDependency);
- }
- }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.IO;
+
+namespace NaCl.Build.CPPTasks
+{
+ class DependencyParser
+ {
+ private static char[] elementEndings = new char[] { ' ', '\n', '\\' };
+ private List<string> m_dependencies;
+ public List<String> Dependencies
+ {
+ get
+ {
+ return m_dependencies;
+ }
+ }
+
+ public DependencyParser(string filename)
+ {
+ m_dependencies = new List<string>();
+
+ using (StreamReader reader = new StreamReader(filename, Encoding.ASCII))
+ {
+ while (!reader.EndOfStream)
+ {
+ string str = reader.ReadLine();
+ ParseLine(str);
+ }
+ reader.Close();
+ }
+ }
+
+ private void ParseLine(string line)
+ {
+ string[] paths = line.Split(elementEndings, StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (string path in paths)
+ {
+ // ignore the source object file
+ // assumes .o file is only possible file ending with 'o'
+ if (path.ElementAt(path.Length - 1) != 'o' && path.ElementAt(path.Length - 1) != ':')
+ {
+ string newDependency = GCCUtilities.Convert_Path_Posix_To_Windows(path);
+ m_dependencies.Add(newDependency);
+ }
+ }
+ }
+ }
+}
diff --git a/NaCl.Build.CPPTasks/GCCUtilities.cs b/NaCl.Build.CPPTasks/GCCUtilities.cs
index 2db604a..57ea253 100644
--- a/NaCl.Build.CPPTasks/GCCUtilities.cs
+++ b/NaCl.Build.CPPTasks/GCCUtilities.cs
@@ -1,101 +1,101 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using System.IO;
-using System.Text.RegularExpressions;
-
-namespace NaCl.Build.CPPTasks
-{
- class GCCUtilities
- {
- public const int s_CommandLineLength = 256;
-
- public static string Convert_Path_Windows_To_Posix(string path)
- {
- return path.Replace('\\', '/');
- }
-
- public static string Convert_Path_Posix_To_Windows(string path)
- {
- path = path.Replace('/', '\\');
- // also make double backslashes a single slash
- // TODO: speed this up by iterating instead of two replaces
- return path.Replace("\\\\", "\\");
- }
-
- // replace GCC error are warning output to Visual Studio format to support going to source code from error output.
- public static string Convert_Output_GCC_to_VS(string line)
- {
- string result;
- foreach (GCCRegexLineConverter converter in s_RegexConverters)
- {
- result = converter.Convert(line);
- if (result.Length > 0)
- {
- return result;
- }
- }
-
- return line;
- }
-
- private class GCCRegexLineConverter
- {
- public Regex OutputExpression { get; set; }
-
- //public string OutputIdentifier { get; set; }
- public string FilenameIdentifier { get; set; }
- public string RemainderIdentifier { get; set; }
-
- // returns empty string if cannot convert.
- public string Convert(string line)
- {
- //Regex expression = new Regex(OutputIdentifier);
- if (OutputExpression.IsMatch(line))
- {
- string filename = OutputExpression.Replace(line, FilenameIdentifier);
-
- // GetFullPath may throw an exception.
- try
- {
- string fullPath = Path.GetFullPath(filename);
- string remainder = OutputExpression.Replace(line, RemainderIdentifier);
-
- string newLine = fullPath + remainder;
-
- return newLine;
- }
- catch
- {
- }
- }
-
- return string.Empty;
- }
- } // GCCRegexLineConverter
-
- private static readonly List<GCCRegexLineConverter> s_RegexConverters = new List<GCCRegexLineConverter>
- {
- new GCCRegexLineConverter
- {
- OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):([1-9]\d*):([1-9]\d*):(.*$)"),
- FilenameIdentifier = @"$1",
- RemainderIdentifier = @"($2,$3):$4"
- },
- new GCCRegexLineConverter
- {
- OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):([1-9]\d*):(.*$)"),
- FilenameIdentifier = @"$1",
- RemainderIdentifier = @"($2):$3"
- },
- new GCCRegexLineConverter
- {
- OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):(.?.?[^:]*.*?):([1-9]\d*):(.*$)"),
- FilenameIdentifier = @"$2",
- RemainderIdentifier = @"($3):'$1' $4"
- }
- };
- } // GCCUtilities
-} // namespace
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace NaCl.Build.CPPTasks
+{
+ class GCCUtilities
+ {
+ public const int s_CommandLineLength = 256;
+
+ public static string Convert_Path_Windows_To_Posix(string path)
+ {
+ return path.Replace('\\', '/');
+ }
+
+ public static string Convert_Path_Posix_To_Windows(string path)
+ {
+ path = path.Replace('/', '\\');
+ // also make double backslashes a single slash
+ // TODO: speed this up by iterating instead of two replaces
+ return path.Replace("\\\\", "\\");
+ }
+
+ // replace GCC error are warning output to Visual Studio format to support going to source code from error output.
+ public static string Convert_Output_GCC_to_VS(string line)
+ {
+ string result;
+ foreach (GCCRegexLineConverter converter in s_RegexConverters)
+ {
+ result = converter.Convert(line);
+ if (result.Length > 0)
+ {
+ return result;
+ }
+ }
+
+ return line;
+ }
+
+ private class GCCRegexLineConverter
+ {
+ public Regex OutputExpression { get; set; }
+
+ //public string OutputIdentifier { get; set; }
+ public string FilenameIdentifier { get; set; }
+ public string RemainderIdentifier { get; set; }
+
+ // returns empty string if cannot convert.
+ public string Convert(string line)
+ {
+ //Regex expression = new Regex(OutputIdentifier);
+ if (OutputExpression.IsMatch(line))
+ {
+ string filename = OutputExpression.Replace(line, FilenameIdentifier);
+
+ // GetFullPath may throw an exception.
+ try
+ {
+ string fullPath = Path.GetFullPath(filename);
+ string remainder = OutputExpression.Replace(line, RemainderIdentifier);
+
+ string newLine = fullPath + remainder;
+
+ return newLine;
+ }
+ catch
+ {
+ }
+ }
+
+ return string.Empty;
+ }
+ } // GCCRegexLineConverter
+
+ private static readonly List<GCCRegexLineConverter> s_RegexConverters = new List<GCCRegexLineConverter>
+ {
+ new GCCRegexLineConverter
+ {
+ OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):([1-9]\d*):([1-9]\d*):(.*$)"),
+ FilenameIdentifier = @"$1",
+ RemainderIdentifier = @"($2,$3):$4"
+ },
+ new GCCRegexLineConverter
+ {
+ OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):([1-9]\d*):(.*$)"),
+ FilenameIdentifier = @"$1",
+ RemainderIdentifier = @"($2):$3"
+ },
+ new GCCRegexLineConverter
+ {
+ OutputExpression = new Regex(@"^\s*(.?.?[^:]*.*?):(.?.?[^:]*.*?):([1-9]\d*):(.*$)"),
+ FilenameIdentifier = @"$2",
+ RemainderIdentifier = @"($3):'$1' $4"
+ }
+ };
+ } // GCCUtilities
+} // namespace
diff --git a/NaCl.Build.CPPTasks/NaClCompile.cs b/NaCl.Build.CPPTasks/NaClCompile.cs
index 7c91a26..5682575 100644
--- a/NaCl.Build.CPPTasks/NaClCompile.cs
+++ b/NaCl.Build.CPPTasks/NaClCompile.cs
@@ -1,645 +1,645 @@
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Collections;
-using System.IO;
-using System.Reflection;
-using System.Resources;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-using System.Diagnostics;
-
-namespace NaCl.Build.CPPTasks
-{
- public class NaClCompile : ToolTask
- {
- private XamlParser m_XamlParser;
- private ITaskItem[] excludedInputPaths;
- private ITaskItem[] tlogReadFiles;
- private ITaskItem tlogCommandFile;
- private ITaskItem[] tlogWriteFiles;
- private CanonicalTrackedInputFiles trackedInputFiles;
- private bool skippedExecution;
- private ITaskItem[] compileSourceList;
- public bool BuildingInIDE { get; set; }
- private string m_toolname;
- private bool trackFileAccess;
- private bool minimalRebuildFromTracking;
- private string pathToLog;
-
- [Required]
- public string PropertiesFile { get; set; }
-
- [Required]
- public ITaskItem[] Sources { get; set; }
-
- [Required]
- public string NaCLCompilerPath { get; set; }
-
- [Required]
- public string OutputCommandLine { get; set; }
-
- [Required]
- public string TrackerLogDirectory { get; set; }
-
-
- protected override string GenerateFullPathToTool() { return ToolName; }
-
- public NaClCompile()
- : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
- {
- this.pathToLog = string.Empty;
- this.EnvironmentVariables = new string []{"CYGWIN=nodosfilewarning", "LC_CTYPE=C"};
- }
-
- protected IDictionary<string, string> GenerateCommandLinesFromTlog()
- {
- IDictionary<string, string> cmdLineDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- string tlogFilename = this.TLogCommandFile.GetMetadata("FullPath");
- if (File.Exists(tlogFilename))
- {
- using (StreamReader reader = File.OpenText(tlogFilename))
- {
- string filename = string.Empty;
- for (string lineStr = reader.ReadLine(); lineStr != null; lineStr = reader.ReadLine())
- {
- if (lineStr.Length == 0 ||
- (lineStr[0] == '^' && lineStr.Length == 1))
- {
- Log.LogMessage(MessageImportance.High, "Invalid line in command tlog");
- break;
- }
- else if (lineStr[0] == '^')
- {
- filename = lineStr.Substring(1);
- }
- else
- {
- cmdLineDictionary[filename] = lineStr;
- }
- }
- }
- }
- return cmdLineDictionary;
- }
-
- protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
- {
- base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance);
- }
-
- private void ConstructReadTLog(ITaskItem[] compiledSources, CanonicalTrackedOutputFiles outputs)
- {
- string trackerPath = Path.GetFullPath(TlogDirectory + ReadTLogFilenames[0]);
-
- //save tlog for sources not compiled during this execution
- TaskItem readTrackerItem = new TaskItem(trackerPath);
- CanonicalTrackedInputFiles files = new CanonicalTrackedInputFiles(new TaskItem[] { readTrackerItem }, Sources, outputs, false, false);
- files.RemoveEntriesForSource(compiledSources);
- files.SaveTlog();
-
- //add tlog information for compiled sources
- using (StreamWriter writer = new StreamWriter(trackerPath, true, Encoding.Unicode))
- {
- foreach (ITaskItem source in compiledSources)
- {
- string sourcePath = Path.GetFullPath(source.ItemSpec).ToUpperInvariant();
-
- string objectFilePath = Path.GetFullPath(source.GetMetadata("ObjectFileName"));
- string depFilePath = Path.ChangeExtension(objectFilePath, ".d");
-
- try
- {
- if (File.Exists(depFilePath) == false)
- {
- Log.LogMessage(MessageImportance.High, depFilePath + " not found");
- }
- else
- {
- writer.WriteLine("^" + sourcePath);
- DependencyParser parser = new DependencyParser(depFilePath);
-
- foreach (string filename in parser.Dependencies)
- {
- //source itself not required
- if (filename == sourcePath)
- continue;
-
- if (File.Exists(filename) == false)
- {
- Log.LogMessage(MessageImportance.High, "File " + sourcePath + " is missing dependency " + filename);
- }
-
- writer.WriteLine(filename);
- }
-
- //remove d file
- try
- {
- File.Delete(depFilePath);
- }
- finally
- {
-
- }
- }
-
- }
- catch (Exception)
- {
- Log.LogError("Failed to update " + readTrackerItem + " for " + sourcePath);
- }
- }
- }
- }
-
- private CanonicalTrackedOutputFiles OutputWriteTrackerLog(ITaskItem[] compiledSources)
- {
- string path = Path.Combine(TlogDirectory, WriteTLogFilename);
- TaskItem item = new TaskItem(path);
- CanonicalTrackedOutputFiles trackedFiles = new CanonicalTrackedOutputFiles(new TaskItem[] { item });
-
- foreach (ITaskItem sourceItem in compiledSources)
- {
- //remove this entry associated with compiled source which is about to be recomputed
- trackedFiles.RemoveEntriesForSource(sourceItem);
-
- //add entry with updated information
- trackedFiles.AddComputedOutputForSourceRoot( Path.GetFullPath(sourceItem.ItemSpec).ToUpperInvariant(),
- Path.GetFullPath(sourceItem.GetMetadata("ObjectFileName")).ToUpperInvariant());
- }
-
- //output tlog
- trackedFiles.SaveTlog();
-
- return trackedFiles;
- }
-
- private void OutputCommandTrackerLog(ITaskItem[] compiledSources)
- {
- IDictionary<string, string> commandLines = GenerateCommandLinesFromTlog();
-
- //
- if (compiledSources != null)
- {
- foreach (ITaskItem source in compiledSources)
- {
- string rmSource = FileTracker.FormatRootingMarker(source);
- commandLines[rmSource] = GenerateCommandLineFromProps(source) + " " + source.GetMetadata("FullPath").ToUpperInvariant();
- }
- }
-
- //write tlog
- using (StreamWriter writer = new StreamWriter(this.TLogCommandFile.GetMetadata("FullPath"), false, Encoding.Unicode))
- {
- foreach (KeyValuePair<string, string> p in commandLines)
- {
- string keyLine = "^" + p.Key;
- writer.WriteLine(keyLine);
- writer.WriteLine(p.Value);
- }
- }
- }
-
- protected string GenerateCommandLineFromProps(ITaskItem sourceFile)
- {
- StringBuilder commandLine = new StringBuilder(GCCUtilities.s_CommandLineLength);
-
- if (sourceFile != null)
- {
- string sourcePath = GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.ToString());
-
- // Remove rtti items as they are not relevant in C compilation and will produce warnings
- if (SourceIsC(sourceFile.ToString()))
- {
- commandLine.Replace("-fno-rtti", "");
- commandLine.Replace("-frtti", "");
- }
-
- //build command line from components and add required switches
- string props = m_XamlParser.Parse(sourceFile);
- commandLine.Append(props);
- commandLine.Append(" -MD -c ");
- commandLine.Append(sourcePath);
-
- }
-
- return commandLine.ToString();
- }
-
- protected ITaskItem[] MergeOutOfDateSources(ITaskItem[] outOfDateSourcesFromTracking, List<ITaskItem> outOfDateSourcesFromCommandLineChanges)
- {
- List<ITaskItem> mergedSources = new List<ITaskItem>(outOfDateSourcesFromTracking);
-
- foreach (ITaskItem item in outOfDateSourcesFromCommandLineChanges)
- {
- if (!mergedSources.Contains(item))
- {
- mergedSources.Add(item);
- }
- }
-
- return mergedSources.ToArray();
- }
-
- protected bool ForcedRebuildRequired()
- {
- string tlogCommandPath = null;
-
- try
- {
- tlogCommandPath = this.TLogCommandFile.GetMetadata("FullPath");
- }
- catch (Exception exception)
- {
- if (exception is InvalidOperationException || exception is NullReferenceException)
- return true;
- else
- throw;
- }
-
- //if command tlog file does not exist then force rebuild is required
- if (File.Exists(tlogCommandPath) == false)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- private int Compile(string pathToTool)
- {
- int returnCode = 0;
-
- foreach (ITaskItem sourceFileItem in CompileSourceList)
- {
- try
- {
- string commandLine = GenerateCommandLineFromProps(sourceFileItem);
-
- base.Log.LogMessageFromText(Path.GetFileName(sourceFileItem.ToString()), MessageImportance.High);
-
- if (OutputCommandLine == "true")
- {
- string logMessage = pathToTool + " " + commandLine;
- Log.LogMessageFromText(logMessage, MessageImportance.High);
- }
-
-
- // compile
- returnCode = base.ExecuteTool(pathToTool, commandLine, string.Empty);
- }
- catch (Exception)
- {
- returnCode = base.ExitCode;
- }
-
- //abort if an error was encountered
- if (returnCode != 0)
- {
- return returnCode;
- }
- }
- return returnCode;
- }
-
- protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
- {
- if (File.Exists(pathToTool) == false)
- {
- base.Log.LogMessageFromText("Unable to find NaCL compiler: " + pathToTool, MessageImportance.High);
- return -1;
- }
-
- int returnCode = -1;
-
- try
- {
- returnCode = Compile(pathToTool);
- }
- finally
- {
-
- }
- return returnCode;
- }
-
- protected override bool SkipTaskExecution()
- {
- return this.skippedExecution;
- }
-
- protected void CalcSourcesToCompile()
- {
- if (this.TrackFileAccess || this.MinimalRebuildFromTracking)
- {
- this.SetTrackerLogPaths();
- }
-
- //check if full recompile is required otherwise perform incremental
- if (this.ForcedRebuildRequired() || this.MinimalRebuildFromTracking == false)
- {
- this.CompileSourceList = this.Sources;
- if ((this.CompileSourceList == null) || (this.CompileSourceList.Length == 0))
- {
- this.SkippedExecution = true;
- }
- }
- else
- {
- //retrieve list of sources out of date due to command line changes
- List<ITaskItem> outOfDateSourcesFromCommandLineChanges = this.GetOutOfDateSourcesFromCommandLineChanges();
-
- //retrieve sources out of date due to tracking
- CanonicalTrackedOutputFiles trackedOutputFiles = new CanonicalTrackedOutputFiles(this, this.TLogWriteFiles);
- this.TrackedInputFiles = new CanonicalTrackedInputFiles(this, this.TLogReadFiles, this.Sources, this.ExcludedInputPaths, trackedOutputFiles, true, false);
- ITaskItem[] outOfDateSourcesFromTracking = this.TrackedInputFiles.ComputeSourcesNeedingCompilation();
-
- //merge out of date lists
- this.CompileSourceList = this.MergeOutOfDateSources(outOfDateSourcesFromTracking, outOfDateSourcesFromCommandLineChanges);
-
- if (this.CompileSourceList.Length == 0)
- {
- this.SkippedExecution = true;
- }
- else
- {
- //remove sources to compile from tracked file list
- this.TrackedInputFiles.RemoveEntriesForSource(this.CompileSourceList);
- trackedOutputFiles.RemoveEntriesForSource(this.CompileSourceList);
- this.TrackedInputFiles.SaveTlog();
- trackedOutputFiles.SaveTlog();
-
- this.SkippedExecution = false;
- }
- }
- }
-
- protected bool SourceIsC(string sourceFilename)
- {
- string fileExt = Path.GetExtension(sourceFilename.ToString());
-
- if (fileExt == ".c")
- return true;
- else
- return false;
- }
-
- public override bool Execute()
- {
- bool returnResult = false;
-
- try
- {
- m_XamlParser = new XamlParser(PropertiesFile);
- m_toolname = Path.GetFileNameWithoutExtension(ToolName);
- ValidateParameters();
- CalcSourcesToCompile();
-
- returnResult = base.Execute();
-
- // Update tracker log files if execution occurred
- //if (this.skippedExecution == false)
- {
- CanonicalTrackedOutputFiles outputs = OutputWriteTrackerLog(CompileSourceList);
- ConstructReadTLog(CompileSourceList, outputs);
- OutputCommandTrackerLog(CompileSourceList);
- }
- }
- finally
- {
-
- }
-
- return returnResult;
- }
-
- protected List<ITaskItem> GetOutOfDateSourcesFromCommandLineChanges()
- {
- //get dictionary of source + command lines
- IDictionary<string, string> dictionary = this.GenerateCommandLinesFromTlog();
- List<ITaskItem> outOfDateSources = new List<ITaskItem>();
-
- //add sources to out of date list if the tlog dictionary string do not match the generated command line string
- StringBuilder currentCommandLine = new StringBuilder(GCCUtilities.s_CommandLineLength);
- foreach (ITaskItem sourceItem in Sources)
- {
- currentCommandLine.Length = 0;
-
- currentCommandLine.Append(GenerateCommandLineFromProps(sourceItem));
- currentCommandLine.Append(" ");
- currentCommandLine.Append(sourceItem.GetMetadata("FullPath").ToUpperInvariant());
-
- string tlogCommandLine = null;
- if (dictionary.TryGetValue(FileTracker.FormatRootingMarker(sourceItem), out tlogCommandLine))
- {
- if ((tlogCommandLine == null) || !currentCommandLine.ToString().Equals(tlogCommandLine, StringComparison.Ordinal))
- {
- outOfDateSources.Add(sourceItem);
- }
- }
- else
- {
- outOfDateSources.Add(sourceItem);
- }
- }
- return outOfDateSources;
- }
-
- protected virtual void SetTrackerLogPaths()
- {
- if (this.TLogCommandFile == null)
- {
- string commandFile = Path.Combine(this.TlogDirectory, this.CommandTLogFilename);
- this.TLogCommandFile = new TaskItem(commandFile);
- }
-
- if (this.TLogReadFiles == null)
- {
- this.TLogReadFiles = new ITaskItem[this.ReadTLogFilenames.Length];
- for (int n = 0; n < this.ReadTLogFilenames.Length; n++)
- {
- string readFile = Path.Combine(this.TlogDirectory, this.ReadTLogFilenames[n]);
- this.TLogReadFiles[n] = new TaskItem(readFile);
- }
- }
-
- if (this.TLogWriteFiles == null)
- {
- this.TLogWriteFiles = new ITaskItem[1];
- string writeFile = Path.Combine(this.TlogDirectory, this.WriteTLogFilename);
- this.TLogWriteFiles[0] = new TaskItem(writeFile);
- }
- }
-
-
- //props
- protected string CommandTLogFilename
- {
- get
- {
- return m_toolname + ".compile.command.1.tlog";
- }
- }
-
- protected string[] ReadTLogFilenames
- {
- get
- {
- return new string[] { m_toolname + ".compile.read.1.tlog" };
- }
- }
-
- [Output]
- public bool SkippedExecution
- {
- get
- {
- return this.skippedExecution;
- }
- set
- {
- this.skippedExecution = value;
- }
- }
-
- public ITaskItem TLogCommandFile
- {
- get
- {
- return this.tlogCommandFile;
- }
- set
- {
- this.tlogCommandFile = value;
- }
- }
-
- protected string TlogDirectory
- {
- get
- {
- if (this.TrackerLogDirectory != null)
- {
- return this.TrackerLogDirectory;
- }
- return string.Empty;
- }
- }
-
- public bool MinimalRebuildFromTracking
- {
- get
- {
- return this.minimalRebuildFromTracking;
- }
- set
- {
- this.minimalRebuildFromTracking = value;
- }
- }
-
-
- public ITaskItem[] TLogReadFiles
- {
- get
- {
- return this.tlogReadFiles;
- }
- set
- {
- this.tlogReadFiles = value;
- }
- }
-
- public ITaskItem[] ExcludedInputPaths
- {
- get
- {
- return this.excludedInputPaths;
- }
- set
- {
- this.excludedInputPaths = value;
- }
- }
-
-
- public ITaskItem[] TLogWriteFiles
- {
- get
- {
- return this.tlogWriteFiles;
- }
- set
- {
- this.tlogWriteFiles = value;
- }
- }
-
- protected string WriteTLogFilename
- {
- get
- {
- return m_toolname + ".compile.write.1.tlog";
- }
- }
-
- public bool TrackFileAccess
- {
- get
- {
- return this.trackFileAccess;
- }
- set
- {
- this.trackFileAccess = value;
- }
- }
-
- protected CanonicalTrackedInputFiles TrackedInputFiles
- {
- get
- {
- return this.trackedInputFiles;
- }
- set
- {
- this.trackedInputFiles = value;
- }
- }
-
- [Output]
- public ITaskItem[] CompileSourceList
- {
- get
- {
- return this.compileSourceList;
- }
- set
- {
- this.compileSourceList = value;
- }
- }
-
- protected override string ToolName
- {
- get
- {
- return NaCLCompilerPath;
- }
- }
-
- protected override Encoding ResponseFileEncoding
- {
- get
- {
- return Encoding.ASCII;
- }
- }
- }
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+using System.Resources;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+using System.Diagnostics;
+
+namespace NaCl.Build.CPPTasks
+{
+ public class NaClCompile : ToolTask
+ {
+ private XamlParser m_XamlParser;
+ private ITaskItem[] excludedInputPaths;
+ private ITaskItem[] tlogReadFiles;
+ private ITaskItem tlogCommandFile;
+ private ITaskItem[] tlogWriteFiles;
+ private CanonicalTrackedInputFiles trackedInputFiles;
+ private bool skippedExecution;
+ private ITaskItem[] compileSourceList;
+ public bool BuildingInIDE { get; set; }
+ private string m_toolname;
+ private bool trackFileAccess;
+ private bool minimalRebuildFromTracking;
+ private string pathToLog;
+
+ [Required]
+ public string PropertiesFile { get; set; }
+
+ [Required]
+ public ITaskItem[] Sources { get; set; }
+
+ [Required]
+ public string NaCLCompilerPath { get; set; }
+
+ [Required]
+ public string OutputCommandLine { get; set; }
+
+ [Required]
+ public string TrackerLogDirectory { get; set; }
+
+
+ protected override string GenerateFullPathToTool() { return ToolName; }
+
+ public NaClCompile()
+ : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
+ {
+ this.pathToLog = string.Empty;
+ this.EnvironmentVariables = new string []{"CYGWIN=nodosfilewarning", "LC_CTYPE=C"};
+ }
+
+ protected IDictionary<string, string> GenerateCommandLinesFromTlog()
+ {
+ IDictionary<string, string> cmdLineDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ string tlogFilename = this.TLogCommandFile.GetMetadata("FullPath");
+ if (File.Exists(tlogFilename))
+ {
+ using (StreamReader reader = File.OpenText(tlogFilename))
+ {
+ string filename = string.Empty;
+ for (string lineStr = reader.ReadLine(); lineStr != null; lineStr = reader.ReadLine())
+ {
+ if (lineStr.Length == 0 ||
+ (lineStr[0] == '^' && lineStr.Length == 1))
+ {
+ Log.LogMessage(MessageImportance.High, "Invalid line in command tlog");
+ break;
+ }
+ else if (lineStr[0] == '^')
+ {
+ filename = lineStr.Substring(1);
+ }
+ else
+ {
+ cmdLineDictionary[filename] = lineStr;
+ }
+ }
+ }
+ }
+ return cmdLineDictionary;
+ }
+
+ protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
+ {
+ base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance);
+ }
+
+ private void ConstructReadTLog(ITaskItem[] compiledSources, CanonicalTrackedOutputFiles outputs)
+ {
+ string trackerPath = Path.GetFullPath(TlogDirectory + ReadTLogFilenames[0]);
+
+ //save tlog for sources not compiled during this execution
+ TaskItem readTrackerItem = new TaskItem(trackerPath);
+ CanonicalTrackedInputFiles files = new CanonicalTrackedInputFiles(new TaskItem[] { readTrackerItem }, Sources, outputs, false, false);
+ files.RemoveEntriesForSource(compiledSources);
+ files.SaveTlog();
+
+ //add tlog information for compiled sources
+ using (StreamWriter writer = new StreamWriter(trackerPath, true, Encoding.Unicode))
+ {
+ foreach (ITaskItem source in compiledSources)
+ {
+ string sourcePath = Path.GetFullPath(source.ItemSpec).ToUpperInvariant();
+
+ string objectFilePath = Path.GetFullPath(source.GetMetadata("ObjectFileName"));
+ string depFilePath = Path.ChangeExtension(objectFilePath, ".d");
+
+ try
+ {
+ if (File.Exists(depFilePath) == false)
+ {
+ Log.LogMessage(MessageImportance.High, depFilePath + " not found");
+ }
+ else
+ {
+ writer.WriteLine("^" + sourcePath);
+ DependencyParser parser = new DependencyParser(depFilePath);
+
+ foreach (string filename in parser.Dependencies)
+ {
+ //source itself not required
+ if (filename == sourcePath)
+ continue;
+
+ if (File.Exists(filename) == false)
+ {
+ Log.LogMessage(MessageImportance.High, "File " + sourcePath + " is missing dependency " + filename);
+ }
+
+ writer.WriteLine(filename);
+ }
+
+ //remove d file
+ try
+ {
+ File.Delete(depFilePath);
+ }
+ finally
+ {
+
+ }
+ }
+
+ }
+ catch (Exception)
+ {
+ Log.LogError("Failed to update " + readTrackerItem + " for " + sourcePath);
+ }
+ }
+ }
+ }
+
+ private CanonicalTrackedOutputFiles OutputWriteTrackerLog(ITaskItem[] compiledSources)
+ {
+ string path = Path.Combine(TlogDirectory, WriteTLogFilename);
+ TaskItem item = new TaskItem(path);
+ CanonicalTrackedOutputFiles trackedFiles = new CanonicalTrackedOutputFiles(new TaskItem[] { item });
+
+ foreach (ITaskItem sourceItem in compiledSources)
+ {
+ //remove this entry associated with compiled source which is about to be recomputed
+ trackedFiles.RemoveEntriesForSource(sourceItem);
+
+ //add entry with updated information
+ trackedFiles.AddComputedOutputForSourceRoot( Path.GetFullPath(sourceItem.ItemSpec).ToUpperInvariant(),
+ Path.GetFullPath(sourceItem.GetMetadata("ObjectFileName")).ToUpperInvariant());
+ }
+
+ //output tlog
+ trackedFiles.SaveTlog();
+
+ return trackedFiles;
+ }
+
+ private void OutputCommandTrackerLog(ITaskItem[] compiledSources)
+ {
+ IDictionary<string, string> commandLines = GenerateCommandLinesFromTlog();
+
+ //
+ if (compiledSources != null)
+ {
+ foreach (ITaskItem source in compiledSources)
+ {
+ string rmSource = FileTracker.FormatRootingMarker(source);
+ commandLines[rmSource] = GenerateCommandLineFromProps(source) + " " + source.GetMetadata("FullPath").ToUpperInvariant();
+ }
+ }
+
+ //write tlog
+ using (StreamWriter writer = new StreamWriter(this.TLogCommandFile.GetMetadata("FullPath"), false, Encoding.Unicode))
+ {
+ foreach (KeyValuePair<string, string> p in commandLines)
+ {
+ string keyLine = "^" + p.Key;
+ writer.WriteLine(keyLine);
+ writer.WriteLine(p.Value);
+ }
+ }
+ }
+
+ protected string GenerateCommandLineFromProps(ITaskItem sourceFile)
+ {
+ StringBuilder commandLine = new StringBuilder(GCCUtilities.s_CommandLineLength);
+
+ if (sourceFile != null)
+ {
+ string sourcePath = GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.ToString());
+
+ // Remove rtti items as they are not relevant in C compilation and will produce warnings
+ if (SourceIsC(sourceFile.ToString()))
+ {
+ commandLine.Replace("-fno-rtti", "");
+ commandLine.Replace("-frtti", "");
+ }
+
+ //build command line from components and add required switches
+ string props = m_XamlParser.Parse(sourceFile);
+ commandLine.Append(props);
+ commandLine.Append(" -MD -c ");
+ commandLine.Append(sourcePath);
+
+ }
+
+ return commandLine.ToString();
+ }
+
+ protected ITaskItem[] MergeOutOfDateSources(ITaskItem[] outOfDateSourcesFromTracking, List<ITaskItem> outOfDateSourcesFromCommandLineChanges)
+ {
+ List<ITaskItem> mergedSources = new List<ITaskItem>(outOfDateSourcesFromTracking);
+
+ foreach (ITaskItem item in outOfDateSourcesFromCommandLineChanges)
+ {
+ if (!mergedSources.Contains(item))
+ {
+ mergedSources.Add(item);
+ }
+ }
+
+ return mergedSources.ToArray();
+ }
+
+ protected bool ForcedRebuildRequired()
+ {
+ string tlogCommandPath = null;
+
+ try
+ {
+ tlogCommandPath = this.TLogCommandFile.GetMetadata("FullPath");
+ }
+ catch (Exception exception)
+ {
+ if (exception is InvalidOperationException || exception is NullReferenceException)
+ return true;
+ else
+ throw;
+ }
+
+ //if command tlog file does not exist then force rebuild is required
+ if (File.Exists(tlogCommandPath) == false)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private int Compile(string pathToTool)
+ {
+ int returnCode = 0;
+
+ foreach (ITaskItem sourceFileItem in CompileSourceList)
+ {
+ try
+ {
+ string commandLine = GenerateCommandLineFromProps(sourceFileItem);
+
+ base.Log.LogMessageFromText(Path.GetFileName(sourceFileItem.ToString()), MessageImportance.High);
+
+ if (OutputCommandLine == "true")
+ {
+ string logMessage = pathToTool + " " + commandLine;
+ Log.LogMessageFromText(logMessage, MessageImportance.High);
+ }
+
+
+ // compile
+ returnCode = base.ExecuteTool(pathToTool, commandLine, string.Empty);
+ }
+ catch (Exception)
+ {
+ returnCode = base.ExitCode;
+ }
+
+ //abort if an error was encountered
+ if (returnCode != 0)
+ {
+ return returnCode;
+ }
+ }
+ return returnCode;
+ }
+
+ protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
+ {
+ if (File.Exists(pathToTool) == false)
+ {
+ base.Log.LogMessageFromText("Unable to find NaCL compiler: " + pathToTool, MessageImportance.High);
+ return -1;
+ }
+
+ int returnCode = -1;
+
+ try
+ {
+ returnCode = Compile(pathToTool);
+ }
+ finally
+ {
+
+ }
+ return returnCode;
+ }
+
+ protected override bool SkipTaskExecution()
+ {
+ return this.skippedExecution;
+ }
+
+ protected void CalcSourcesToCompile()
+ {
+ if (this.TrackFileAccess || this.MinimalRebuildFromTracking)
+ {
+ this.SetTrackerLogPaths();
+ }
+
+ //check if full recompile is required otherwise perform incremental
+ if (this.ForcedRebuildRequired() || this.MinimalRebuildFromTracking == false)
+ {
+ this.CompileSourceList = this.Sources;
+ if ((this.CompileSourceList == null) || (this.CompileSourceList.Length == 0))
+ {
+ this.SkippedExecution = true;
+ }
+ }
+ else
+ {
+ //retrieve list of sources out of date due to command line changes
+ List<ITaskItem> outOfDateSourcesFromCommandLineChanges = this.GetOutOfDateSourcesFromCommandLineChanges();
+
+ //retrieve sources out of date due to tracking
+ CanonicalTrackedOutputFiles trackedOutputFiles = new CanonicalTrackedOutputFiles(this, this.TLogWriteFiles);
+ this.TrackedInputFiles = new CanonicalTrackedInputFiles(this, this.TLogReadFiles, this.Sources, this.ExcludedInputPaths, trackedOutputFiles, true, false);
+ ITaskItem[] outOfDateSourcesFromTracking = this.TrackedInputFiles.ComputeSourcesNeedingCompilation();
+
+ //merge out of date lists
+ this.CompileSourceList = this.MergeOutOfDateSources(outOfDateSourcesFromTracking, outOfDateSourcesFromCommandLineChanges);
+
+ if (this.CompileSourceList.Length == 0)
+ {
+ this.SkippedExecution = true;
+ }
+ else
+ {
+ //remove sources to compile from tracked file list
+ this.TrackedInputFiles.RemoveEntriesForSource(this.CompileSourceList);
+ trackedOutputFiles.RemoveEntriesForSource(this.CompileSourceList);
+ this.TrackedInputFiles.SaveTlog();
+ trackedOutputFiles.SaveTlog();
+
+ this.SkippedExecution = false;
+ }
+ }
+ }
+
+ protected bool SourceIsC(string sourceFilename)
+ {
+ string fileExt = Path.GetExtension(sourceFilename.ToString());
+
+ if (fileExt == ".c")
+ return true;
+ else
+ return false;
+ }
+
+ public override bool Execute()
+ {
+ bool returnResult = false;
+
+ try
+ {
+ m_XamlParser = new XamlParser(PropertiesFile);
+ m_toolname = Path.GetFileNameWithoutExtension(ToolName);
+ ValidateParameters();
+ CalcSourcesToCompile();
+
+ returnResult = base.Execute();
+
+ // Update tracker log files if execution occurred
+ //if (this.skippedExecution == false)
+ {
+ CanonicalTrackedOutputFiles outputs = OutputWriteTrackerLog(CompileSourceList);
+ ConstructReadTLog(CompileSourceList, outputs);
+ OutputCommandTrackerLog(CompileSourceList);
+ }
+ }
+ finally
+ {
+
+ }
+
+ return returnResult;
+ }
+
+ protected List<ITaskItem> GetOutOfDateSourcesFromCommandLineChanges()
+ {
+ //get dictionary of source + command lines
+ IDictionary<string, string> dictionary = this.GenerateCommandLinesFromTlog();
+ List<ITaskItem> outOfDateSources = new List<ITaskItem>();
+
+ //add sources to out of date list if the tlog dictionary string do not match the generated command line string
+ StringBuilder currentCommandLine = new StringBuilder(GCCUtilities.s_CommandLineLength);
+ foreach (ITaskItem sourceItem in Sources)
+ {
+ currentCommandLine.Length = 0;
+
+ currentCommandLine.Append(GenerateCommandLineFromProps(sourceItem));
+ currentCommandLine.Append(" ");
+ currentCommandLine.Append(sourceItem.GetMetadata("FullPath").ToUpperInvariant());
+
+ string tlogCommandLine = null;
+ if (dictionary.TryGetValue(FileTracker.FormatRootingMarker(sourceItem), out tlogCommandLine))
+ {
+ if ((tlogCommandLine == null) || !currentCommandLine.ToString().Equals(tlogCommandLine, StringComparison.Ordinal))
+ {
+ outOfDateSources.Add(sourceItem);
+ }
+ }
+ else
+ {
+ outOfDateSources.Add(sourceItem);
+ }
+ }
+ return outOfDateSources;
+ }
+
+ protected virtual void SetTrackerLogPaths()
+ {
+ if (this.TLogCommandFile == null)
+ {
+ string commandFile = Path.Combine(this.TlogDirectory, this.CommandTLogFilename);
+ this.TLogCommandFile = new TaskItem(commandFile);
+ }
+
+ if (this.TLogReadFiles == null)
+ {
+ this.TLogReadFiles = new ITaskItem[this.ReadTLogFilenames.Length];
+ for (int n = 0; n < this.ReadTLogFilenames.Length; n++)
+ {
+ string readFile = Path.Combine(this.TlogDirectory, this.ReadTLogFilenames[n]);
+ this.TLogReadFiles[n] = new TaskItem(readFile);
+ }
+ }
+
+ if (this.TLogWriteFiles == null)
+ {
+ this.TLogWriteFiles = new ITaskItem[1];
+ string writeFile = Path.Combine(this.TlogDirectory, this.WriteTLogFilename);
+ this.TLogWriteFiles[0] = new TaskItem(writeFile);
+ }
+ }
+
+
+ //props
+ protected string CommandTLogFilename
+ {
+ get
+ {
+ return m_toolname + ".compile.command.1.tlog";
+ }
+ }
+
+ protected string[] ReadTLogFilenames
+ {
+ get
+ {
+ return new string[] { m_toolname + ".compile.read.1.tlog" };
+ }
+ }
+
+ [Output]
+ public bool SkippedExecution
+ {
+ get
+ {
+ return this.skippedExecution;
+ }
+ set
+ {
+ this.skippedExecution = value;
+ }
+ }
+
+ public ITaskItem TLogCommandFile
+ {
+ get
+ {
+ return this.tlogCommandFile;
+ }
+ set
+ {
+ this.tlogCommandFile = value;
+ }
+ }
+
+ protected string TlogDirectory
+ {
+ get
+ {
+ if (this.TrackerLogDirectory != null)
+ {
+ return this.TrackerLogDirectory;
+ }
+ return string.Empty;
+ }
+ }
+
+ public bool MinimalRebuildFromTracking
+ {
+ get
+ {
+ return this.minimalRebuildFromTracking;
+ }
+ set
+ {
+ this.minimalRebuildFromTracking = value;
+ }
+ }
+
+
+ public ITaskItem[] TLogReadFiles
+ {
+ get
+ {
+ return this.tlogReadFiles;
+ }
+ set
+ {
+ this.tlogReadFiles = value;
+ }
+ }
+
+ public ITaskItem[] ExcludedInputPaths
+ {
+ get
+ {
+ return this.excludedInputPaths;
+ }
+ set
+ {
+ this.excludedInputPaths = value;
+ }
+ }
+
+
+ public ITaskItem[] TLogWriteFiles
+ {
+ get
+ {
+ return this.tlogWriteFiles;
+ }
+ set
+ {
+ this.tlogWriteFiles = value;
+ }
+ }
+
+ protected string WriteTLogFilename
+ {
+ get
+ {
+ return m_toolname + ".compile.write.1.tlog";
+ }
+ }
+
+ public bool TrackFileAccess
+ {
+ get
+ {
+ return this.trackFileAccess;
+ }
+ set
+ {
+ this.trackFileAccess = value;
+ }
+ }
+
+ protected CanonicalTrackedInputFiles TrackedInputFiles
+ {
+ get
+ {
+ return this.trackedInputFiles;
+ }
+ set
+ {
+ this.trackedInputFiles = value;
+ }
+ }
+
+ [Output]
+ public ITaskItem[] CompileSourceList
+ {
+ get
+ {
+ return this.compileSourceList;
+ }
+ set
+ {
+ this.compileSourceList = value;
+ }
+ }
+
+ protected override string ToolName
+ {
+ get
+ {
+ return NaCLCompilerPath;
+ }
+ }
+
+ protected override Encoding ResponseFileEncoding
+ {
+ get
+ {
+ return Encoding.ASCII;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/NaCl.Build.CPPTasks/NaClLib.cs b/NaCl.Build.CPPTasks/NaClLib.cs
index bd32bf0..2c732ee 100644
--- a/NaCl.Build.CPPTasks/NaClLib.cs
+++ b/NaCl.Build.CPPTasks/NaClLib.cs
@@ -1,161 +1,161 @@
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Collections;
-using System.IO;
-using System.Reflection;
-using System.Resources;
-using System.Text.RegularExpressions;
-using System.Diagnostics;
-
-using Microsoft.Build.Framework;
-using Microsoft.Build.CPPTasks;
-using Microsoft.Build.Utilities;
-
-namespace NaCl.Build.CPPTasks
-{
- public class NaClLib : TrackedVCToolTask
- {
- public bool BuildingInIDE { get; set; }
-
- [Required]
- public string LibrarianToolPath { get; set; }
-
- [Required]
- public string PropertiesFile { get; set; }
-
- [Required]
- public virtual string OutputFile { get; set; }
-
- [Required]
- public string OutputCommandLine { get; set; }
-
- [Required]
- public virtual ITaskItem[] Sources { get; set; }
-
-
- public NaClLib()
- : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
- {
- this.EnvironmentVariables = new string[] { "CYGWIN=nodosfilewarning", "LC_CTYPE=C" };
- }
-
- protected override string GenerateResponseFileCommands()
- {
- StringBuilder responseFileCmds = new StringBuilder(GCCUtilities.s_CommandLineLength);
- responseFileCmds.Append("rcs ");
- responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(OutputFile));
-
- foreach (ITaskItem item in Sources)
- {
- responseFileCmds.Append(" ");
- responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(item.ToString()));
- }
- return responseFileCmds.ToString();
- }
-
- protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
- {
- if (OutputCommandLine == "true")
- {
- Log.LogMessage(MessageImportance.High, pathToTool + " " + responseFileCommands);
- }
-
- return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
- }
-
-
-
- public virtual string PlatformToolset
- {
- get
- {
- return "GCC";
- }
- }
-
- protected override bool MaintainCompositeRootingMarkers
- {
- get
- {
- return true;
- }
- }
-
- protected override ITaskItem[] TrackedInputFiles
- {
- get
- {
- return Sources;
- }
- }
-
-
- protected override Encoding ResponseFileEncoding
- {
- get
- {
- return Encoding.ASCII;
- }
- }
-
- protected override string ToolName
- {
- get
- {
- return LibrarianToolPath;
- }
- }
-
- protected override string TrackerIntermediateDirectory
- {
- get
- {
- if (this.TrackerLogDirectory != null)
- {
- return this.TrackerLogDirectory;
- }
- else
- {
- return string.Empty;
- }
- }
- }
-
- protected override string CommandTLogName
- {
- get
- {
- return "default.link.command.tlog";
- }
- }
-
- protected override string[] ReadTLogNames
- {
- get
- {
- return new string[]
- {
- "default.link.read.tlog"
- };
- }
- }
-
- protected override string[] WriteTLogNames
- {
- get
- {
- return new string[]
- {
- "default.link.write.tlog"
- };
- }
- }
-
- public string TrackerLogDirectory { get; set; }
- }
-
-
-}
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+using System.Resources;
+using System.Text.RegularExpressions;
+using System.Diagnostics;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.CPPTasks;
+using Microsoft.Build.Utilities;
+
+namespace NaCl.Build.CPPTasks
+{
+ public class NaClLib : TrackedVCToolTask
+ {
+ public bool BuildingInIDE { get; set; }
+
+ [Required]
+ public string LibrarianToolPath { get; set; }
+
+ [Required]
+ public string PropertiesFile { get; set; }
+
+ [Required]
+ public virtual string OutputFile { get; set; }
+
+ [Required]
+ public string OutputCommandLine { get; set; }
+
+ [Required]
+ public virtual ITaskItem[] Sources { get; set; }
+
+
+ public NaClLib()
+ : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
+ {
+ this.EnvironmentVariables = new string[] { "CYGWIN=nodosfilewarning", "LC_CTYPE=C" };
+ }
+
+ protected override string GenerateResponseFileCommands()
+ {
+ StringBuilder responseFileCmds = new StringBuilder(GCCUtilities.s_CommandLineLength);
+ responseFileCmds.Append("rcs ");
+ responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(OutputFile));
+
+ foreach (ITaskItem item in Sources)
+ {
+ responseFileCmds.Append(" ");
+ responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(item.ToString()));
+ }
+ return responseFileCmds.ToString();
+ }
+
+ protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
+ {
+ if (OutputCommandLine == "true")
+ {
+ Log.LogMessage(MessageImportance.High, pathToTool + " " + responseFileCommands);
+ }
+
+ return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
+ }
+
+
+
+ public virtual string PlatformToolset
+ {
+ get
+ {
+ return "GCC";
+ }
+ }
+
+ protected override bool MaintainCompositeRootingMarkers
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ protected override ITaskItem[] TrackedInputFiles
+ {
+ get
+ {
+ return Sources;
+ }
+ }
+
+
+ protected override Encoding ResponseFileEncoding
+ {
+ get
+ {
+ return Encoding.ASCII;
+ }
+ }
+
+ protected override string ToolName
+ {
+ get
+ {
+ return LibrarianToolPath;
+ }
+ }
+
+ protected override string TrackerIntermediateDirectory
+ {
+ get
+ {
+ if (this.TrackerLogDirectory != null)
+ {
+ return this.TrackerLogDirectory;
+ }
+ else
+ {
+ return string.Empty;
+ }
+ }
+ }
+
+ protected override string CommandTLogName
+ {
+ get
+ {
+ return "default.link.command.tlog";
+ }
+ }
+
+ protected override string[] ReadTLogNames
+ {
+ get
+ {
+ return new string[]
+ {
+ "default.link.read.tlog"
+ };
+ }
+ }
+
+ protected override string[] WriteTLogNames
+ {
+ get
+ {
+ return new string[]
+ {
+ "default.link.write.tlog"
+ };
+ }
+ }
+
+ public string TrackerLogDirectory { get; set; }
+ }
+
+
+}
diff --git a/NaCl.Build.CPPTasks/NaClLink.cs b/NaCl.Build.CPPTasks/NaClLink.cs
index a55543e..7a0ee54 100644
--- a/NaCl.Build.CPPTasks/NaClLink.cs
+++ b/NaCl.Build.CPPTasks/NaClLink.cs
@@ -1,195 +1,195 @@
-
-using System;
-using System.IO;
-using System.Resources;
-using System.Reflection;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.CPPTasks;
-
-
-namespace NaCl.Build.CPPTasks
-{
- public class NaClLink : TrackedVCToolTask
- {
- private XamlParser m_XamlParser;
-
- public bool BuildingInIDE { get; set; }
-
- [Required]
- public string OutputCommandLine { get; set; }
-
- [Required]
- public string NaClLinkerPath { get; set; }
-
- [Required]
- public virtual string OutputFile { get; set; }
-
- [Required]
- public string PropertiesFile { get; set; }
-
- [Required]
- public virtual ITaskItem[] Sources { get; set; }
-
- [Required]
- public string ConfigurationType { get; set; }
-
- public NaClLink()
- : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
- {
- this.EnvironmentVariables = new string[] { "CYGWIN=nodosfilewarning", "LC_CTYPE=C" };
- }
-
- protected override string CommandTLogName
- {
- get
- {
- return "default.link.command.tlog";
- }
- }
-
- protected override string[] ReadTLogNames
- {
- get
- {
- return new string[] {
- "default.link.read.tlog"
- };
- }
- }
-
- protected override string[] WriteTLogNames
- {
- get
- {
- return new string[] {
- "default.link.write.tlog"
- };
- }
- }
-
- protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
- {
- base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance);
- }
-
- protected override string GenerateResponseFileCommands()
- {
- StringBuilder responseFileCmds = new StringBuilder(GCCUtilities.s_CommandLineLength);
-
- foreach (ITaskItem sourceFile in Sources)
- {
- responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.GetMetadata("Identity")));
- responseFileCmds.Append(" ");
- }
-
- responseFileCmds.Append(m_XamlParser.Parse(Sources[0]));
-
- return responseFileCmds.ToString();
- }
-
- public override bool Execute()
- {
- bool returnResult = false;
-
- try
- {
- m_XamlParser = new XamlParser(PropertiesFile);
-
- returnResult = base.Execute();
- }
- finally
- {
-
- }
-
- return returnResult;
- }
-
- protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
- {
- if (OutputCommandLine == "true")
- {
- Log.LogMessage(MessageImportance.High, pathToTool + " " + responseFileCommands);
- }
-
- return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
- }
-
- protected override void PostProcessSwitchList()
- {
- //skip default behavior
- }
-
- protected override string GenerateFullPathToTool()
- {
- return this.ToolName;
- }
-
- protected override string TrackerIntermediateDirectory
- {
- get
- {
- if (this.TrackerLogDirectory != null)
- {
- return this.TrackerLogDirectory;
- }
-
- return string.Empty;
- }
- }
-
- protected override Encoding ResponseFileEncoding
- {
- get
- {
- return Encoding.ASCII;
- }
- }
-
- protected override ITaskItem[] TrackedInputFiles
- {
- get
- {
- return this.Sources;
- }
- }
-
- protected override bool MaintainCompositeRootingMarkers
- {
- get
- {
- return true;
- }
-
- }
-
- protected override string ToolName
- {
- get
- {
- return NaClLinkerPath;
- }
- }
-
- public override bool AttributeFileTracking
- {
- get
- {
- return true;
- }
- }
-
- public virtual string PlatformToolset
- {
- get
- {
- return "GCC";
- }
- set
- {}
- }
-
- public string TrackerLogDirectory { get; set; }
- }
-}
+
+using System;
+using System.IO;
+using System.Resources;
+using System.Reflection;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.CPPTasks;
+
+
+namespace NaCl.Build.CPPTasks
+{
+ public class NaClLink : TrackedVCToolTask
+ {
+ private XamlParser m_XamlParser;
+
+ public bool BuildingInIDE { get; set; }
+
+ [Required]
+ public string OutputCommandLine { get; set; }
+
+ [Required]
+ public string NaClLinkerPath { get; set; }
+
+ [Required]
+ public virtual string OutputFile { get; set; }
+
+ [Required]
+ public string PropertiesFile { get; set; }
+
+ [Required]
+ public virtual ITaskItem[] Sources { get; set; }
+
+ [Required]
+ public string ConfigurationType { get; set; }
+
+ public NaClLink()
+ : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
+ {
+ this.EnvironmentVariables = new string[] { "CYGWIN=nodosfilewarning", "LC_CTYPE=C" };
+ }
+
+ protected override string CommandTLogName
+ {
+ get
+ {
+ return "default.link.command.tlog";
+ }
+ }
+
+ protected override string[] ReadTLogNames
+ {
+ get
+ {
+ return new string[] {
+ "default.link.read.tlog"
+ };
+ }
+ }
+
+ protected override string[] WriteTLogNames
+ {
+ get
+ {
+ return new string[] {
+ "default.link.write.tlog"
+ };
+ }
+ }
+
+ protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
+ {
+ base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance);
+ }
+
+ protected override string GenerateResponseFileCommands()
+ {
+ StringBuilder responseFileCmds = new StringBuilder(GCCUtilities.s_CommandLineLength);
+
+ foreach (ITaskItem sourceFile in Sources)
+ {
+ responseFileCmds.Append(GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.GetMetadata("Identity")));
+ responseFileCmds.Append(" ");
+ }
+
+ responseFileCmds.Append(m_XamlParser.Parse(Sources[0]));
+
+ return responseFileCmds.ToString();
+ }
+
+ public override bool Execute()
+ {
+ bool returnResult = false;
+
+ try
+ {
+ m_XamlParser = new XamlParser(PropertiesFile);
+
+ returnResult = base.Execute();
+ }
+ finally
+ {
+
+ }
+
+ return returnResult;
+ }
+
+ protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
+ {
+ if (OutputCommandLine == "true")
+ {
+ Log.LogMessage(MessageImportance.High, pathToTool + " " + responseFileCommands);
+ }
+
+ return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
+ }
+
+ protected override void PostProcessSwitchList()
+ {
+ //skip default behavior
+ }
+
+ protected override string GenerateFullPathToTool()
+ {
+ return this.ToolName;
+ }
+
+ protected override string TrackerIntermediateDirectory
+ {
+ get
+ {
+ if (this.TrackerLogDirectory != null)
+ {
+ return this.TrackerLogDirectory;
+ }
+
+ return string.Empty;
+ }
+ }
+
+ protected override Encoding ResponseFileEncoding
+ {
+ get
+ {
+ return Encoding.ASCII;
+ }
+ }
+
+ protected override ITaskItem[] TrackedInputFiles
+ {
+ get
+ {
+ return this.Sources;
+ }
+ }
+
+ protected override bool MaintainCompositeRootingMarkers
+ {
+ get
+ {
+ return true;
+ }
+
+ }
+
+ protected override string ToolName
+ {
+ get
+ {
+ return NaClLinkerPath;
+ }
+ }
+
+ public override bool AttributeFileTracking
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public virtual string PlatformToolset
+ {
+ get
+ {
+ return "GCC";
+ }
+ set
+ {}
+ }
+
+ public string TrackerLogDirectory { get; set; }
+ }
+}
diff --git a/NaCl.Build.CPPTasks/Properties/AssemblyInfo.cs b/NaCl.Build.CPPTasks/Properties/AssemblyInfo.cs
index f248fdd..71a3fea 100644
--- a/NaCl.Build.CPPTasks/Properties/AssemblyInfo.cs
+++ b/NaCl.Build.CPPTasks/Properties/AssemblyInfo.cs
@@ -1,38 +1,38 @@
-//CONVERTED - ENTIRE FILE
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("NaCl.Build.CPPTasks")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Google Inc.")]
-[assembly: AssemblyProduct("NaCl.Build.CPPTasks")]
-[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("a17d894a-0fe8-46e4-8715-60f815bc103d")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+//CONVERTED - ENTIRE FILE
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("NaCl.Build.CPPTasks")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Google Inc.")]
+[assembly: AssemblyProduct("NaCl.Build.CPPTasks")]
+[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a17d894a-0fe8-46e4-8715-60f815bc103d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/NaCl.Build.CPPTasks/Properties/Resources.Designer.cs b/NaCl.Build.CPPTasks/Properties/Resources.Designer.cs
index 31cd155..c419c72 100644
--- a/NaCl.Build.CPPTasks/Properties/Resources.Designer.cs
+++ b/NaCl.Build.CPPTasks/Properties/Resources.Designer.cs
@@ -1,144 +1,144 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.269
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace NaCl.Build.CPPTasks.Properties {
- using System;
-
-
- /// <summary>
- /// A strongly-typed resource class, for looking up localized strings, etc.
- /// </summary>
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources() {
- }
-
- /// <summary>
- /// Returns the cached ResourceManager instance used by this class.
- /// </summary>
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", typeof(Resources).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- /// <summary>
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- /// </summary>
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to # This file is automatically generated by vs-nacl.
- ///# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
- ///#
- ///# This file must *NOT* be checked in Version Control Systems,
- ///# as it contains information specific to your local configuration.
- ///
- ///# location of the SDK. This is only used by Ant
- ///# For customization when using a Version Control System, please read the
- ///# header note.
- ///sdk.dir={SDKDIR}.
- /// </summary>
- internal static string localproperties_ant_file {
- get {
- return ResourceManager.GetString("localproperties_ant_file", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Tracking command:.
- /// </summary>
- internal static string Native_TrackingCommandMessage {
- get {
- return ResourceManager.GetString("Native_TrackingCommandMessage", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to MSB8016: Can not turn on Unicode output for "{0}". Some Unicode characters will be improperly displayed..
- /// </summary>
- internal static string TrackedVCToolTask_CreateUnicodeOutputPipeFailed {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.CreateUnicodeOutputPipeFailed", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Forcing rebuild of all source files due to a change in the command line since the last build..
- /// </summary>
- internal static string TrackedVCToolTask_RebuildingAllSourcesCommandLineChanged {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.RebuildingAllSourcesCommandLineChanged", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to MSB8014: Forcing a rebuild of all sources due to an error with the tracking logs. {0}.
- /// </summary>
- internal static string TrackedVCToolTask_RebuildingDueToInvalidTLog {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.RebuildingDueToInvalidTLog", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to MSB8015: Forcing a rebuild of all source files due to the contents of "{0}" being invalid..
- /// </summary>
- internal static string TrackedVCToolTask_RebuildingDueToInvalidTLogContents {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.RebuildingDueToInvalidTLogContents", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Forcing rebuild of all source files due to missing command tlog "{0}"..
- /// </summary>
- internal static string TrackedVCToolTask_RebuildingNoCommandTLog {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.RebuildingNoCommandTLog", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Forcing rebuild of source file "{0}" due to a change in the command line since the last build..
- /// </summary>
- internal static string TrackedVCToolTask_RebuildingSourceCommandLineChanged {
- get {
- return ResourceManager.GetString("TrackedVCToolTask.RebuildingSourceCommandLineChanged", resourceCulture);
- }
- }
- }
-}
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.269
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace NaCl.Build.CPPTasks.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to # This file is automatically generated by vs-nacl.
+ ///# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+ ///#
+ ///# This file must *NOT* be checked in Version Control Systems,
+ ///# as it contains information specific to your local configuration.
+ ///
+ ///# location of the SDK. This is only used by Ant
+ ///# For customization when using a Version Control System, please read the
+ ///# header note.
+ ///sdk.dir={SDKDIR}.
+ /// </summary>
+ internal static string localproperties_ant_file {
+ get {
+ return ResourceManager.GetString("localproperties_ant_file", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Tracking command:.
+ /// </summary>
+ internal static string Native_TrackingCommandMessage {
+ get {
+ return ResourceManager.GetString("Native_TrackingCommandMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to MSB8016: Can not turn on Unicode output for "{0}". Some Unicode characters will be improperly displayed..
+ /// </summary>
+ internal static string TrackedVCToolTask_CreateUnicodeOutputPipeFailed {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.CreateUnicodeOutputPipeFailed", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Forcing rebuild of all source files due to a change in the command line since the last build..
+ /// </summary>
+ internal static string TrackedVCToolTask_RebuildingAllSourcesCommandLineChanged {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.RebuildingAllSourcesCommandLineChanged", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to MSB8014: Forcing a rebuild of all sources due to an error with the tracking logs. {0}.
+ /// </summary>
+ internal static string TrackedVCToolTask_RebuildingDueToInvalidTLog {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.RebuildingDueToInvalidTLog", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to MSB8015: Forcing a rebuild of all source files due to the contents of "{0}" being invalid..
+ /// </summary>
+ internal static string TrackedVCToolTask_RebuildingDueToInvalidTLogContents {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.RebuildingDueToInvalidTLogContents", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Forcing rebuild of all source files due to missing command tlog "{0}"..
+ /// </summary>
+ internal static string TrackedVCToolTask_RebuildingNoCommandTLog {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.RebuildingNoCommandTLog", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Forcing rebuild of source file "{0}" due to a change in the command line since the last build..
+ /// </summary>
+ internal static string TrackedVCToolTask_RebuildingSourceCommandLineChanged {
+ get {
+ return ResourceManager.GetString("TrackedVCToolTask.RebuildingSourceCommandLineChanged", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/NaCl.Build.CPPTasks/XamlParser.cs b/NaCl.Build.CPPTasks/XamlParser.cs
index 099d4df..8acbc5f 100644
--- a/NaCl.Build.CPPTasks/XamlParser.cs
+++ b/NaCl.Build.CPPTasks/XamlParser.cs
@@ -1,152 +1,152 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Microsoft.Build.Framework;
-using System.Xaml;
-using Microsoft.Build.Framework.XamlTypes;
-using Microsoft.Build.Utilities;
-
-namespace NaCl.Build.CPPTasks
-{
- class XamlParser
- {
- public XamlParser(string path)
- {
- // load and store properties from xaml file
- m_parsedBuildRule = (Rule)XamlServices.Load(path);
-
- // NOTE:
- // There are MSBuild classes which support command line building,
- // argument switch encapsulation and more. Code within VCToolTask,
- // a hidden interface, uses some these classes to generate command line
- // switches given project settings. As the VCToolTask class is a hidden
- // class and the MSBuild documentation is very sparse, we are going
- // with a small custom solution. For reference see the
- // Microsoft.Build.Tasks.Xaml, Microsoft.Build.Framework.XamlTypes namespaces.
-
- // move the properties to a property name keyed dictionary for faster lookup
- ToolProperties = new Dictionary<string, PropertyWrapper>();
- ToolProperties = m_parsedBuildRule.Properties.ToDictionary(x => x.Name, x => (new PropertyWrapper(x.GetType(), x)));
-
- InitFunctionMap();
- }
-
- private void InitFunctionMap()
- {
- m_typeFunctionMap = new Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>>
- {
- { typeof(StringListProperty), GenerateArgumentStringList },
- { typeof(StringProperty), GenerateArgumentString },
- { typeof(IntProperty), GenerateArgumentString },
- { typeof(BoolProperty), GenerateArgumentBool },
- { typeof(EnumProperty), GenerateArgumentEnum }
- };
- }
-
- public string Parse(ITaskItem taskItem)
- {
- CommandLineBuilder builder = new CommandLineBuilder();
-
- foreach (string name in taskItem.MetadataNames)
- {
- string value = taskItem.GetMetadata(name);
- AppendArgumentForProperty(builder, name, value);
- }
-
- string result = builder.ToString();
- result = result.Replace('\\', '/'); // posix paths
- return result;
- }
-
- private string AppendArgumentForProperty(CommandLineBuilder builder, string name, string value)
- {
- PropertyWrapper current;
- ToolProperties.TryGetValue(name, out current);
- if (current != null && value.Length > 0)
- {
- // call appropriate function for type
- m_typeFunctionMap[current.PropertyType](builder, current.Property, value);
- }
- return string.Empty;
- }
-
- private void GenerateArgumentEnum(CommandLineBuilder builder, BaseProperty property, string value)
- {
- var result = ((EnumProperty)property).AdmissibleValues.Find(x => (x.Name == value));
- if (result != null)
- {
- builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, result.Switch);
- }
- }
-
- // helper for string-based properties
- private void AppendStringValue(CommandLineBuilder builder, BaseProperty property, string subtype, string value)
- {
- value = value.Trim();
-
- // could cache this SubType test off in property wrapper or somewhere if performance were an issue
- if (subtype == "file" || subtype == "folder")
- {
- builder.AppendSwitchIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value);
- }
- else
- {
- builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value);
- }
- }
-
- private void GenerateArgumentStringList(CommandLineBuilder builder, BaseProperty property, string value)
- {
- string [] arguments = value.Split(';');
-
- foreach (string argument in arguments)
- {
- if (argument.Length > 0)
- {
- StringListProperty casted = (StringListProperty)property;
- AppendStringValue(builder, property, casted.Subtype, argument);
- }
- }
- }
-
- private void GenerateArgumentString(CommandLineBuilder builder, BaseProperty property, string value)
- {
- // could cache this SubType test off in property wrapper or somewhere if performance were an issue
- StringProperty casted = (StringProperty)property;
- AppendStringValue(builder, property, casted.Subtype, value);
- }
-
- private void GenerateArgumentBool(CommandLineBuilder builder, BaseProperty property, string value)
- {
- if (value == "true")
- {
- builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, property.Switch);
- }
- else if (value == "false" && ((BoolProperty)property).ReverseSwitch != null)
- {
- builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, ((BoolProperty)property).ReverseSwitch);
- }
- }
-
- // to store off MSBuild property type and allow faster searching on them
- private class PropertyWrapper
- {
- public PropertyWrapper(Type newType, BaseProperty newProperty)
- {
- PropertyType = newType;
- Property = newProperty;
- }
- public Type PropertyType { get; set; }
- public BaseProperty Property { get; set; }
- } // class
-
- private Rule m_parsedBuildRule;
- private Dictionary<string, PropertyWrapper> ToolProperties { get; set; }
-
- // function mapping for easy property function calling
- private Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>> m_typeFunctionMap;
- } // XamlParser
-} // namespace NaCl.Build.CPPTasks
-
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Microsoft.Build.Framework;
+using System.Xaml;
+using Microsoft.Build.Framework.XamlTypes;
+using Microsoft.Build.Utilities;
+
+namespace NaCl.Build.CPPTasks
+{
+ class XamlParser
+ {
+ public XamlParser(string path)
+ {
+ // load and store properties from xaml file
+ m_parsedBuildRule = (Rule)XamlServices.Load(path);
+
+ // NOTE:
+ // There are MSBuild classes which support command line building,
+ // argument switch encapsulation and more. Code within VCToolTask,
+ // a hidden interface, uses some these classes to generate command line
+ // switches given project settings. As the VCToolTask class is a hidden
+ // class and the MSBuild documentation is very sparse, we are going
+ // with a small custom solution. For reference see the
+ // Microsoft.Build.Tasks.Xaml, Microsoft.Build.Framework.XamlTypes namespaces.
+
+ // move the properties to a property name keyed dictionary for faster lookup
+ ToolProperties = new Dictionary<string, PropertyWrapper>();
+ ToolProperties = m_parsedBuildRule.Properties.ToDictionary(x => x.Name, x => (new PropertyWrapper(x.GetType(), x)));
+
+ InitFunctionMap();
+ }
+
+ private void InitFunctionMap()
+ {
+ m_typeFunctionMap = new Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>>
+ {
+ { typeof(StringListProperty), GenerateArgumentStringList },
+ { typeof(StringProperty), GenerateArgumentString },
+ { typeof(IntProperty), GenerateArgumentString },
+ { typeof(BoolProperty), GenerateArgumentBool },
+ { typeof(EnumProperty), GenerateArgumentEnum }
+ };
+ }
+
+ public string Parse(ITaskItem taskItem)
+ {
+ CommandLineBuilder builder = new CommandLineBuilder();
+
+ foreach (string name in taskItem.MetadataNames)
+ {
+ string value = taskItem.GetMetadata(name);
+ AppendArgumentForProperty(builder, name, value);
+ }
+
+ string result = builder.ToString();
+ result = result.Replace('\\', '/'); // posix paths
+ return result;
+ }
+
+ private string AppendArgumentForProperty(CommandLineBuilder builder, string name, string value)
+ {
+ PropertyWrapper current;
+ ToolProperties.TryGetValue(name, out current);
+ if (current != null && value.Length > 0)
+ {
+ // call appropriate function for type
+ m_typeFunctionMap[current.PropertyType](builder, current.Property, value);
+ }
+ return string.Empty;
+ }
+
+ private void GenerateArgumentEnum(CommandLineBuilder builder, BaseProperty property, string value)
+ {
+ var result = ((EnumProperty)property).AdmissibleValues.Find(x => (x.Name == value));
+ if (result != null)
+ {
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, result.Switch);
+ }
+ }
+
+ // helper for string-based properties
+ private void AppendStringValue(CommandLineBuilder builder, BaseProperty property, string subtype, string value)
+ {
+ value = value.Trim();
+
+ // could cache this SubType test off in property wrapper or somewhere if performance were an issue
+ if (subtype == "file" || subtype == "folder")
+ {
+ builder.AppendSwitchIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value);
+ }
+ else
+ {
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value);
+ }
+ }
+
+ private void GenerateArgumentStringList(CommandLineBuilder builder, BaseProperty property, string value)
+ {
+ string [] arguments = value.Split(';');
+
+ foreach (string argument in arguments)
+ {
+ if (argument.Length > 0)
+ {
+ StringListProperty casted = (StringListProperty)property;
+ AppendStringValue(builder, property, casted.Subtype, argument);
+ }
+ }
+ }
+
+ private void GenerateArgumentString(CommandLineBuilder builder, BaseProperty property, string value)
+ {
+ // could cache this SubType test off in property wrapper or somewhere if performance were an issue
+ StringProperty casted = (StringProperty)property;
+ AppendStringValue(builder, property, casted.Subtype, value);
+ }
+
+ private void GenerateArgumentBool(CommandLineBuilder builder, BaseProperty property, string value)
+ {
+ if (value == "true")
+ {
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, property.Switch);
+ }
+ else if (value == "false" && ((BoolProperty)property).ReverseSwitch != null)
+ {
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, ((BoolProperty)property).ReverseSwitch);
+ }
+ }
+
+ // to store off MSBuild property type and allow faster searching on them
+ private class PropertyWrapper
+ {
+ public PropertyWrapper(Type newType, BaseProperty newProperty)
+ {
+ PropertyType = newType;
+ Property = newProperty;
+ }
+ public Type PropertyType { get; set; }
+ public BaseProperty Property { get; set; }
+ } // class
+
+ private Rule m_parsedBuildRule;
+ private Dictionary<string, PropertyWrapper> ToolProperties { get; set; }
+
+ // function mapping for easy property function calling
+ private Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>> m_typeFunctionMap;
+ } // XamlParser
+} // namespace NaCl.Build.CPPTasks
+
diff --git a/NativeClientVSAddIn/AssemblyInfo.cs b/NativeClientVSAddIn/AssemblyInfo.cs
index e67e254..76f0d73 100644
--- a/NativeClientVSAddIn/AssemblyInfo.cs
+++ b/NativeClientVSAddIn/AssemblyInfo.cs
@@ -1,31 +1,31 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Native Client Visual Studio Add-in")]
-[assembly: AssemblyDescription("An add-in for Visual Studio aiding Native Client development")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Google Inc.")]
-[assembly: AssemblyProduct("Native Client SDK Visual Studio Add-in")]
-[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Revision
-// Build Number
-//
-// You can specify all the value or you can default the Revision and
-// Build Numbers by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.*")]
-
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Native Client Visual Studio Add-in")]
+[assembly: AssemblyDescription("An add-in for Visual Studio aiding Native Client development")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Google Inc.")]
+[assembly: AssemblyProduct("Native Client SDK Visual Studio Add-in")]
+[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Revision
+// Build Number
+//
+// You can specify all the value or you can default the Revision and
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.*")]
+
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")]
\ No newline at end of file
diff --git a/NativeClientVSAddIn/PluginDebuggerBase.cs b/NativeClientVSAddIn/PluginDebuggerBase.cs
index 0d0e64b..71c23a0 100644
--- a/NativeClientVSAddIn/PluginDebuggerBase.cs
+++ b/NativeClientVSAddIn/PluginDebuggerBase.cs
@@ -1,239 +1,239 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
- using System.Collections.Generic;
- using System.Windows.Forms;
-
- using EnvDTE;
- using EnvDTE80;
-
- /// <summary>
- /// This is a base class for encapsulating functionality related to attaching a debugger
- /// to a nacl/pepper plug-in. This base class mostly contains functionality related to finding
- /// the plug-in.
- /// </summary>
- public class PluginDebuggerBase : IDisposable
- {
- /// <summary>
- /// This is the initial number of milliseconds to wait between
- /// checking for plug-in processes to attach the debugger to.
- /// </summary>
- private const int InitialPluginCheckFrequency = 1000;
-
- /// <summary>
- /// After a plug-in has been found, we slow the frequency of checking
- /// for new ones. This value is in milliseconds.
- /// </summary>
- private const int RelaxedPluginCheckFrequency = 5000;
-
- /// <summary>
- /// Timer object that periodically calls a function to look for the plug-in process to debug.
- /// </summary>
- private Timer pluginFinderTimer_;
-
- /// <summary>
- /// List of process IDs which we should not attempt to attach the debugger to. Mainly this
- /// list contains process IDs of processes we have already attached to.
- /// </summary>
- private List<uint> pluginFinderForbiddenPids_;
-
- /// <summary>
- /// Process searcher class which allows us to query the system for running processes.
- /// </summary>
- private ProcessSearcher processSearcher_;
-
- /// <summary>
- /// The main process of chrome that was started by Visual Studio during debugging.
- /// </summary>
- private System.Diagnostics.Process debuggedChromeMainProcess_;
-
- /// <summary>
- /// Constructs the PluginDebuggerHelper.
- /// </summary>
- /// <param name="dte">Automation object from Visual Studio.</param>
- /// <param name="properties">PropertyManager set to a valid project/platform.</param>
- protected PluginDebuggerBase(DTE2 dte, PropertyManager properties)
- {
- if (dte == null)
- {
- throw new ArgumentNullException("dte");
- }
-
- if (properties == null)
- {
- throw new ArgumentNullException("properties");
- }
-
- Dte = dte;
-
- // Every second, check for a new instance of the plug-in to attach to.
- // Note that although the timer itself runs on a separate thread, the event
- // is fired from the main UI thread during message processing, thus we do not
- // need to worry about threading issues.
- pluginFinderTimer_ = new Timer();
- pluginFinderTimer_.Tick += new EventHandler(FindAndAttachToPlugin);
- pluginFinderForbiddenPids_ = new List<uint>();
- processSearcher_ = new ProcessSearcher();
-
- pluginFinderTimer_.Interval = InitialPluginCheckFrequency;
- pluginFinderTimer_.Start();
- }
-
- /// <summary>
- /// Finalizer. Should clean up unmanaged resources. Should not be overriden in derived classes.
- /// </summary>
- ~PluginDebuggerBase()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// An event indicating a target plug-in was found on the system.
- /// </summary>
- public event EventHandler<PluginFoundEventArgs> PluginFoundEvent;
-
- /// <summary>
- /// Gets or sets a value indicating whether this object has been disposed of already.
- /// </summary>
- protected bool Disposed { get; set; }
-
- /// <summary>
- /// Gets or sets the main visual studio object.
- /// </summary>
- protected DTE2 Dte { get; set; }
-
- /// <summary>
- /// Disposes the object when called by user code (not directly by garbage collector).
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// This is called periodically by the Visual Studio UI thread to look for our plug-in process
- /// and attach the debugger to it. The call is triggered by the pluginFinderTimer_ object.
- /// </summary>
- /// <param name="unused">The parameter is not used.</param>
- /// <param name="unused1">The parameter is not used.</param>
- public void FindAndAttachToPlugin(object unused, EventArgs unused1)
- {
- StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase;
-
- // This function is called by the main Visual Studio event loop and we may have put the event
- // on the queue just before disposing it meaning this could be called after we've disposed.
- if (Disposed)
- {
- return;
- }
-
- // Set the main chrome process that was started by visual studio. If it's not chrome
- // or not found then we have no business attaching to any plug-ins so return.
- if (debuggedChromeMainProcess_ == null)
- {
- foreach (Process proc in Dte.Debugger.DebuggedProcesses)
- {
- if (proc.Name.EndsWith(Strings.ChromeProcessName, ignoreCase))
- {
- debuggedChromeMainProcess_ = System.Diagnostics.Process.GetProcessById(proc.ProcessID);
- break;
- }
- }
-
- return;
- }
-
- if (debuggedChromeMainProcess_.HasExited)
- {
- // Might happen if we're shutting down debugging.
- return;
- }
-
- // Get the list of all descendants of the main chrome process.
- uint mainChromeProcId = (uint)debuggedChromeMainProcess_.Id;
- List<ProcessInfo> chromeDescendants = processSearcher_.GetDescendants(mainChromeProcId);
- if (chromeDescendants.Count == 0)
- {
- // Might happen if we're shutting down debugging.
- return;
- }
-
- ProcessInfo mainProcInfo = chromeDescendants.Find(p => p.ID == mainChromeProcId);
- if (mainProcInfo == null)
- {
- // Might happen if we're shutting down debugging.
- return;
- }
-
- string mainChromeFlags = mainProcInfo.CommandLine;
-
- // From the list of descendants, find the plug-in by it's command line arguments and
- // process name as well as not being attached to already.
- List<ProcessInfo> plugins = chromeDescendants.FindAll(p =>
- IsPluginProcess(p, mainChromeFlags) && !pluginFinderForbiddenPids_.Contains(p.ID));
-
- // Attach to all plug-ins that we found.
- foreach (ProcessInfo process in plugins)
- {
- // If we are attaching to a plug-in, add it to the forbidden list to ensure we
- // don't try to attach again later.
- pluginFinderForbiddenPids_.Add(process.ID);
- PluginFoundEvent.Invoke(this, new PluginFoundEventArgs(process.ID));
-
- // Slow down the frequency of checks for new plugins.
- pluginFinderTimer_.Interval = RelaxedPluginCheckFrequency;
- }
- }
-
- /// <summary>
- /// Disposes the object. If disposing is false then this has been called by garbage collection,
- /// and we shouldn't reference managed objects.
- /// </summary>
- /// <param name="disposing">True if user call to Dispose, false if garbase collection.</param>
- protected virtual void Dispose(bool disposing)
- {
- if (!Disposed && disposing)
- {
- pluginFinderTimer_.Stop();
- }
-
- Disposed = true;
- }
-
- /// <summary>
- /// Called to check if a process is a valid plugin to attach to.
- /// </summary>
- /// <param name="proc">Contains information about the process in question.</param>
- /// <param name="mainChromeFlags">Flags on the main Chrome process.</param>
- /// <returns>True if we should attach to the process.</returns>
- protected virtual bool IsPluginProcess(ProcessInfo proc, string mainChromeFlags)
- {
- throw new InvalidOperationException();
- }
-
- /// <summary>
- /// The event arguments when a plug-in is found.
- /// </summary>
- public class PluginFoundEventArgs : EventArgs
- {
- /// <summary>
- /// Construct the PluginFoundEventArgs.
- /// </summary>
- /// <param name="pid">Process ID of the found plug-in.</param>
- public PluginFoundEventArgs(uint pid)
- {
- this.ProcessID = pid;
- }
-
- /// <summary>
- /// Gets or sets process ID of the found plug-in.
- /// </summary>
- public uint ProcessID { get; set; }
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Windows.Forms;
+
+ using EnvDTE;
+ using EnvDTE80;
+
+ /// <summary>
+ /// This is a base class for encapsulating functionality related to attaching a debugger
+ /// to a nacl/pepper plug-in. This base class mostly contains functionality related to finding
+ /// the plug-in.
+ /// </summary>
+ public class PluginDebuggerBase : IDisposable
+ {
+ /// <summary>
+ /// This is the initial number of milliseconds to wait between
+ /// checking for plug-in processes to attach the debugger to.
+ /// </summary>
+ private const int InitialPluginCheckFrequency = 1000;
+
+ /// <summary>
+ /// After a plug-in has been found, we slow the frequency of checking
+ /// for new ones. This value is in milliseconds.
+ /// </summary>
+ private const int RelaxedPluginCheckFrequency = 5000;
+
+ /// <summary>
+ /// Timer object that periodically calls a function to look for the plug-in process to debug.
+ /// </summary>
+ private Timer pluginFinderTimer_;
+
+ /// <summary>
+ /// List of process IDs which we should not attempt to attach the debugger to. Mainly this
+ /// list contains process IDs of processes we have already attached to.
+ /// </summary>
+ private List<uint> pluginFinderForbiddenPids_;
+
+ /// <summary>
+ /// Process searcher class which allows us to query the system for running processes.
+ /// </summary>
+ private ProcessSearcher processSearcher_;
+
+ /// <summary>
+ /// The main process of chrome that was started by Visual Studio during debugging.
+ /// </summary>
+ private System.Diagnostics.Process debuggedChromeMainProcess_;
+
+ /// <summary>
+ /// Constructs the PluginDebuggerHelper.
+ /// </summary>
+ /// <param name="dte">Automation object from Visual Studio.</param>
+ /// <param name="properties">PropertyManager set to a valid project/platform.</param>
+ protected PluginDebuggerBase(DTE2 dte, PropertyManager properties)
+ {
+ if (dte == null)
+ {
+ throw new ArgumentNullException("dte");
+ }
+
+ if (properties == null)
+ {
+ throw new ArgumentNullException("properties");
+ }
+
+ Dte = dte;
+
+ // Every second, check for a new instance of the plug-in to attach to.
+ // Note that although the timer itself runs on a separate thread, the event
+ // is fired from the main UI thread during message processing, thus we do not
+ // need to worry about threading issues.
+ pluginFinderTimer_ = new Timer();
+ pluginFinderTimer_.Tick += new EventHandler(FindAndAttachToPlugin);
+ pluginFinderForbiddenPids_ = new List<uint>();
+ processSearcher_ = new ProcessSearcher();
+
+ pluginFinderTimer_.Interval = InitialPluginCheckFrequency;
+ pluginFinderTimer_.Start();
+ }
+
+ /// <summary>
+ /// Finalizer. Should clean up unmanaged resources. Should not be overriden in derived classes.
+ /// </summary>
+ ~PluginDebuggerBase()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// An event indicating a target plug-in was found on the system.
+ /// </summary>
+ public event EventHandler<PluginFoundEventArgs> PluginFoundEvent;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this object has been disposed of already.
+ /// </summary>
+ protected bool Disposed { get; set; }
+
+ /// <summary>
+ /// Gets or sets the main visual studio object.
+ /// </summary>
+ protected DTE2 Dte { get; set; }
+
+ /// <summary>
+ /// Disposes the object when called by user code (not directly by garbage collector).
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// This is called periodically by the Visual Studio UI thread to look for our plug-in process
+ /// and attach the debugger to it. The call is triggered by the pluginFinderTimer_ object.
+ /// </summary>
+ /// <param name="unused">The parameter is not used.</param>
+ /// <param name="unused1">The parameter is not used.</param>
+ public void FindAndAttachToPlugin(object unused, EventArgs unused1)
+ {
+ StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase;
+
+ // This function is called by the main Visual Studio event loop and we may have put the event
+ // on the queue just before disposing it meaning this could be called after we've disposed.
+ if (Disposed)
+ {
+ return;
+ }
+
+ // Set the main chrome process that was started by visual studio. If it's not chrome
+ // or not found then we have no business attaching to any plug-ins so return.
+ if (debuggedChromeMainProcess_ == null)
+ {
+ foreach (Process proc in Dte.Debugger.DebuggedProcesses)
+ {
+ if (proc.Name.EndsWith(Strings.ChromeProcessName, ignoreCase))
+ {
+ debuggedChromeMainProcess_ = System.Diagnostics.Process.GetProcessById(proc.ProcessID);
+ break;
+ }
+ }
+
+ return;
+ }
+
+ if (debuggedChromeMainProcess_.HasExited)
+ {
+ // Might happen if we're shutting down debugging.
+ return;
+ }
+
+ // Get the list of all descendants of the main chrome process.
+ uint mainChromeProcId = (uint)debuggedChromeMainProcess_.Id;
+ List<ProcessInfo> chromeDescendants = processSearcher_.GetDescendants(mainChromeProcId);
+ if (chromeDescendants.Count == 0)
+ {
+ // Might happen if we're shutting down debugging.
+ return;
+ }
+
+ ProcessInfo mainProcInfo = chromeDescendants.Find(p => p.ID == mainChromeProcId);
+ if (mainProcInfo == null)
+ {
+ // Might happen if we're shutting down debugging.
+ return;
+ }
+
+ string mainChromeFlags = mainProcInfo.CommandLine;
+
+ // From the list of descendants, find the plug-in by it's command line arguments and
+ // process name as well as not being attached to already.
+ List<ProcessInfo> plugins = chromeDescendants.FindAll(p =>
+ IsPluginProcess(p, mainChromeFlags) && !pluginFinderForbiddenPids_.Contains(p.ID));
+
+ // Attach to all plug-ins that we found.
+ foreach (ProcessInfo process in plugins)
+ {
+ // If we are attaching to a plug-in, add it to the forbidden list to ensure we
+ // don't try to attach again later.
+ pluginFinderForbiddenPids_.Add(process.ID);
+ PluginFoundEvent.Invoke(this, new PluginFoundEventArgs(process.ID));
+
+ // Slow down the frequency of checks for new plugins.
+ pluginFinderTimer_.Interval = RelaxedPluginCheckFrequency;
+ }
+ }
+
+ /// <summary>
+ /// Disposes the object. If disposing is false then this has been called by garbage collection,
+ /// and we shouldn't reference managed objects.
+ /// </summary>
+ /// <param name="disposing">True if user call to Dispose, false if garbase collection.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!Disposed && disposing)
+ {
+ pluginFinderTimer_.Stop();
+ }
+
+ Disposed = true;
+ }
+
+ /// <summary>
+ /// Called to check if a process is a valid plugin to attach to.
+ /// </summary>
+ /// <param name="proc">Contains information about the process in question.</param>
+ /// <param name="mainChromeFlags">Flags on the main Chrome process.</param>
+ /// <returns>True if we should attach to the process.</returns>
+ protected virtual bool IsPluginProcess(ProcessInfo proc, string mainChromeFlags)
+ {
+ throw new InvalidOperationException();
+ }
+
+ /// <summary>
+ /// The event arguments when a plug-in is found.
+ /// </summary>
+ public class PluginFoundEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Construct the PluginFoundEventArgs.
+ /// </summary>
+ /// <param name="pid">Process ID of the found plug-in.</param>
+ public PluginFoundEventArgs(uint pid)
+ {
+ this.ProcessID = pid;
+ }
+
+ /// <summary>
+ /// Gets or sets process ID of the found plug-in.
+ /// </summary>
+ public uint ProcessID { get; set; }
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/PluginDebuggerVS.cs b/NativeClientVSAddIn/PluginDebuggerVS.cs
index 2ad73e8..be2feb5 100644
--- a/NativeClientVSAddIn/PluginDebuggerVS.cs
+++ b/NativeClientVSAddIn/PluginDebuggerVS.cs
@@ -1,66 +1,66 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
-
- using EnvDTE80;
-
- /// <summary>
- /// This class handles the details of finding a pepper plugin and attaching to it.
- /// </summary>
- public class PluginDebuggerVS : PluginDebuggerBase
- {
- /// <summary>
- /// Path to the actual plug-in assembly.
- /// </summary>
- private string pluginAssembly_;
-
- /// <summary>
- /// Constructs the PluginDebuggerHelper.
- /// </summary>
- /// <param name="dte">Automation object from Visual Studio.</param>
- /// <param name="properties">PropertyManager pointing to a valid project/platform.</param>
- public PluginDebuggerVS(DTE2 dte, PropertyManager properties)
- : base(dte, properties)
- {
- pluginAssembly_ = properties.PluginAssembly;
- PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(Attach);
- }
-
- /// <summary>
- /// Called to check if a process is a valid pepper plugin to attach to.
- /// </summary>
- /// <param name="proc">Contains information about the process in question.</param>
- /// <param name="mainChromeFlags">Flags on the main Chrome process.</param>
- /// <returns>True if we should attach to the process.</returns>
- protected override bool IsPluginProcess(ProcessInfo proc, string mainChromeFlags)
- {
- StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase;
- string identifierFlagTarget =
- string.Format(Strings.PepperProcessPluginFlagFormat, pluginAssembly_);
- return proc.Name.Equals(Strings.ChromeProcessName, ignoreCase) &&
- proc.CommandLine.Contains(Strings.ChromeRendererFlag, ignoreCase) &&
- proc.CommandLine.Contains(identifierFlagTarget, ignoreCase);
- }
-
- /// <summary>
- /// Attaches the Visual Studio debugger to the given process ID.
- /// </summary>
- /// <param name="src">The parameter is not used.</param>
- /// <param name="args">Contains the process ID to attach to.</param>
- private void Attach(object src, PluginFoundEventArgs args)
- {
- foreach (EnvDTE.Process proc in Dte.Debugger.LocalProcesses)
- {
- if (proc.ProcessID == args.ProcessID)
- {
- proc.Attach();
- break;
- }
- }
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+
+ using EnvDTE80;
+
+ /// <summary>
+ /// This class handles the details of finding a pepper plugin and attaching to it.
+ /// </summary>
+ public class PluginDebuggerVS : PluginDebuggerBase
+ {
+ /// <summary>
+ /// Path to the actual plug-in assembly.
+ /// </summary>
+ private string pluginAssembly_;
+
+ /// <summary>
+ /// Constructs the PluginDebuggerHelper.
+ /// </summary>
+ /// <param name="dte">Automation object from Visual Studio.</param>
+ /// <param name="properties">PropertyManager pointing to a valid project/platform.</param>
+ public PluginDebuggerVS(DTE2 dte, PropertyManager properties)
+ : base(dte, properties)
+ {
+ pluginAssembly_ = properties.PluginAssembly;
+ PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(Attach);
+ }
+
+ /// <summary>
+ /// Called to check if a process is a valid pepper plugin to attach to.
+ /// </summary>
+ /// <param name="proc">Contains information about the process in question.</param>
+ /// <param name="mainChromeFlags">Flags on the main Chrome process.</param>
+ /// <returns>True if we should attach to the process.</returns>
+ protected override bool IsPluginProcess(ProcessInfo proc, string mainChromeFlags)
+ {
+ StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase;
+ string identifierFlagTarget =
+ string.Format(Strings.PepperProcessPluginFlagFormat, pluginAssembly_);
+ return proc.Name.Equals(Strings.ChromeProcessName, ignoreCase) &&
+ proc.CommandLine.Contains(Strings.ChromeRendererFlag, ignoreCase) &&
+ proc.CommandLine.Contains(identifierFlagTarget, ignoreCase);
+ }
+
+ /// <summary>
+ /// Attaches the Visual Studio debugger to the given process ID.
+ /// </summary>
+ /// <param name="src">The parameter is not used.</param>
+ /// <param name="args">Contains the process ID to attach to.</param>
+ private void Attach(object src, PluginFoundEventArgs args)
+ {
+ foreach (EnvDTE.Process proc in Dte.Debugger.LocalProcesses)
+ {
+ if (proc.ProcessID == args.ProcessID)
+ {
+ proc.Attach();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/ProcessInfo.cs b/NativeClientVSAddIn/ProcessInfo.cs
index 118b5b4..ca5333a 100644
--- a/NativeClientVSAddIn/ProcessInfo.cs
+++ b/NativeClientVSAddIn/ProcessInfo.cs
@@ -1,90 +1,90 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
- using System.Globalization;
- using System.Management;
-
- /// <summary>
- /// Holds information about a process for a ProcessSearcher.
- /// </summary>
- public class ProcessInfo
- {
- /// <summary>
- /// Constructs a process entry.
- /// </summary>
- /// <param name="id">Process ID.</param>
- /// <param name="parentId">Process ID of the parent process.</param>
- /// <param name="creationDate">
- /// String date in format 'yyyyMMddHHmmss.ffffff', or if empty then current time used.
- /// </param>
- /// <param name="commandLine">Command line arguments to the process.</param>
- /// <param name="name">Process name.</param>
- public ProcessInfo(uint id, uint parentId, string creationDate, string commandLine, string name)
- {
- if (string.IsNullOrEmpty(creationDate))
- {
- // If creationDate string is empty, then use the current timestamp.
- CreationDate = DateTime.UtcNow;
- }
- else
- {
- // Example creationDate: "20120622150149.843021-420".
- CreationDate = DateTime.ParseExact(
- creationDate.Substring(0, 21),
- "yyyyMMddHHmmss.ffffff",
- CultureInfo.InvariantCulture);
- long timeZoneMinutes = long.Parse(creationDate.Substring(21));
- CreationDate = CreationDate.AddMinutes(-timeZoneMinutes);
- }
-
- ID = id;
- ParentID = parentId;
- CommandLine = commandLine;
- Name = name;
- }
-
- /// <summary>
- /// Gets or sets Process ID of the represented process.
- /// </summary>
- public uint ID { get; set; }
-
- /// <summary>
- /// Gets or sets Process ID of the parent process.
- /// </summary>
- public uint ParentID { get; set; }
-
- /// <summary>
- /// Gets or sets DateTime of the process creation.
- /// </summary>
- public DateTime CreationDate { get; set; }
-
- /// <summary>
- /// Gets or sets Command line arguments to the process.
- /// </summary>
- public string CommandLine { get; set; }
-
- /// <summary>
- /// Gets or sets Name of the process.
- /// </summary>
- public string Name { get; set; }
-
- /// <summary>
- /// Casts from a management object that is a Win32_Process underlying type to a ProcessInfo.
- /// </summary>
- /// <param name="from">A management object that is Win32_Process underneath.</param>
- /// <returns>A ProcessInfo object.</returns>
- public static explicit operator ProcessInfo(ManagementObject from)
- {
- return new ProcessInfo(
- id: (uint)from["ProcessID"],
- parentId: (uint)from["ParentProcessID"],
- creationDate: from["CreationDate"] as string,
- commandLine: from["CommandLine"] as string,
- name: from["Name"] as string);
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+ using System.Globalization;
+ using System.Management;
+
+ /// <summary>
+ /// Holds information about a process for a ProcessSearcher.
+ /// </summary>
+ public class ProcessInfo
+ {
+ /// <summary>
+ /// Constructs a process entry.
+ /// </summary>
+ /// <param name="id">Process ID.</param>
+ /// <param name="parentId">Process ID of the parent process.</param>
+ /// <param name="creationDate">
+ /// String date in format 'yyyyMMddHHmmss.ffffff', or if empty then current time used.
+ /// </param>
+ /// <param name="commandLine">Command line arguments to the process.</param>
+ /// <param name="name">Process name.</param>
+ public ProcessInfo(uint id, uint parentId, string creationDate, string commandLine, string name)
+ {
+ if (string.IsNullOrEmpty(creationDate))
+ {
+ // If creationDate string is empty, then use the current timestamp.
+ CreationDate = DateTime.UtcNow;
+ }
+ else
+ {
+ // Example creationDate: "20120622150149.843021-420".
+ CreationDate = DateTime.ParseExact(
+ creationDate.Substring(0, 21),
+ "yyyyMMddHHmmss.ffffff",
+ CultureInfo.InvariantCulture);
+ long timeZoneMinutes = long.Parse(creationDate.Substring(21));
+ CreationDate = CreationDate.AddMinutes(-timeZoneMinutes);
+ }
+
+ ID = id;
+ ParentID = parentId;
+ CommandLine = commandLine;
+ Name = name;
+ }
+
+ /// <summary>
+ /// Gets or sets Process ID of the represented process.
+ /// </summary>
+ public uint ID { get; set; }
+
+ /// <summary>
+ /// Gets or sets Process ID of the parent process.
+ /// </summary>
+ public uint ParentID { get; set; }
+
+ /// <summary>
+ /// Gets or sets DateTime of the process creation.
+ /// </summary>
+ public DateTime CreationDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets Command line arguments to the process.
+ /// </summary>
+ public string CommandLine { get; set; }
+
+ /// <summary>
+ /// Gets or sets Name of the process.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Casts from a management object that is a Win32_Process underlying type to a ProcessInfo.
+ /// </summary>
+ /// <param name="from">A management object that is Win32_Process underneath.</param>
+ /// <returns>A ProcessInfo object.</returns>
+ public static explicit operator ProcessInfo(ManagementObject from)
+ {
+ return new ProcessInfo(
+ id: (uint)from["ProcessID"],
+ parentId: (uint)from["ParentProcessID"],
+ creationDate: from["CreationDate"] as string,
+ commandLine: from["CommandLine"] as string,
+ name: from["Name"] as string);
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/ProcessSearcher.cs b/NativeClientVSAddIn/ProcessSearcher.cs
index ceb3b0d..3657553 100644
--- a/NativeClientVSAddIn/ProcessSearcher.cs
+++ b/NativeClientVSAddIn/ProcessSearcher.cs
@@ -1,96 +1,96 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Management;
-
- /// <summary>
- /// Queries the system for the list of running processes.
- /// </summary>
- public class ProcessSearcher
- {
- /// <summary>
- /// Returns results of a process search subject to given constraints.
- /// </summary>
- /// <param name="constraints">
- /// A function taking a ProcessInfo object and returning true if the
- /// ProcessInfo object satisfies the constraints.
- /// </param>
- /// <returns>List of matching processes.</returns>
- public List<ProcessInfo> GetResults(Func<ProcessInfo, bool> constraints)
- {
- return GetSystemProcesses().Where(constraints).ToList();
- }
-
- /// <summary>
- /// Searches the system for all processes of a given name.
- /// </summary>
- /// <param name="name">Name to search for.</param>
- /// <returns>List of matching processes.</returns>
- public List<ProcessInfo> GetResultsByName(string name)
- {
- return GetResults(p => name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
- }
-
- /// <summary>
- /// Searches the system for all processes of a given process ID.
- /// </summary>
- /// <param name="procID">ID to search for.</param>
- /// <returns>List of matching processes.</returns>
- public List<ProcessInfo> GetResultsByID(uint procID)
- {
- return GetResults(p => procID == p.ID);
- }
-
- /// <summary>
- /// Returns a list of all descendant processes of a process.
- /// </summary>
- /// <param name="root">Process ID of the process to get all descendants from.</param>
- /// <returns>All descendants of the given root process.</returns>
- public List<ProcessInfo> GetDescendants(uint root)
- {
- List<ProcessInfo> processes = GetSystemProcesses();
- HashSet<ProcessInfo> descendants = new HashSet<ProcessInfo>();
- descendants.UnionWith(processes.Where(p => p.ID == root));
- int lastCount = 0;
- while (descendants.Count > lastCount)
- {
- lastCount = descendants.Count;
-
- // Add any processes who have a parent that is in the descendant list already.
- // Note we check the creation date to prevent cycles caused by recycled process IDs.
- descendants.UnionWith(processes.Where(p => descendants.Any(
- parent => parent.ID == p.ParentID && parent.CreationDate <= p.CreationDate)));
- }
-
- return descendants.ToList();
- }
-
- /// <summary>
- /// Queries the system for the full list of processes.
- /// </summary>
- /// <returns>List of processes on the system.</returns>
- protected virtual List<ProcessInfo> GetSystemProcesses()
- {
- var processList = new List<ProcessInfo>();
- string query = "select * from Win32_Process";
- using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
- {
- using (ManagementObjectCollection results = searcher.Get())
- {
- foreach (ManagementObject process in results)
- {
- processList.Add((ProcessInfo)process);
- }
- }
- }
-
- return processList;
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Management;
+
+ /// <summary>
+ /// Queries the system for the list of running processes.
+ /// </summary>
+ public class ProcessSearcher
+ {
+ /// <summary>
+ /// Returns results of a process search subject to given constraints.
+ /// </summary>
+ /// <param name="constraints">
+ /// A function taking a ProcessInfo object and returning true if the
+ /// ProcessInfo object satisfies the constraints.
+ /// </param>
+ /// <returns>List of matching processes.</returns>
+ public List<ProcessInfo> GetResults(Func<ProcessInfo, bool> constraints)
+ {
+ return GetSystemProcesses().Where(constraints).ToList();
+ }
+
+ /// <summary>
+ /// Searches the system for all processes of a given name.
+ /// </summary>
+ /// <param name="name">Name to search for.</param>
+ /// <returns>List of matching processes.</returns>
+ public List<ProcessInfo> GetResultsByName(string name)
+ {
+ return GetResults(p => name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
+ }
+
+ /// <summary>
+ /// Searches the system for all processes of a given process ID.
+ /// </summary>
+ /// <param name="procID">ID to search for.</param>
+ /// <returns>List of matching processes.</returns>
+ public List<ProcessInfo> GetResultsByID(uint procID)
+ {
+ return GetResults(p => procID == p.ID);
+ }
+
+ /// <summary>
+ /// Returns a list of all descendant processes of a process.
+ /// </summary>
+ /// <param name="root">Process ID of the process to get all descendants from.</param>
+ /// <returns>All descendants of the given root process.</returns>
+ public List<ProcessInfo> GetDescendants(uint root)
+ {
+ List<ProcessInfo> processes = GetSystemProcesses();
+ HashSet<ProcessInfo> descendants = new HashSet<ProcessInfo>();
+ descendants.UnionWith(processes.Where(p => p.ID == root));
+ int lastCount = 0;
+ while (descendants.Count > lastCount)
+ {
+ lastCount = descendants.Count;
+
+ // Add any processes who have a parent that is in the descendant list already.
+ // Note we check the creation date to prevent cycles caused by recycled process IDs.
+ descendants.UnionWith(processes.Where(p => descendants.Any(
+ parent => parent.ID == p.ParentID && parent.CreationDate <= p.CreationDate)));
+ }
+
+ return descendants.ToList();
+ }
+
+ /// <summary>
+ /// Queries the system for the full list of processes.
+ /// </summary>
+ /// <returns>List of processes on the system.</returns>
+ protected virtual List<ProcessInfo> GetSystemProcesses()
+ {
+ var processList = new List<ProcessInfo>();
+ string query = "select * from Win32_Process";
+ using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
+ {
+ using (ManagementObjectCollection results = searcher.Get())
+ {
+ foreach (ManagementObject process in results)
+ {
+ processList.Add((ProcessInfo)process);
+ }
+ }
+ }
+
+ return processList;
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/Strings.Designer.cs b/NativeClientVSAddIn/Strings.Designer.cs
index f6ba255..26f5a52 100644
--- a/NativeClientVSAddIn/Strings.Designer.cs
+++ b/NativeClientVSAddIn/Strings.Designer.cs
@@ -1,234 +1,234 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.269
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace NativeClientVSAddIn {
- using System;
-
-
- /// <summary>
- /// A strongly-typed resource class, for looking up localized strings, etc.
- /// </summary>
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Strings {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Strings() {
- }
-
- /// <summary>
- /// Returns the cached ResourceManager instance used by this class.
- /// </summary>
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NativeClientVSAddIn.Strings", typeof(Strings).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- /// <summary>
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- /// </summary>
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Native Client Visual Studio Add-In.
- /// </summary>
- internal static string AddInName {
- get {
- return ResourceManager.GetString("AddInName", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to CHROME_PATH.
- /// </summary>
- internal static string ChromePathEnvironmentVariable {
- get {
- return ResourceManager.GetString("ChromePathEnvironmentVariable", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to chrome.exe.
- /// </summary>
- internal static string ChromeProcessName {
- get {
- return ResourceManager.GetString("ChromeProcessName", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to --type=renderer.
- /// </summary>
- internal static string ChromeRendererFlag {
- get {
- return ResourceManager.GetString("ChromeRendererFlag", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Warning: Multiple start-up projects not supported. Web server will only be run from first project directory.
- /// </summary>
- internal static string MultiStartProjectWarning {
- get {
- return ResourceManager.GetString("MultiStartProjectWarning", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to --enable-nacl-debug.
- /// </summary>
- internal static string NaClDebugFlag {
- get {
- return ResourceManager.GetString("NaClDebugFlag", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to --type=nacl-loader.
- /// </summary>
- internal static string NaClLoaderFlag {
- get {
- return ResourceManager.GetString("NaClLoaderFlag", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to NaCl.
- /// </summary>
- internal static string NaClPlatformName {
- get {
- return ResourceManager.GetString("NaClPlatformName", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to nacl64.exe.
- /// </summary>
- internal static string NaClProcessName {
- get {
- return ResourceManager.GetString("NaClProcessName", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to PPAPI.
- /// </summary>
- internal static string PepperPlatformName {
- get {
- return ResourceManager.GetString("PepperPlatformName", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to --register-pepper-plugins="{0};application/x-nacl".
- /// </summary>
- internal static string PepperProcessPluginFlagFormat {
- get {
- return ResourceManager.GetString("PepperProcessPluginFlagFormat", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to NACL_SDK_ROOT.
- /// </summary>
- internal static string SDKPathEnvironmentVariable {
- get {
- return ResourceManager.GetString("SDKPathEnvironmentVariable", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to NaCl SDK Root is not set in project properties! Cannot run NaCl functionality..
- /// </summary>
- internal static string SDKPathNotSetError {
- get {
- return ResourceManager.GetString("SDKPathNotSetError", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Unsupported breakpoint type: {0}.
- /// </summary>
- internal static string UnsupportedBreakpointTypeFormat {
- get {
- return ResourceManager.GetString("UnsupportedBreakpointTypeFormat", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Native Client Web Server Output.
- /// </summary>
- internal static string WebServerOutputWindowTitle {
- get {
- return ResourceManager.GetString("WebServerOutputWindowTitle", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Specified web server port was not valid, defaulting to {0}.
- /// </summary>
- internal static string WebServerPortNotSetFormat {
- get {
- return ResourceManager.GetString("WebServerPortNotSetFormat", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Warning: Failed to start web server. Is python.exe in PATH?.
- /// </summary>
- internal static string WebServerStartFail {
- get {
- return ResourceManager.GetString("WebServerStartFail", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Launching web server....
- /// </summary>
- internal static string WebServerStartMessage {
- get {
- return ResourceManager.GetString("WebServerStartMessage", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Killing web server....
- /// </summary>
- internal static string WebServerStopMessage {
- get {
- return ResourceManager.GetString("WebServerStopMessage", resourceCulture);
- }
- }
- }
-}
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.269
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace NativeClientVSAddIn {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Strings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Strings() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NativeClientVSAddIn.Strings", typeof(Strings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Native Client Visual Studio Add-In.
+ /// </summary>
+ internal static string AddInName {
+ get {
+ return ResourceManager.GetString("AddInName", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to CHROME_PATH.
+ /// </summary>
+ internal static string ChromePathEnvironmentVariable {
+ get {
+ return ResourceManager.GetString("ChromePathEnvironmentVariable", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to chrome.exe.
+ /// </summary>
+ internal static string ChromeProcessName {
+ get {
+ return ResourceManager.GetString("ChromeProcessName", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to --type=renderer.
+ /// </summary>
+ internal static string ChromeRendererFlag {
+ get {
+ return ResourceManager.GetString("ChromeRendererFlag", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Warning: Multiple start-up projects not supported. Web server will only be run from first project directory.
+ /// </summary>
+ internal static string MultiStartProjectWarning {
+ get {
+ return ResourceManager.GetString("MultiStartProjectWarning", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to --enable-nacl-debug.
+ /// </summary>
+ internal static string NaClDebugFlag {
+ get {
+ return ResourceManager.GetString("NaClDebugFlag", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to --type=nacl-loader.
+ /// </summary>
+ internal static string NaClLoaderFlag {
+ get {
+ return ResourceManager.GetString("NaClLoaderFlag", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to NaCl.
+ /// </summary>
+ internal static string NaClPlatformName {
+ get {
+ return ResourceManager.GetString("NaClPlatformName", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to nacl64.exe.
+ /// </summary>
+ internal static string NaClProcessName {
+ get {
+ return ResourceManager.GetString("NaClProcessName", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to PPAPI.
+ /// </summary>
+ internal static string PepperPlatformName {
+ get {
+ return ResourceManager.GetString("PepperPlatformName", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to --register-pepper-plugins="{0};application/x-nacl".
+ /// </summary>
+ internal static string PepperProcessPluginFlagFormat {
+ get {
+ return ResourceManager.GetString("PepperProcessPluginFlagFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to NACL_SDK_ROOT.
+ /// </summary>
+ internal static string SDKPathEnvironmentVariable {
+ get {
+ return ResourceManager.GetString("SDKPathEnvironmentVariable", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to NaCl SDK Root is not set in project properties! Cannot run NaCl functionality..
+ /// </summary>
+ internal static string SDKPathNotSetError {
+ get {
+ return ResourceManager.GetString("SDKPathNotSetError", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Unsupported breakpoint type: {0}.
+ /// </summary>
+ internal static string UnsupportedBreakpointTypeFormat {
+ get {
+ return ResourceManager.GetString("UnsupportedBreakpointTypeFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Native Client Web Server Output.
+ /// </summary>
+ internal static string WebServerOutputWindowTitle {
+ get {
+ return ResourceManager.GetString("WebServerOutputWindowTitle", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Specified web server port was not valid, defaulting to {0}.
+ /// </summary>
+ internal static string WebServerPortNotSetFormat {
+ get {
+ return ResourceManager.GetString("WebServerPortNotSetFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Warning: Failed to start web server. Is python.exe in PATH?.
+ /// </summary>
+ internal static string WebServerStartFail {
+ get {
+ return ResourceManager.GetString("WebServerStartFail", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Launching web server....
+ /// </summary>
+ internal static string WebServerStartMessage {
+ get {
+ return ResourceManager.GetString("WebServerStartMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Killing web server....
+ /// </summary>
+ internal static string WebServerStopMessage {
+ get {
+ return ResourceManager.GetString("WebServerStopMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/Utility.cs b/NativeClientVSAddIn/Utility.cs
index 69eec0f..94dff83 100644
--- a/NativeClientVSAddIn/Utility.cs
+++ b/NativeClientVSAddIn/Utility.cs
@@ -1,220 +1,220 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
- using System.Collections.Generic;
-
- using EnvDTE;
- using EnvDTE80;
- using Microsoft.VisualStudio.VCProjectEngine;
-
- /// <summary>
- /// Contains helper functions for this add-in.
- /// </summary>
- public static class Utility
- {
- /// <summary>
- /// Tells us if the given project is a Visual C/C++ project.
- /// </summary>
- /// <param name="proj">Project to check.</param>
- /// <returns>True if project is a Visual C/C++ project.</returns>
- public static bool IsVisualCProject(Project proj)
- {
- foreach (Property prop in proj.Properties)
- {
- if (prop.Name == "Kind")
- {
- string projectType = prop.Value as string;
- return projectType == "VCProject";
- }
- }
-
- return false;
- }
-
- /// <summary>
- /// Given a generic project, checks that it is a Visual C project, and
- /// extracts the active VCConfiguration object.
- /// </summary>
- /// <param name="proj">Generic project object.</param>
- /// <returns>The active configuration, or null if failure.</returns>
- public static VCConfiguration GetActiveVCConfiguration(Project proj)
- {
- if (!IsVisualCProject(proj))
- {
- return null;
- }
-
- VCProject vcproj = (VCProject)proj.Object;
- IVCCollection configs = vcproj.Configurations;
- Configuration active = proj.ConfigurationManager.ActiveConfiguration;
-
- foreach (VCConfiguration config in configs)
- {
- if (config.ConfigurationName == active.ConfigurationName &&
- config.Platform.Name == active.PlatformName)
- {
- return config;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Will print a message to the web server output pane.
- /// </summary>
- /// <param name="dte">The main visual studio interface.</param>
- /// <param name="message">Message to print to the output pane.</param>
- public static void WebServerWriteLine(DTE2 dte, string message)
- {
- try
- {
- OutputWindowPane pane = dte.ToolWindows.OutputWindow.OutputWindowPanes.Item(
- Strings.WebServerOutputWindowTitle);
- pane.OutputString(message + "\n");
- }
- catch (ArgumentException)
- {
- // This exception is expected if the window pane hasn't been created yet.
- }
- }
-
- /// <summary>
- /// Returns all VCConfigurations from the open solution that have the specified platform name.
- /// Note only VC++ projects are checked.
- /// </summary>
- /// <param name="dte">Visual studio main interface.</param>
- /// <param name="platformName">Name of the platform to get.</param>
- /// <returns>List of all matching VCConfigurations.</returns>
- public static List<VCConfiguration> GetPlatformVCConfigurations(DTE2 dte, string platformName)
- {
- var platformConfigs = new List<VCConfiguration>();
- foreach (Project proj in dte.Solution.Projects)
- {
- if (Utility.IsVisualCProject(proj))
- {
- VCProject vcproj = (VCProject)proj.Object;
- IVCCollection configs = vcproj.Configurations;
-
- foreach (VCConfiguration config in configs)
- {
- if (platformName.Equals(config.Platform.Name))
- {
- platformConfigs.Add(config);
- }
- }
- }
- }
-
- return platformConfigs;
- }
-
- /// <summary>
- /// Extends the string class to allow checking if a string contains another string
- /// allowing a comparison type (such as case-insensitivity).
- /// </summary>
- /// <param name="source">Base string to search.</param>
- /// <param name="toCheck">String to check if contained within base string.</param>
- /// <param name="comparison">Comparison type.</param>
- /// <returns>True if toCheck is contained in source.</returns>
- public static bool Contains(this string source, string toCheck, StringComparison comparison)
- {
- return source.IndexOf(toCheck, comparison) != -1;
- }
-
- /// <summary>
- /// This checks if the first argument is a descendant of the second, where
- /// both arguments are process IDs of two processes.
- /// </summary>
- /// <param name="processSearcher">Process searcher object.</param>
- /// <param name="descendant">Process ID of the descendant.</param>
- /// <param name="ancestor">Process ID of ancestor.</param>
- /// <returns>True if descendant is a descendant of ancestor.</returns>
- public static bool IsDescendantOfProcess(
- ProcessSearcher processSearcher,
- uint descendant,
- uint ancestor)
- {
- return IsDescendantOfProcessHelper(
- processSearcher,
- descendant,
- ancestor,
- DateTime.UtcNow);
- }
-
- /// <summary>
- /// Helper function to properly dispose of a process object and ensure it is dead. The given
- /// reference is set to null afterwards.
- /// </summary>
- /// <param name="process">Process to kill. Reference is set to null afterwards.</param>
- public static void EnsureProcessKill(ref System.Diagnostics.Process process)
- {
- if (process == null)
- {
- return;
- }
-
- try
- {
- process.Kill();
- }
- catch (System.InvalidOperationException)
- {
- // This happens if the process has already exited.
- }
-
- process.Dispose();
- process = null;
- }
-
- /// <summary>
- /// Helper function for IsDescendantOfProcessHelper().
- /// This function prevents an edge case where a process has a parent process ID
- /// that refers to a descendant of itself. This can occur when the parent of a process
- /// is destroyed and the parent's pid is recycled and reused on a descendant. The
- /// parent process ID value is never updated when the parent is destroyed. The solution
- /// is to make sure that parents are created before children, otherwise it is a cycle.
- /// </summary>
- /// <param name="processSearcher">Process searcher object.</param>
- /// <param name="descendant">Process ID of the descendant.</param>
- /// <param name="anscestor">Process ID of the ancestor.</param>
- /// <param name="previousCreationTime">Creation time of the previous call's descendant.</param>
- /// <returns>True if descendant is a descendant of ancestor.</returns>
- private static bool IsDescendantOfProcessHelper(
- ProcessSearcher processSearcher,
- uint descendant,
- uint anscestor,
- DateTime previousCreationTime)
- {
- List<ProcessInfo> results = processSearcher.GetResultsByID(descendant);
- foreach (ProcessInfo proc in results)
- {
- // Ensure this parent relationship is valid.
- if (proc.CreationDate <= previousCreationTime)
- {
- if (descendant == anscestor)
- {
- return true;
- }
- else if (descendant == proc.ParentID)
- {
- // If process is its own parent then we have a cycle, return false.
- return false;
- }
-
- return IsDescendantOfProcessHelper(
- processSearcher,
- proc.ParentID,
- anscestor,
- proc.CreationDate);
- }
- }
-
- return false;
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+ using System.Collections.Generic;
+
+ using EnvDTE;
+ using EnvDTE80;
+ using Microsoft.VisualStudio.VCProjectEngine;
+
+ /// <summary>
+ /// Contains helper functions for this add-in.
+ /// </summary>
+ public static class Utility
+ {
+ /// <summary>
+ /// Tells us if the given project is a Visual C/C++ project.
+ /// </summary>
+ /// <param name="proj">Project to check.</param>
+ /// <returns>True if project is a Visual C/C++ project.</returns>
+ public static bool IsVisualCProject(Project proj)
+ {
+ foreach (Property prop in proj.Properties)
+ {
+ if (prop.Name == "Kind")
+ {
+ string projectType = prop.Value as string;
+ return projectType == "VCProject";
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Given a generic project, checks that it is a Visual C project, and
+ /// extracts the active VCConfiguration object.
+ /// </summary>
+ /// <param name="proj">Generic project object.</param>
+ /// <returns>The active configuration, or null if failure.</returns>
+ public static VCConfiguration GetActiveVCConfiguration(Project proj)
+ {
+ if (!IsVisualCProject(proj))
+ {
+ return null;
+ }
+
+ VCProject vcproj = (VCProject)proj.Object;
+ IVCCollection configs = vcproj.Configurations;
+ Configuration active = proj.ConfigurationManager.ActiveConfiguration;
+
+ foreach (VCConfiguration config in configs)
+ {
+ if (config.ConfigurationName == active.ConfigurationName &&
+ config.Platform.Name == active.PlatformName)
+ {
+ return config;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Will print a message to the web server output pane.
+ /// </summary>
+ /// <param name="dte">The main visual studio interface.</param>
+ /// <param name="message">Message to print to the output pane.</param>
+ public static void WebServerWriteLine(DTE2 dte, string message)
+ {
+ try
+ {
+ OutputWindowPane pane = dte.ToolWindows.OutputWindow.OutputWindowPanes.Item(
+ Strings.WebServerOutputWindowTitle);
+ pane.OutputString(message + "\n");
+ }
+ catch (ArgumentException)
+ {
+ // This exception is expected if the window pane hasn't been created yet.
+ }
+ }
+
+ /// <summary>
+ /// Returns all VCConfigurations from the open solution that have the specified platform name.
+ /// Note only VC++ projects are checked.
+ /// </summary>
+ /// <param name="dte">Visual studio main interface.</param>
+ /// <param name="platformName">Name of the platform to get.</param>
+ /// <returns>List of all matching VCConfigurations.</returns>
+ public static List<VCConfiguration> GetPlatformVCConfigurations(DTE2 dte, string platformName)
+ {
+ var platformConfigs = new List<VCConfiguration>();
+ foreach (Project proj in dte.Solution.Projects)
+ {
+ if (Utility.IsVisualCProject(proj))
+ {
+ VCProject vcproj = (VCProject)proj.Object;
+ IVCCollection configs = vcproj.Configurations;
+
+ foreach (VCConfiguration config in configs)
+ {
+ if (platformName.Equals(config.Platform.Name))
+ {
+ platformConfigs.Add(config);
+ }
+ }
+ }
+ }
+
+ return platformConfigs;
+ }
+
+ /// <summary>
+ /// Extends the string class to allow checking if a string contains another string
+ /// allowing a comparison type (such as case-insensitivity).
+ /// </summary>
+ /// <param name="source">Base string to search.</param>
+ /// <param name="toCheck">String to check if contained within base string.</param>
+ /// <param name="comparison">Comparison type.</param>
+ /// <returns>True if toCheck is contained in source.</returns>
+ public static bool Contains(this string source, string toCheck, StringComparison comparison)
+ {
+ return source.IndexOf(toCheck, comparison) != -1;
+ }
+
+ /// <summary>
+ /// This checks if the first argument is a descendant of the second, where
+ /// both arguments are process IDs of two processes.
+ /// </summary>
+ /// <param name="processSearcher">Process searcher object.</param>
+ /// <param name="descendant">Process ID of the descendant.</param>
+ /// <param name="ancestor">Process ID of ancestor.</param>
+ /// <returns>True if descendant is a descendant of ancestor.</returns>
+ public static bool IsDescendantOfProcess(
+ ProcessSearcher processSearcher,
+ uint descendant,
+ uint ancestor)
+ {
+ return IsDescendantOfProcessHelper(
+ processSearcher,
+ descendant,
+ ancestor,
+ DateTime.UtcNow);
+ }
+
+ /// <summary>
+ /// Helper function to properly dispose of a process object and ensure it is dead. The given
+ /// reference is set to null afterwards.
+ /// </summary>
+ /// <param name="process">Process to kill. Reference is set to null afterwards.</param>
+ public static void EnsureProcessKill(ref System.Diagnostics.Process process)
+ {
+ if (process == null)
+ {
+ return;
+ }
+
+ try
+ {
+ process.Kill();
+ }
+ catch (System.InvalidOperationException)
+ {
+ // This happens if the process has already exited.
+ }
+
+ process.Dispose();
+ process = null;
+ }
+
+ /// <summary>
+ /// Helper function for IsDescendantOfProcessHelper().
+ /// This function prevents an edge case where a process has a parent process ID
+ /// that refers to a descendant of itself. This can occur when the parent of a process
+ /// is destroyed and the parent's pid is recycled and reused on a descendant. The
+ /// parent process ID value is never updated when the parent is destroyed. The solution
+ /// is to make sure that parents are created before children, otherwise it is a cycle.
+ /// </summary>
+ /// <param name="processSearcher">Process searcher object.</param>
+ /// <param name="descendant">Process ID of the descendant.</param>
+ /// <param name="anscestor">Process ID of the ancestor.</param>
+ /// <param name="previousCreationTime">Creation time of the previous call's descendant.</param>
+ /// <returns>True if descendant is a descendant of ancestor.</returns>
+ private static bool IsDescendantOfProcessHelper(
+ ProcessSearcher processSearcher,
+ uint descendant,
+ uint anscestor,
+ DateTime previousCreationTime)
+ {
+ List<ProcessInfo> results = processSearcher.GetResultsByID(descendant);
+ foreach (ProcessInfo proc in results)
+ {
+ // Ensure this parent relationship is valid.
+ if (proc.CreationDate <= previousCreationTime)
+ {
+ if (descendant == anscestor)
+ {
+ return true;
+ }
+ else if (descendant == proc.ParentID)
+ {
+ // If process is its own parent then we have a cycle, return false.
+ return false;
+ }
+
+ return IsDescendantOfProcessHelper(
+ processSearcher,
+ proc.ParentID,
+ anscestor,
+ proc.CreationDate);
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/NativeClientVSAddIn/WebServer.cs b/NativeClientVSAddIn/WebServer.cs
index 152a944..f60a582 100644
--- a/NativeClientVSAddIn/WebServer.cs
+++ b/NativeClientVSAddIn/WebServer.cs
@@ -1,142 +1,142 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
-
- using EnvDTE;
- using Microsoft.VisualStudio.VCProjectEngine;
-
- /// <summary>
- /// This class contains the functionality related to the web server which hosts the web page
- /// during debugging.
- /// </summary>
- public class WebServer : IDisposable
- {
- /// <summary>
- /// The web server port to default to if the user does not specify one.
- /// </summary>
- private const int DefaultWebServerPort = 5103;
-
- /// <summary>
- /// Holds the main web server process.
- /// </summary>
- private System.Diagnostics.Process webServer_;
-
- /// <summary>
- /// Captures output from the web server.
- /// </summary>
- private OutputWindowPane webServerOutputPane_;
-
- /// <summary>
- /// Keeps track of if dispose has been called.
- /// </summary>
- private bool disposed_ = false;
-
- /// <summary>
- /// Constructs the WebServer, starts the web server process.
- /// </summary>
- /// <param name="outputWindowPane">Existing output pane to send web server output to.</param>
- /// <param name="properties">PropertyManager that is set to a valid project/platform.</param>
- public WebServer(OutputWindowPane outputWindowPane, PropertyManager properties)
- {
- if (outputWindowPane == null)
- {
- throw new ArgumentNullException("outputWindowPane");
- }
-
- if (properties == null)
- {
- throw new ArgumentNullException("properties");
- }
-
- webServerOutputPane_ = outputWindowPane;
-
- // Read port from properties, if invalid port then set to default value.
- int webServerPort;
- if (!int.TryParse(properties.WebServerPort, out webServerPort))
- {
- webServerPort = DefaultWebServerPort;
- }
-
- string webServerExecutable = "python.exe";
- string webServerArguments = string.Format(
- "{0}\\examples\\httpd.py --no_dir_check {1}", properties.SDKRootDirectory, webServerPort);
-
- // Start the web server process.
- try
- {
- webServer_ = new System.Diagnostics.Process();
- webServer_.StartInfo.CreateNoWindow = true;
- webServer_.StartInfo.UseShellExecute = false;
- webServer_.StartInfo.RedirectStandardOutput = true;
- webServer_.StartInfo.RedirectStandardError = true;
- webServer_.StartInfo.FileName = webServerExecutable;
- webServer_.StartInfo.Arguments = webServerArguments;
- webServer_.StartInfo.WorkingDirectory = properties.ProjectDirectory;
- webServer_.OutputDataReceived += WebServerMessageReceive;
- webServer_.ErrorDataReceived += WebServerMessageReceive;
- webServer_.Start();
- webServer_.BeginOutputReadLine();
- webServer_.BeginErrorReadLine();
- }
- catch (Exception e)
- {
- webServerOutputPane_.OutputString(Strings.WebServerStartFail + "\n");
- webServerOutputPane_.OutputString("Exception: " + e.Message + "\n");
- webServerOutputPane_.Activate();
- }
-
- webServerOutputPane_.Clear();
- webServerOutputPane_.OutputString(Strings.WebServerStartMessage + "\n");
- webServerOutputPane_.Activate();
- }
-
- /// <summary>
- /// Finalizer. Should clean up unmanaged resources. Should not be overriden in derived classes.
- /// </summary>
- ~WebServer()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// Disposes the object when called by user code (not directly by garbage collector).
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Disposes the object. If disposing is false then this has been called by garbage collection,
- /// and we shouldn't reference managed objects.
- /// </summary>
- /// <param name="disposing">True if user called Dispose, false if garbage collection.</param>
- protected virtual void Dispose(bool disposing)
- {
- if (!disposed_ && disposing)
- {
- // Managed resource clean up.
- Utility.EnsureProcessKill(ref webServer_);
- webServerOutputPane_.OutputString(Strings.WebServerStopMessage);
- webServerOutputPane_.Activate();
- }
-
- disposed_ = true;
- }
-
- /// <summary>
- /// Receives output from the web server process to display in the Visual Studio UI.
- /// </summary>
- /// <param name="sender">The parameter is not used.</param>
- /// <param name="e">Contains the data to display.</param>
- private void WebServerMessageReceive(object sender, System.Diagnostics.DataReceivedEventArgs e)
- {
- webServerOutputPane_.OutputString(e.Data + "\n");
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+
+ using EnvDTE;
+ using Microsoft.VisualStudio.VCProjectEngine;
+
+ /// <summary>
+ /// This class contains the functionality related to the web server which hosts the web page
+ /// during debugging.
+ /// </summary>
+ public class WebServer : IDisposable
+ {
+ /// <summary>
+ /// The web server port to default to if the user does not specify one.
+ /// </summary>
+ private const int DefaultWebServerPort = 5103;
+
+ /// <summary>
+ /// Holds the main web server process.
+ /// </summary>
+ private System.Diagnostics.Process webServer_;
+
+ /// <summary>
+ /// Captures output from the web server.
+ /// </summary>
+ private OutputWindowPane webServerOutputPane_;
+
+ /// <summary>
+ /// Keeps track of if dispose has been called.
+ /// </summary>
+ private bool disposed_ = false;
+
+ /// <summary>
+ /// Constructs the WebServer, starts the web server process.
+ /// </summary>
+ /// <param name="outputWindowPane">Existing output pane to send web server output to.</param>
+ /// <param name="properties">PropertyManager that is set to a valid project/platform.</param>
+ public WebServer(OutputWindowPane outputWindowPane, PropertyManager properties)
+ {
+ if (outputWindowPane == null)
+ {
+ throw new ArgumentNullException("outputWindowPane");
+ }
+
+ if (properties == null)
+ {
+ throw new ArgumentNullException("properties");
+ }
+
+ webServerOutputPane_ = outputWindowPane;
+
+ // Read port from properties, if invalid port then set to default value.
+ int webServerPort;
+ if (!int.TryParse(properties.WebServerPort, out webServerPort))
+ {
+ webServerPort = DefaultWebServerPort;
+ }
+
+ string webServerExecutable = "python.exe";
+ string webServerArguments = string.Format(
+ "{0}\\examples\\httpd.py --no_dir_check {1}", properties.SDKRootDirectory, webServerPort);
+
+ // Start the web server process.
+ try
+ {
+ webServer_ = new System.Diagnostics.Process();
+ webServer_.StartInfo.CreateNoWindow = true;
+ webServer_.StartInfo.UseShellExecute = false;
+ webServer_.StartInfo.RedirectStandardOutput = true;
+ webServer_.StartInfo.RedirectStandardError = true;
+ webServer_.StartInfo.FileName = webServerExecutable;
+ webServer_.StartInfo.Arguments = webServerArguments;
+ webServer_.StartInfo.WorkingDirectory = properties.ProjectDirectory;
+ webServer_.OutputDataReceived += WebServerMessageReceive;
+ webServer_.ErrorDataReceived += WebServerMessageReceive;
+ webServer_.Start();
+ webServer_.BeginOutputReadLine();
+ webServer_.BeginErrorReadLine();
+ }
+ catch (Exception e)
+ {
+ webServerOutputPane_.OutputString(Strings.WebServerStartFail + "\n");
+ webServerOutputPane_.OutputString("Exception: " + e.Message + "\n");
+ webServerOutputPane_.Activate();
+ }
+
+ webServerOutputPane_.Clear();
+ webServerOutputPane_.OutputString(Strings.WebServerStartMessage + "\n");
+ webServerOutputPane_.Activate();
+ }
+
+ /// <summary>
+ /// Finalizer. Should clean up unmanaged resources. Should not be overriden in derived classes.
+ /// </summary>
+ ~WebServer()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// Disposes the object when called by user code (not directly by garbage collector).
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Disposes the object. If disposing is false then this has been called by garbage collection,
+ /// and we shouldn't reference managed objects.
+ /// </summary>
+ /// <param name="disposing">True if user called Dispose, false if garbage collection.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed_ && disposing)
+ {
+ // Managed resource clean up.
+ Utility.EnsureProcessKill(ref webServer_);
+ webServerOutputPane_.OutputString(Strings.WebServerStopMessage);
+ webServerOutputPane_.Activate();
+ }
+
+ disposed_ = true;
+ }
+
+ /// <summary>
+ /// Receives output from the web server process to display in the Visual Studio UI.
+ /// </summary>
+ /// <param name="sender">The parameter is not used.</param>
+ /// <param name="e">Contains the data to display.</param>
+ private void WebServerMessageReceive(object sender, System.Diagnostics.DataReceivedEventArgs e)
+ {
+ webServerOutputPane_.OutputString(e.Data + "\n");
+ }
+ }
+}
diff --git a/TestingProjects/BlankValidSolution/NotNaCl/Program.cs b/TestingProjects/BlankValidSolution/NotNaCl/Program.cs
index f45a93f..41c5030 100644
--- a/TestingProjects/BlankValidSolution/NotNaCl/Program.cs
+++ b/TestingProjects/BlankValidSolution/NotNaCl/Program.cs
@@ -1,14 +1,14 @@
-namespace NotNaCl
-{
- /// <summary>
- /// This project is used in tests to ensure that the add-in doesn't run
- /// when a non-NaCl/Pepper project is the start-up project, and that non-NaCl/pepper
- /// projects still compile correctly when part of a solution containing NaCl projects.
- /// </summary>
- class Program
- {
- static void Main(string[] args)
- {
- }
- }
-}
+namespace NotNaCl
+{
+ /// <summary>
+ /// This project is used in tests to ensure that the add-in doesn't run
+ /// when a non-NaCl/Pepper project is the start-up project, and that non-NaCl/pepper
+ /// projects still compile correctly when part of a solution containing NaCl projects.
+ /// </summary>
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ }
+ }
+}
diff --git a/UnitTests/ComMessageFilter.cs b/UnitTests/ComMessageFilter.cs
index ae616c3..b90d1d3 100644
--- a/UnitTests/ComMessageFilter.cs
+++ b/UnitTests/ComMessageFilter.cs
@@ -1,161 +1,161 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
- using System.Runtime.InteropServices;
-
- /// <summary>
- /// Interface for IOleMessageFilter.
- /// </summary>
- [ComImport, Guid("00000016-0000-0000-C000-000000000046"),
- InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IOleMessageFilter
- {
- /// <summary>
- /// Handles calls for the thread.
- /// </summary>
- /// <param name="dwCallType">The parameter is not used.</param>
- /// <param name="hTaskCaller">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="lpInterfaceInfo">The parameter is not used.</param>
- /// <returns>Code indicating message was handled.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- [PreserveSig]
- int HandleInComingCall(
- int dwCallType,
- IntPtr hTaskCaller,
- int dwTickCount,
- IntPtr lpInterfaceInfo);
-
- /// <summary>
- /// Automatically retries the failed call.
- /// </summary>
- /// <param name="hTaskCallee">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="dwRejectType">The parameter is not used.</param>
- /// <returns>Code indicating call should be retried.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- [PreserveSig]
- int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
-
- /// <summary>
- /// Handles an incoming message by indicating it should be dispatched always.
- /// </summary>
- /// <param name="hTaskCallee">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="dwPendingType">The parameter is not used.</param>
- /// <returns>Code indicating message should be dispatched.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- [PreserveSig]
- int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
- }
-
- /// <summary>
- /// This class receives messages from the COM calls to Visual Studio
- /// and auto-retries them if they fail because VS is busy.
- /// </summary>
- public class ComMessageFilter : IOleMessageFilter
- {
- /// <summary>
- /// Note this registers the filter only for the current thread.
- /// </summary>
- public static void Register()
- {
- IOleMessageFilter oldFilter = null;
- CoRegisterMessageFilter(new ComMessageFilter(), out oldFilter);
- }
-
- /// <summary>
- /// Note this only closes the filter for the current thread.
- /// </summary>
- public static void Revoke()
- {
- IOleMessageFilter oldFilter = null;
- CoRegisterMessageFilter(null, out oldFilter);
- }
-
- /// <summary>
- /// Handles calls for the thread.
- /// </summary>
- /// <param name="dwCallType">The parameter is not used.</param>
- /// <param name="hTaskCaller">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="lpInterfaceInfo">The parameter is not used.</param>
- /// <returns>Code indicating message was handled.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- int IOleMessageFilter.HandleInComingCall(
- int dwCallType,
- System.IntPtr hTaskCaller,
- int dwTickCount,
- System.IntPtr lpInterfaceInfo)
- {
- return 0; // SERVERCALL_ISHANDLED.
- }
-
- /// <summary>
- /// Automatically retries the failed call.
- /// </summary>
- /// <param name="hTaskCallee">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="dwRejectType">The parameter is not used.</param>
- /// <returns>Code indicating call should be retried.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- int IOleMessageFilter.RetryRejectedCall(
- System.IntPtr hTaskCallee,
- int dwTickCount,
- int dwRejectType)
- {
- // If reject type is SERVERCALL_RETRYLATER.
- if (dwRejectType == 2)
- {
- // Immediate retry.
- return 99;
- }
-
- // Cancel call.
- return -1;
- }
-
- /// <summary>
- /// Handles an incoming message by indicating it should be dispatched always.
- /// </summary>
- /// <param name="hTaskCallee">The parameter is not used.</param>
- /// <param name="dwTickCount">The parameter is not used.</param>
- /// <param name="dwPendingType">The parameter is not used.</param>
- /// <returns>Code indicating message should be dispatched.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage(
- "Microsoft.StyleCop.CSharp.NamingRules",
- "SA1305:FieldNamesMustNotUseHungarianNotation",
- Justification = "Matching variable name to COM interface")]
- int IOleMessageFilter.MessagePending(
- System.IntPtr hTaskCallee,
- int dwTickCount,
- int dwPendingType)
- {
- return 2; // PENDINGMSG_WAITDEFPROCESS.
- }
-
- // Implement the IOleMessageFilter interface.
- [DllImport("Ole32.dll")]
- private static extern int CoRegisterMessageFilter(
- IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
- }
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ /// <summary>
+ /// Interface for IOleMessageFilter.
+ /// </summary>
+ [ComImport, Guid("00000016-0000-0000-C000-000000000046"),
+ InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IOleMessageFilter
+ {
+ /// <summary>
+ /// Handles calls for the thread.
+ /// </summary>
+ /// <param name="dwCallType">The parameter is not used.</param>
+ /// <param name="hTaskCaller">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="lpInterfaceInfo">The parameter is not used.</param>
+ /// <returns>Code indicating message was handled.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ [PreserveSig]
+ int HandleInComingCall(
+ int dwCallType,
+ IntPtr hTaskCaller,
+ int dwTickCount,
+ IntPtr lpInterfaceInfo);
+
+ /// <summary>
+ /// Automatically retries the failed call.
+ /// </summary>
+ /// <param name="hTaskCallee">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="dwRejectType">The parameter is not used.</param>
+ /// <returns>Code indicating call should be retried.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ [PreserveSig]
+ int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
+
+ /// <summary>
+ /// Handles an incoming message by indicating it should be dispatched always.
+ /// </summary>
+ /// <param name="hTaskCallee">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="dwPendingType">The parameter is not used.</param>
+ /// <returns>Code indicating message should be dispatched.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ [PreserveSig]
+ int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
+ }
+
+ /// <summary>
+ /// This class receives messages from the COM calls to Visual Studio
+ /// and auto-retries them if they fail because VS is busy.
+ /// </summary>
+ public class ComMessageFilter : IOleMessageFilter
+ {
+ /// <summary>
+ /// Note this registers the filter only for the current thread.
+ /// </summary>
+ public static void Register()
+ {
+ IOleMessageFilter oldFilter = null;
+ CoRegisterMessageFilter(new ComMessageFilter(), out oldFilter);
+ }
+
+ /// <summary>
+ /// Note this only closes the filter for the current thread.
+ /// </summary>
+ public static void Revoke()
+ {
+ IOleMessageFilter oldFilter = null;
+ CoRegisterMessageFilter(null, out oldFilter);
+ }
+
+ /// <summary>
+ /// Handles calls for the thread.
+ /// </summary>
+ /// <param name="dwCallType">The parameter is not used.</param>
+ /// <param name="hTaskCaller">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="lpInterfaceInfo">The parameter is not used.</param>
+ /// <returns>Code indicating message was handled.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ int IOleMessageFilter.HandleInComingCall(
+ int dwCallType,
+ System.IntPtr hTaskCaller,
+ int dwTickCount,
+ System.IntPtr lpInterfaceInfo)
+ {
+ return 0; // SERVERCALL_ISHANDLED.
+ }
+
+ /// <summary>
+ /// Automatically retries the failed call.
+ /// </summary>
+ /// <param name="hTaskCallee">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="dwRejectType">The parameter is not used.</param>
+ /// <returns>Code indicating call should be retried.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ int IOleMessageFilter.RetryRejectedCall(
+ System.IntPtr hTaskCallee,
+ int dwTickCount,
+ int dwRejectType)
+ {
+ // If reject type is SERVERCALL_RETRYLATER.
+ if (dwRejectType == 2)
+ {
+ // Immediate retry.
+ return 99;
+ }
+
+ // Cancel call.
+ return -1;
+ }
+
+ /// <summary>
+ /// Handles an incoming message by indicating it should be dispatched always.
+ /// </summary>
+ /// <param name="hTaskCallee">The parameter is not used.</param>
+ /// <param name="dwTickCount">The parameter is not used.</param>
+ /// <param name="dwPendingType">The parameter is not used.</param>
+ /// <returns>Code indicating message should be dispatched.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "Microsoft.StyleCop.CSharp.NamingRules",
+ "SA1305:FieldNamesMustNotUseHungarianNotation",
+ Justification = "Matching variable name to COM interface")]
+ int IOleMessageFilter.MessagePending(
+ System.IntPtr hTaskCallee,
+ int dwTickCount,
+ int dwPendingType)
+ {
+ return 2; // PENDINGMSG_WAITDEFPROCESS.
+ }
+
+ // Implement the IOleMessageFilter interface.
+ [DllImport("Ole32.dll")]
+ private static extern int CoRegisterMessageFilter(
+ IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
+ }
}
\ No newline at end of file
diff --git a/UnitTests/MockProcessSearcher.cs b/UnitTests/MockProcessSearcher.cs
index 5cb9827..3ca346d 100644
--- a/UnitTests/MockProcessSearcher.cs
+++ b/UnitTests/MockProcessSearcher.cs
@@ -1,36 +1,36 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System.Collections.Generic;
-
- /// <summary>
- /// A fake process searcher that allows the list of 'processes' on the system to be faked.
- /// </summary>
- public class MockProcessSearcher : NativeClientVSAddIn.ProcessSearcher
- {
- /// <summary>
- /// Constructs the fake process searcher.
- /// </summary>
- public MockProcessSearcher()
- {
- this.ProcessList = new List<NativeClientVSAddIn.ProcessInfo>();
- }
-
- /// <summary>
- /// Gets or sets the fake list of processes this MockProcessSearcher knows about.
- /// </summary>
- public List<NativeClientVSAddIn.ProcessInfo> ProcessList { get; set; }
-
- /// <summary>
- /// This method substitutes the fake process list for the list of real system processes.
- /// </summary>
- /// <returns>Fake list of processes</returns>
- protected override List<NativeClientVSAddIn.ProcessInfo> GetSystemProcesses()
- {
- return this.ProcessList;
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// A fake process searcher that allows the list of 'processes' on the system to be faked.
+ /// </summary>
+ public class MockProcessSearcher : NativeClientVSAddIn.ProcessSearcher
+ {
+ /// <summary>
+ /// Constructs the fake process searcher.
+ /// </summary>
+ public MockProcessSearcher()
+ {
+ this.ProcessList = new List<NativeClientVSAddIn.ProcessInfo>();
+ }
+
+ /// <summary>
+ /// Gets or sets the fake list of processes this MockProcessSearcher knows about.
+ /// </summary>
+ public List<NativeClientVSAddIn.ProcessInfo> ProcessList { get; set; }
+
+ /// <summary>
+ /// This method substitutes the fake process list for the list of real system processes.
+ /// </summary>
+ /// <returns>Fake list of processes</returns>
+ protected override List<NativeClientVSAddIn.ProcessInfo> GetSystemProcesses()
+ {
+ return this.ProcessList;
+ }
+ }
+}
diff --git a/UnitTests/MockPropertyManager.cs b/UnitTests/MockPropertyManager.cs
index b156aad..7189150 100644
--- a/UnitTests/MockPropertyManager.cs
+++ b/UnitTests/MockPropertyManager.cs
@@ -1,117 +1,117 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace NativeClientVSAddIn
-{
- using System;
-
- /// <summary>
- /// This class fakes the mechanism for reading and writing properties on property pages.
- /// </summary>
- public class MockPropertyManager : PropertyManager
- {
- /// <summary>
- /// Relays property get calls to the provided delegate.
- /// </summary>
- private PropertyGetter getter_;
-
- /// <summary>
- /// Relays property set calls to the provided delegate.
- /// </summary>
- private PropertySetter setter_;
-
- /// <summary>
- /// Constructs the property manager.
- /// </summary>
- /// <param name="platformType">The platform type to represent.</param>
- /// <param name="getter">Receives property get requests and returns mock values.</param>
- /// <param name="setter">Receives property set requests and checks them.</param>
- public MockPropertyManager(
- ProjectPlatformType platformType, PropertyGetter getter, PropertySetter setter)
- {
- this.ProjectPlatform = platformType;
- getter_ = getter;
- setter_ = setter;
- }
-
- /// <summary>
- /// Can be used to capture the property requests and return whatever value is desired.
- /// If this returns null then the test will throw an error that the property was unexpected.
- /// </summary>
- /// <param name="page">Property page name.</param>
- /// <param name="name">Property name.</param>
- /// <returns>Value to return. Should return null if property was unexpected.</returns>
- public delegate string PropertyGetter(string page, string name);
-
- /// <summary>
- /// Can be used to capture the property requests and set whatever value is desired or do checks.
- /// If this returns false then the test will throw an error that the property was unexpected.
- /// </summary>
- /// <param name="page">Property page name.</param>
- /// <param name="name">Property name.</param>
- /// <param name="value">Value to set.</param>
- /// <returns>True if the value was expected, false if unexpected (error).</returns>
- public delegate bool PropertySetter(string page, string name, string value);
-
- /// <summary>
- /// The full path to the output assembly.
- /// </summary>
- public override string PluginAssembly
- {
- get { return getter_("Property", "PluginAssembly"); }
- protected set { setter_("Property", "PluginAssembly", value); }
- }
-
- /// <summary>
- /// The main project directory.
- /// </summary>
- public override string ProjectDirectory
- {
- get { return getter_("Property", "ProjectDirectory"); }
- protected set { setter_("Property", "ProjectDirectory", value); }
- }
-
- /// <summary>
- /// The directory where the output assembly is placed.
- /// </summary>
- public override string OutputDirectory
- {
- get { return getter_("Property", "OutputDirectory"); }
- protected set { setter_("Property", "OutputDirectory", value); }
- }
-
- /// <summary>
- /// Reads any generic property from the current target properties.
- /// </summary>
- /// <param name="page">Name of the page where the property is located.</param>
- /// <param name="name">Name of the property.</param>
- /// <returns>Mock value of the property as returned by the getter_.</returns>
- public override string GetProperty(string page, string name)
- {
- string value = getter_(page, name);
- if (value == null)
- {
- throw new Exception(string.Format(
- "Property request not expected by test! Page: {0}, Prop: {1}", page, name));
- }
-
- return value;
- }
-
- /// <summary>
- /// Sets any generic property to the current target properties.
- /// </summary>
- /// <param name="page">Page where property is located.</param>
- /// <param name="name">Name of the property.</param>
- /// <param name="value">Unevaluated string value to set.</param>
- public override void SetProperty(string page, string name, string value)
- {
- if (!setter_(page, name, value))
- {
- throw new Exception(string.Format(
- "Property set request was not expected by test! Page {0}, Prop: {1}", page, name));
- }
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace NativeClientVSAddIn
+{
+ using System;
+
+ /// <summary>
+ /// This class fakes the mechanism for reading and writing properties on property pages.
+ /// </summary>
+ public class MockPropertyManager : PropertyManager
+ {
+ /// <summary>
+ /// Relays property get calls to the provided delegate.
+ /// </summary>
+ private PropertyGetter getter_;
+
+ /// <summary>
+ /// Relays property set calls to the provided delegate.
+ /// </summary>
+ private PropertySetter setter_;
+
+ /// <summary>
+ /// Constructs the property manager.
+ /// </summary>
+ /// <param name="platformType">The platform type to represent.</param>
+ /// <param name="getter">Receives property get requests and returns mock values.</param>
+ /// <param name="setter">Receives property set requests and checks them.</param>
+ public MockPropertyManager(
+ ProjectPlatformType platformType, PropertyGetter getter, PropertySetter setter)
+ {
+ this.ProjectPlatform = platformType;
+ getter_ = getter;
+ setter_ = setter;
+ }
+
+ /// <summary>
+ /// Can be used to capture the property requests and return whatever value is desired.
+ /// If this returns null then the test will throw an error that the property was unexpected.
+ /// </summary>
+ /// <param name="page">Property page name.</param>
+ /// <param name="name">Property name.</param>
+ /// <returns>Value to return. Should return null if property was unexpected.</returns>
+ public delegate string PropertyGetter(string page, string name);
+
+ /// <summary>
+ /// Can be used to capture the property requests and set whatever value is desired or do checks.
+ /// If this returns false then the test will throw an error that the property was unexpected.
+ /// </summary>
+ /// <param name="page">Property page name.</param>
+ /// <param name="name">Property name.</param>
+ /// <param name="value">Value to set.</param>
+ /// <returns>True if the value was expected, false if unexpected (error).</returns>
+ public delegate bool PropertySetter(string page, string name, string value);
+
+ /// <summary>
+ /// The full path to the output assembly.
+ /// </summary>
+ public override string PluginAssembly
+ {
+ get { return getter_("Property", "PluginAssembly"); }
+ protected set { setter_("Property", "PluginAssembly", value); }
+ }
+
+ /// <summary>
+ /// The main project directory.
+ /// </summary>
+ public override string ProjectDirectory
+ {
+ get { return getter_("Property", "ProjectDirectory"); }
+ protected set { setter_("Property", "ProjectDirectory", value); }
+ }
+
+ /// <summary>
+ /// The directory where the output assembly is placed.
+ /// </summary>
+ public override string OutputDirectory
+ {
+ get { return getter_("Property", "OutputDirectory"); }
+ protected set { setter_("Property", "OutputDirectory", value); }
+ }
+
+ /// <summary>
+ /// Reads any generic property from the current target properties.
+ /// </summary>
+ /// <param name="page">Name of the page where the property is located.</param>
+ /// <param name="name">Name of the property.</param>
+ /// <returns>Mock value of the property as returned by the getter_.</returns>
+ public override string GetProperty(string page, string name)
+ {
+ string value = getter_(page, name);
+ if (value == null)
+ {
+ throw new Exception(string.Format(
+ "Property request not expected by test! Page: {0}, Prop: {1}", page, name));
+ }
+
+ return value;
+ }
+
+ /// <summary>
+ /// Sets any generic property to the current target properties.
+ /// </summary>
+ /// <param name="page">Page where property is located.</param>
+ /// <param name="name">Name of the property.</param>
+ /// <param name="value">Unevaluated string value to set.</param>
+ public override void SetProperty(string page, string name, string value)
+ {
+ if (!setter_(page, name, value))
+ {
+ throw new Exception(string.Format(
+ "Property set request was not expected by test! Page {0}, Prop: {1}", page, name));
+ }
+ }
+ }
+}
diff --git a/UnitTests/PluginDebuggerGDBTest.cs b/UnitTests/PluginDebuggerGDBTest.cs
index 6f54d08..9a85d90 100644
--- a/UnitTests/PluginDebuggerGDBTest.cs
+++ b/UnitTests/PluginDebuggerGDBTest.cs
@@ -1,398 +1,398 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Reflection;
-
- using EnvDTE80;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- using NativeClientVSAddIn;
-
- /// <summary>
- /// This is a test class for PluginDebuggerGDBTest and is intended
- /// to contain all PluginDebuggerGDB Unit Tests
- /// </summary>
- [TestClass]
- public class PluginDebuggerGDBTest
- {
- /// <summary>
- /// This holds the path to the NaCl solution used in these tests.
- /// The NaCl solution is a valid nacl/pepper plug-in VS solution.
- /// It is copied into the testing deployment directory and opened in some tests.
- /// Because unit-tests run in any order, the solution should not be written to
- /// in any tests.
- /// </summary>
- private static string naclSolution;
-
- /// <summary>
- /// The main visual studio object.
- /// </summary>
- private DTE2 dte_;
-
- /// <summary>
- /// Holds the default properties from property pages to use during tests.
- /// </summary>
- private MockPropertyManager properties_;
-
- /// <summary>
- /// Gets or sets the test context which provides information about,
- /// and functionality for the current test run.
- /// </summary>
- public TestContext TestContext { get; set; }
-
- /// <summary>
- /// This is run one time before any test methods are called. Here we set-up a test-copy of a
- /// new NaCl solution for use in the tests.
- /// </summary>
- /// <param name="testContext">Holds information about the current test run</param>
- [ClassInitialize]
- public static void ClassSetup(TestContext testContext)
- {
- DTE2 dte = TestUtilities.StartVisualStudioInstance();
- try
- {
- naclSolution = TestUtilities.CreateBlankValidNaClSolution(
- dte,
- "PluginDebuggerGDBTest",
- NativeClientVSAddIn.Strings.PepperPlatformName,
- NativeClientVSAddIn.Strings.NaClPlatformName,
- testContext);
- }
- finally
- {
- TestUtilities.CleanUpVisualStudioInstance(dte);
- }
- }
-
- /// <summary>
- /// This is run before each test to create test resources.
- /// </summary>
- [TestInitialize]
- public void TestSetup()
- {
- dte_ = TestUtilities.StartVisualStudioInstance();
- try
- {
- TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
- }
- catch
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- throw;
- }
-
- // Set up mock property manager to return the desired property values.
- properties_ = new MockPropertyManager(
- PropertyManager.ProjectPlatformType.NaCl,
- delegate(string page, string name)
- {
- switch (page)
- {
- case "ConfigurationGeneral":
- switch (name)
- {
- case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
- NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
- case "NaClIrtPath": return @"fake\Irt\Path";
- case "NaClManifestPath": return string.Empty;
- case "ToolchainName": return "newlib";
- }
-
- break;
- case "Property":
- switch (name)
- {
- case "ProjectDirectory": return TestContext.DeploymentDirectory;
- case "PluginAssembly": return @"fake\Assembly\String";
- }
-
- break;
- }
-
- return null;
- },
- null);
- }
-
- /// <summary>
- /// This is run after each test to clean up things created in TestSetup().
- /// </summary>
- [TestCleanup]
- public void TestCleanup()
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- }
-
- /// <summary>
- /// A test for the constructor.
- /// </summary>
- [TestMethod]
- public void PluginDebuggerGDBConstructorTest()
- {
- // Check that a null dte fails.
- try
- {
- PluginDebuggerBase nullDte = new PluginDebuggerGDB(null, properties_);
- Assert.Fail("Using null DTE instance did not throw exception");
- }
- catch (ArgumentNullException)
- {
- // This is expected for a correct implementation.
- }
- catch
- {
- Assert.Fail("Using null DTE instance threw something other than ArgumentNullException");
- }
-
- // Check that a null PropertyManager fails.
- try
- {
- PluginDebuggerBase nullDte = new PluginDebuggerGDB(dte_, null);
- Assert.Fail("Using null property manager did not throw exception");
- }
- catch (ArgumentNullException)
- {
- // This is expected for a correct implementation.
- }
- catch
- {
- Assert.Fail("Using null property manager threw something other than ArgumentNullException");
- }
- }
-
- /// <summary>
- /// Tests that a plugin can be found.
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void FindAndAttachToNaClPluginTest()
- {
- MockProcessSearcher processResults = new MockProcessSearcher();
-
- using (PluginDebuggerGDB target = new PluginDebuggerGDB(dte_, properties_))
- {
- PluginDebuggerBase_Accessor targetBase = new PluginDebuggerBase_Accessor(
- new PrivateObject(target, new PrivateType(typeof(PluginDebuggerBase))));
- targetBase.debuggedChromeMainProcess_ = System.Diagnostics.Process.GetCurrentProcess();
-
- uint currentProcId = (uint)targetBase.debuggedChromeMainProcess_.Id;
-
- // Target nacl process flag.
- string naclCommandLine = Strings.NaClLoaderFlag;
-
- // Fake the list of processes on the system.
- processResults.ProcessList.Add(
- new ProcessInfo(
- currentProcId,
- currentProcId,
- string.Empty,
- Strings.NaClDebugFlag,
- Strings.ChromeProcessName));
- processResults.ProcessList.Add(
- new ProcessInfo(1, currentProcId, string.Empty, string.Empty, "MyParentProcess"));
- processResults.ProcessList.Add(
- new ProcessInfo(11, 1, string.Empty, naclCommandLine, Strings.NaClProcessName));
-
- // This is missing some relevant command line args, should not be attached to.
- processResults.ProcessList.Add(
- new ProcessInfo(13, 1, string.Empty, string.Empty, Strings.NaClProcessName));
-
- // This doesn't have chrome process as their parent, so they should not be attached to.
- processResults.ProcessList.Add(
- new ProcessInfo(15, 15, string.Empty, naclCommandLine, Strings.NaClProcessName));
-
- // Set the private value to the mock object (can't use accessor since no valid cast).
- FieldInfo processSearcherField = typeof(PluginDebuggerBase).GetField(
- "processSearcher_",
- BindingFlags.NonPublic | BindingFlags.Instance);
- processSearcherField.SetValue(targetBase.Target, processResults);
-
- // Test that the correct processes are attached to.
- bool goodNaCl = false;
- var handler = new EventHandler<NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs>(
- delegate(object unused, NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs args)
- {
- switch (args.ProcessID)
- {
- case 11:
- if (goodNaCl)
- {
- Assert.Fail("Should not attach twice to same nacl process");
- }
-
- goodNaCl = true;
- break;
- case 13:
- Assert.Fail("Should not attach to nacl process with bad args");
- break;
- case 15:
- Assert.Fail("Should not attach to nacl process that is not "
- + "descendant of Visual Studio");
- break;
- default:
- Assert.Fail("Should not attach to non-pepper/non-nacl process");
- break;
- }
- });
-
- target.PluginFoundEvent += handler;
- target.FindAndAttachToPlugin(null, null);
- target.PluginFoundEvent -= handler;
-
- Assert.IsTrue(goodNaCl, "Failed to attach to NaCl process");
- }
- }
-
- /// <summary>
- /// A test for Attach. Implicitly tests CleanUpGDBProcess().
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void AttachNaClGDBTest()
- {
- PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
-
- string existingGDB = "AttachNaClGDBTest_existingGDB";
- try
- {
- target.gdbProcess_ = TestUtilities.StartProcessForKilling(existingGDB, 20);
- string existingInitFileName = Path.GetTempFileName();
- target.gdbInitFileName_ = existingInitFileName;
-
- // Visual studio won't allow adding a breakpoint unless it is associated with
- // an existing file and valid line number, so use BlankValidSolution.
- dte_.Solution.Open(naclSolution);
- string fileName = "main.cpp";
- string functionName = "NaClProjectInstance::HandleMessage";
- int lineNumber = 39;
- dte_.Debugger.Breakpoints.Add(Function: functionName);
- dte_.Debugger.Breakpoints.Add(Line: lineNumber, File: fileName);
-
- target.Attach(null, new PluginDebuggerBase.PluginFoundEventArgs(0));
-
- Assert.IsTrue(File.Exists(target.gdbInitFileName_), "Init file not written");
-
- var gdbCommands = new List<string>(File.ReadAllLines(target.gdbInitFileName_));
-
- // Validate that the commands contain what we specified.
- // The syntax itself is not validated since this add-in is not responsible for
- // the syntax and it could change.
- Assert.IsTrue(
- gdbCommands.Exists(s => s.Contains(fileName) && s.Contains(lineNumber.ToString())),
- "Line breakpoint not properly set");
- Assert.IsTrue(
- gdbCommands.Exists(s => s.Contains(functionName)),
- "Function breakpoint not properly set");
-
- // Note fake assembly string should be double escaped when passed to gdb.
- Assert.IsTrue(
- gdbCommands.Exists(s => s.Contains(functionName)),
- @"fake\\Assembly\\String");
-
- // Check that the pre-existing gdb process was killed and its init file cleaned up.
- Assert.IsFalse(
- TestUtilities.DoesProcessExist("python.exe", existingGDB),
- "Failed to kill existing GDB process");
- Assert.IsFalse(
- File.Exists(existingInitFileName),
- "Failed to delete existing temp gdb init file");
- }
- finally
- {
- if (dte_.Debugger.Breakpoints != null)
- {
- // Remove all breakpoints.
- foreach (EnvDTE.Breakpoint bp in dte_.Debugger.Breakpoints)
- {
- bp.Delete();
- }
- }
-
- // Clean up file if not erased.
- if (!string.IsNullOrEmpty(target.gdbInitFileName_) && File.Exists(target.gdbInitFileName_))
- {
- File.Delete(target.gdbInitFileName_);
- }
-
- // Kill the gdb process if not killed.
- if (target.gdbProcess_ != null && !target.gdbProcess_.HasExited)
- {
- target.gdbProcess_.Kill();
- target.gdbProcess_.Dispose();
- }
- }
- }
-
- /// <summary>
- /// A test for Dispose. Implicitly tests CleanUpGDBProcess().
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void DisposeTest()
- {
- PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
-
- string existingGDB = "DisposeTest_GDB";
- try
- {
- target.gdbProcess_ = TestUtilities.StartProcessForKilling(existingGDB, 20);
- string existingInitFileName = Path.GetTempFileName();
- target.gdbInitFileName_ = existingInitFileName;
-
- target.Dispose();
-
- // Check that the pre-existing gdb process was killed and its init file cleaned up.
- Assert.IsFalse(
- TestUtilities.DoesProcessExist("python.exe", existingGDB),
- "Failed to kill existing GDB process");
- Assert.IsFalse(
- File.Exists(existingInitFileName),
- "Failed to delete existing temp gdb init file");
- }
- finally
- {
- // Clean up file if not erased.
- if (!string.IsNullOrEmpty(target.gdbInitFileName_) && File.Exists(target.gdbInitFileName_))
- {
- File.Delete(target.gdbInitFileName_);
- }
-
- // Kill the gdb process if not killed.
- if (target.gdbProcess_ != null && !target.gdbProcess_.HasExited)
- {
- target.gdbProcess_.Kill();
- target.gdbProcess_.Dispose();
- }
- }
- }
-
- /// <summary>
- /// A test for IsPluginProcess.
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void IsNaClPluginProcessTest()
- {
- PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
-
- ProcessInfo badProc = new ProcessInfo(
- 1, 1, string.Empty, Strings.ChromeRendererFlag, Strings.NaClProcessName);
- ProcessInfo goodProc = new ProcessInfo(
- 1, 1, string.Empty, Strings.NaClLoaderFlag, Strings.NaClProcessName);
-
- string goodMainChromeFlags = Strings.NaClDebugFlag;
- string badMainChromeFlags = string.Format(
- Strings.PepperProcessPluginFlagFormat, target.pluginAssembly_);
-
- Assert.IsTrue(target.IsPluginProcess(goodProc, goodMainChromeFlags));
- Assert.IsFalse(target.IsPluginProcess(goodProc, badMainChromeFlags));
- Assert.IsFalse(target.IsPluginProcess(badProc, goodMainChromeFlags));
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Reflection;
+
+ using EnvDTE80;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using NativeClientVSAddIn;
+
+ /// <summary>
+ /// This is a test class for PluginDebuggerGDBTest and is intended
+ /// to contain all PluginDebuggerGDB Unit Tests
+ /// </summary>
+ [TestClass]
+ public class PluginDebuggerGDBTest
+ {
+ /// <summary>
+ /// This holds the path to the NaCl solution used in these tests.
+ /// The NaCl solution is a valid nacl/pepper plug-in VS solution.
+ /// It is copied into the testing deployment directory and opened in some tests.
+ /// Because unit-tests run in any order, the solution should not be written to
+ /// in any tests.
+ /// </summary>
+ private static string naclSolution;
+
+ /// <summary>
+ /// The main visual studio object.
+ /// </summary>
+ private DTE2 dte_;
+
+ /// <summary>
+ /// Holds the default properties from property pages to use during tests.
+ /// </summary>
+ private MockPropertyManager properties_;
+
+ /// <summary>
+ /// Gets or sets the test context which provides information about,
+ /// and functionality for the current test run.
+ /// </summary>
+ public TestContext TestContext { get; set; }
+
+ /// <summary>
+ /// This is run one time before any test methods are called. Here we set-up a test-copy of a
+ /// new NaCl solution for use in the tests.
+ /// </summary>
+ /// <param name="testContext">Holds information about the current test run</param>
+ [ClassInitialize]
+ public static void ClassSetup(TestContext testContext)
+ {
+ DTE2 dte = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ naclSolution = TestUtilities.CreateBlankValidNaClSolution(
+ dte,
+ "PluginDebuggerGDBTest",
+ NativeClientVSAddIn.Strings.PepperPlatformName,
+ NativeClientVSAddIn.Strings.NaClPlatformName,
+ testContext);
+ }
+ finally
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte);
+ }
+ }
+
+ /// <summary>
+ /// This is run before each test to create test resources.
+ /// </summary>
+ [TestInitialize]
+ public void TestSetup()
+ {
+ dte_ = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
+ }
+ catch
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ throw;
+ }
+
+ // Set up mock property manager to return the desired property values.
+ properties_ = new MockPropertyManager(
+ PropertyManager.ProjectPlatformType.NaCl,
+ delegate(string page, string name)
+ {
+ switch (page)
+ {
+ case "ConfigurationGeneral":
+ switch (name)
+ {
+ case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
+ NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
+ case "NaClIrtPath": return @"fake\Irt\Path";
+ case "NaClManifestPath": return string.Empty;
+ case "ToolchainName": return "newlib";
+ }
+
+ break;
+ case "Property":
+ switch (name)
+ {
+ case "ProjectDirectory": return TestContext.DeploymentDirectory;
+ case "PluginAssembly": return @"fake\Assembly\String";
+ }
+
+ break;
+ }
+
+ return null;
+ },
+ null);
+ }
+
+ /// <summary>
+ /// This is run after each test to clean up things created in TestSetup().
+ /// </summary>
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ }
+
+ /// <summary>
+ /// A test for the constructor.
+ /// </summary>
+ [TestMethod]
+ public void PluginDebuggerGDBConstructorTest()
+ {
+ // Check that a null dte fails.
+ try
+ {
+ PluginDebuggerBase nullDte = new PluginDebuggerGDB(null, properties_);
+ Assert.Fail("Using null DTE instance did not throw exception");
+ }
+ catch (ArgumentNullException)
+ {
+ // This is expected for a correct implementation.
+ }
+ catch
+ {
+ Assert.Fail("Using null DTE instance threw something other than ArgumentNullException");
+ }
+
+ // Check that a null PropertyManager fails.
+ try
+ {
+ PluginDebuggerBase nullDte = new PluginDebuggerGDB(dte_, null);
+ Assert.Fail("Using null property manager did not throw exception");
+ }
+ catch (ArgumentNullException)
+ {
+ // This is expected for a correct implementation.
+ }
+ catch
+ {
+ Assert.Fail("Using null property manager threw something other than ArgumentNullException");
+ }
+ }
+
+ /// <summary>
+ /// Tests that a plugin can be found.
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void FindAndAttachToNaClPluginTest()
+ {
+ MockProcessSearcher processResults = new MockProcessSearcher();
+
+ using (PluginDebuggerGDB target = new PluginDebuggerGDB(dte_, properties_))
+ {
+ PluginDebuggerBase_Accessor targetBase = new PluginDebuggerBase_Accessor(
+ new PrivateObject(target, new PrivateType(typeof(PluginDebuggerBase))));
+ targetBase.debuggedChromeMainProcess_ = System.Diagnostics.Process.GetCurrentProcess();
+
+ uint currentProcId = (uint)targetBase.debuggedChromeMainProcess_.Id;
+
+ // Target nacl process flag.
+ string naclCommandLine = Strings.NaClLoaderFlag;
+
+ // Fake the list of processes on the system.
+ processResults.ProcessList.Add(
+ new ProcessInfo(
+ currentProcId,
+ currentProcId,
+ string.Empty,
+ Strings.NaClDebugFlag,
+ Strings.ChromeProcessName));
+ processResults.ProcessList.Add(
+ new ProcessInfo(1, currentProcId, string.Empty, string.Empty, "MyParentProcess"));
+ processResults.ProcessList.Add(
+ new ProcessInfo(11, 1, string.Empty, naclCommandLine, Strings.NaClProcessName));
+
+ // This is missing some relevant command line args, should not be attached to.
+ processResults.ProcessList.Add(
+ new ProcessInfo(13, 1, string.Empty, string.Empty, Strings.NaClProcessName));
+
+ // This doesn't have chrome process as their parent, so they should not be attached to.
+ processResults.ProcessList.Add(
+ new ProcessInfo(15, 15, string.Empty, naclCommandLine, Strings.NaClProcessName));
+
+ // Set the private value to the mock object (can't use accessor since no valid cast).
+ FieldInfo processSearcherField = typeof(PluginDebuggerBase).GetField(
+ "processSearcher_",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ processSearcherField.SetValue(targetBase.Target, processResults);
+
+ // Test that the correct processes are attached to.
+ bool goodNaCl = false;
+ var handler = new EventHandler<NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs>(
+ delegate(object unused, NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs args)
+ {
+ switch (args.ProcessID)
+ {
+ case 11:
+ if (goodNaCl)
+ {
+ Assert.Fail("Should not attach twice to same nacl process");
+ }
+
+ goodNaCl = true;
+ break;
+ case 13:
+ Assert.Fail("Should not attach to nacl process with bad args");
+ break;
+ case 15:
+ Assert.Fail("Should not attach to nacl process that is not "
+ + "descendant of Visual Studio");
+ break;
+ default:
+ Assert.Fail("Should not attach to non-pepper/non-nacl process");
+ break;
+ }
+ });
+
+ target.PluginFoundEvent += handler;
+ target.FindAndAttachToPlugin(null, null);
+ target.PluginFoundEvent -= handler;
+
+ Assert.IsTrue(goodNaCl, "Failed to attach to NaCl process");
+ }
+ }
+
+ /// <summary>
+ /// A test for Attach. Implicitly tests CleanUpGDBProcess().
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void AttachNaClGDBTest()
+ {
+ PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
+
+ string existingGDB = "AttachNaClGDBTest_existingGDB";
+ try
+ {
+ target.gdbProcess_ = TestUtilities.StartProcessForKilling(existingGDB, 20);
+ string existingInitFileName = Path.GetTempFileName();
+ target.gdbInitFileName_ = existingInitFileName;
+
+ // Visual studio won't allow adding a breakpoint unless it is associated with
+ // an existing file and valid line number, so use BlankValidSolution.
+ dte_.Solution.Open(naclSolution);
+ string fileName = "main.cpp";
+ string functionName = "NaClProjectInstance::HandleMessage";
+ int lineNumber = 39;
+ dte_.Debugger.Breakpoints.Add(Function: functionName);
+ dte_.Debugger.Breakpoints.Add(Line: lineNumber, File: fileName);
+
+ target.Attach(null, new PluginDebuggerBase.PluginFoundEventArgs(0));
+
+ Assert.IsTrue(File.Exists(target.gdbInitFileName_), "Init file not written");
+
+ var gdbCommands = new List<string>(File.ReadAllLines(target.gdbInitFileName_));
+
+ // Validate that the commands contain what we specified.
+ // The syntax itself is not validated since this add-in is not responsible for
+ // the syntax and it could change.
+ Assert.IsTrue(
+ gdbCommands.Exists(s => s.Contains(fileName) && s.Contains(lineNumber.ToString())),
+ "Line breakpoint not properly set");
+ Assert.IsTrue(
+ gdbCommands.Exists(s => s.Contains(functionName)),
+ "Function breakpoint not properly set");
+
+ // Note fake assembly string should be double escaped when passed to gdb.
+ Assert.IsTrue(
+ gdbCommands.Exists(s => s.Contains(functionName)),
+ @"fake\\Assembly\\String");
+
+ // Check that the pre-existing gdb process was killed and its init file cleaned up.
+ Assert.IsFalse(
+ TestUtilities.DoesProcessExist("python.exe", existingGDB),
+ "Failed to kill existing GDB process");
+ Assert.IsFalse(
+ File.Exists(existingInitFileName),
+ "Failed to delete existing temp gdb init file");
+ }
+ finally
+ {
+ if (dte_.Debugger.Breakpoints != null)
+ {
+ // Remove all breakpoints.
+ foreach (EnvDTE.Breakpoint bp in dte_.Debugger.Breakpoints)
+ {
+ bp.Delete();
+ }
+ }
+
+ // Clean up file if not erased.
+ if (!string.IsNullOrEmpty(target.gdbInitFileName_) && File.Exists(target.gdbInitFileName_))
+ {
+ File.Delete(target.gdbInitFileName_);
+ }
+
+ // Kill the gdb process if not killed.
+ if (target.gdbProcess_ != null && !target.gdbProcess_.HasExited)
+ {
+ target.gdbProcess_.Kill();
+ target.gdbProcess_.Dispose();
+ }
+ }
+ }
+
+ /// <summary>
+ /// A test for Dispose. Implicitly tests CleanUpGDBProcess().
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void DisposeTest()
+ {
+ PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
+
+ string existingGDB = "DisposeTest_GDB";
+ try
+ {
+ target.gdbProcess_ = TestUtilities.StartProcessForKilling(existingGDB, 20);
+ string existingInitFileName = Path.GetTempFileName();
+ target.gdbInitFileName_ = existingInitFileName;
+
+ target.Dispose();
+
+ // Check that the pre-existing gdb process was killed and its init file cleaned up.
+ Assert.IsFalse(
+ TestUtilities.DoesProcessExist("python.exe", existingGDB),
+ "Failed to kill existing GDB process");
+ Assert.IsFalse(
+ File.Exists(existingInitFileName),
+ "Failed to delete existing temp gdb init file");
+ }
+ finally
+ {
+ // Clean up file if not erased.
+ if (!string.IsNullOrEmpty(target.gdbInitFileName_) && File.Exists(target.gdbInitFileName_))
+ {
+ File.Delete(target.gdbInitFileName_);
+ }
+
+ // Kill the gdb process if not killed.
+ if (target.gdbProcess_ != null && !target.gdbProcess_.HasExited)
+ {
+ target.gdbProcess_.Kill();
+ target.gdbProcess_.Dispose();
+ }
+ }
+ }
+
+ /// <summary>
+ /// A test for IsPluginProcess.
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void IsNaClPluginProcessTest()
+ {
+ PluginDebuggerGDB_Accessor target = new PluginDebuggerGDB_Accessor(dte_, properties_);
+
+ ProcessInfo badProc = new ProcessInfo(
+ 1, 1, string.Empty, Strings.ChromeRendererFlag, Strings.NaClProcessName);
+ ProcessInfo goodProc = new ProcessInfo(
+ 1, 1, string.Empty, Strings.NaClLoaderFlag, Strings.NaClProcessName);
+
+ string goodMainChromeFlags = Strings.NaClDebugFlag;
+ string badMainChromeFlags = string.Format(
+ Strings.PepperProcessPluginFlagFormat, target.pluginAssembly_);
+
+ Assert.IsTrue(target.IsPluginProcess(goodProc, goodMainChromeFlags));
+ Assert.IsFalse(target.IsPluginProcess(goodProc, badMainChromeFlags));
+ Assert.IsFalse(target.IsPluginProcess(badProc, goodMainChromeFlags));
+ }
+ }
+}
diff --git a/UnitTests/PluginDebuggerVSTest.cs b/UnitTests/PluginDebuggerVSTest.cs
index dd37310..62d5841 100644
--- a/UnitTests/PluginDebuggerVSTest.cs
+++ b/UnitTests/PluginDebuggerVSTest.cs
@@ -1,286 +1,286 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
- using System.Reflection;
-
- using EnvDTE80;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- using NativeClientVSAddIn;
-
- /// <summary>
- /// This is a test class for PluginDebuggerVSTest and is intended
- /// to contain all PluginDebuggerVS Unit Tests
- /// </summary>
- [TestClass]
- public class PluginDebuggerVSTest
- {
- /// <summary>
- /// The main visual studio object.
- /// </summary>
- private DTE2 dte_;
-
- /// <summary>
- /// Holds the default properties from property pages to use during tests.
- /// </summary>
- private MockPropertyManager properties_;
-
- /// <summary>
- /// Gets or sets the test context which provides information about,
- /// and functionality for the current test run.
- /// </summary>
- public TestContext TestContext { get; set; }
-
- /// <summary>
- /// This is run before each test to create test resources.
- /// </summary>
- [TestInitialize]
- public void TestSetup()
- {
- dte_ = TestUtilities.StartVisualStudioInstance();
- try
- {
- TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
- }
- catch
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- throw;
- }
-
- // Set up mock property manager to return the desired property values.
- properties_ = new MockPropertyManager(
- PropertyManager.ProjectPlatformType.Pepper,
- delegate(string page, string name)
- {
- switch (page)
- {
- case "ConfigurationGeneral":
- switch (name)
- {
- case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
- NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
- }
-
- break;
- case "Property":
- switch (name)
- {
- case "ProjectDirectory": return TestContext.DeploymentDirectory;
- case "PluginAssembly": return @"fake\Assembly\String";
- }
-
- break;
- }
-
- return null;
- },
- null);
- }
-
- /// <summary>
- /// This is run after each test to clean up things created in TestSetup().
- /// </summary>
- [TestCleanup]
- public void TestCleanup()
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- }
-
- /// <summary>
- /// A test for the constructor.
- /// </summary>
- [TestMethod]
- public void PluginDebuggerVSConstructorTest()
- {
- // Check that a null dte fails.
- try
- {
- PluginDebuggerBase nullDte = new PluginDebuggerVS(null, properties_);
- Assert.Fail("Using null DTE instance did not throw exception");
- }
- catch (ArgumentNullException)
- {
- // This is expected for a correct implementation.
- }
- catch
- {
- Assert.Fail("Using null DTE instance threw something other than ArgumentNullException");
- }
-
- // Check that a null PropertyManager fails.
- try
- {
- PluginDebuggerBase nullDte = new PluginDebuggerVS(dte_, null);
- Assert.Fail("Using null property manager did not throw exception");
- }
- catch (ArgumentNullException)
- {
- // This is expected for a correct implementation.
- }
- catch
- {
- Assert.Fail("Using null property manager threw something other than ArgumentNullException");
- }
- }
-
- /// <summary>
- /// A test for FindAndAttachToPlugin.
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void FindAndAttachToPepperPluginTest()
- {
- MockProcessSearcher processResults = new MockProcessSearcher();
-
- using (PluginDebuggerVS target = new PluginDebuggerVS(dte_, properties_))
- {
- PluginDebuggerBase_Accessor targetBase = new PluginDebuggerBase_Accessor(
- new PrivateObject(target, new PrivateType(typeof(PluginDebuggerBase))));
- targetBase.debuggedChromeMainProcess_ = System.Diagnostics.Process.GetCurrentProcess();
- uint currentProcId = (uint)targetBase.debuggedChromeMainProcess_.Id;
-
- string pluginLoadFlag = string.Format(
- Strings.PepperProcessPluginFlagFormat, properties_.PluginAssembly);
- string pepperCommandLine = string.Concat(
- pluginLoadFlag, " ", Strings.ChromeRendererFlag);
-
- // Fake the list of processes on the system.
- processResults.ProcessList.Add(
- new ProcessInfo(
- currentProcId,
- currentProcId,
- string.Empty,
- Strings.NaClDebugFlag,
- Strings.ChromeProcessName));
- processResults.ProcessList.Add(
- new ProcessInfo(1, currentProcId, string.Empty, string.Empty, "MyParentProcess"));
- processResults.ProcessList.Add(
- new ProcessInfo(10, 1, string.Empty, pepperCommandLine, Strings.ChromeProcessName));
-
- // This is missing some relevant command line args, and should not be attached to.
- processResults.ProcessList.Add(
- new ProcessInfo(12, 1, string.Empty, pluginLoadFlag, Strings.ChromeProcessName));
-
- // This doesn't have this process as its parent, and should not be attached to.
- processResults.ProcessList.Add(
- new ProcessInfo(14, 14, string.Empty, pepperCommandLine, Strings.ChromeProcessName));
-
- // Set the private value to the mock object (can't use accessor since no valid cast).
- FieldInfo processSearcherField = typeof(PluginDebuggerBase).GetField(
- "processSearcher_",
- BindingFlags.NonPublic | BindingFlags.Instance);
- processSearcherField.SetValue(targetBase.Target, processResults);
-
- // Test that the correct processes are attached to.
- bool goodPepper = false;
- var handler = new EventHandler<NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs>(
- delegate(object unused, NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs args)
- {
- switch (args.ProcessID)
- {
- case 10:
- if (goodPepper)
- {
- Assert.Fail("Should not attach twice to same pepper process");
- }
-
- goodPepper = true;
- break;
- case 12:
- Assert.Fail("Should not attach to pepper process with bad args");
- break;
- case 14:
- Assert.Fail("Should not attach to pepper process that is not "
- + "descendant of Visual Studio");
- break;
- default:
- Assert.Fail("Should not attach to non-pepper/non-nacl process");
- break;
- }
- });
-
- target.PluginFoundEvent += handler;
- target.FindAndAttachToPlugin(null, null);
- target.PluginFoundEvent -= handler;
-
- Assert.IsTrue(goodPepper, "Failed to attach to pepper process");
- }
- }
-
- /// <summary>
- /// Checks that VS properly attaches debugger.
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void AttachVSDebuggerTest()
- {
- using (System.Diagnostics.Process dummyProc = TestUtilities.StartProcessForKilling(
- "DummyProc", 20))
- {
- try
- {
- PluginDebuggerVS_Accessor target = new PluginDebuggerVS_Accessor(dte_, properties_);
-
- var pluginFoundArgs = new NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs(
- (uint)dummyProc.Id);
- target.Attach(null, pluginFoundArgs);
-
- bool isBeingDebugged = false;
- foreach (EnvDTE.Process proc in dte_.Debugger.DebuggedProcesses)
- {
- if (proc.ProcessID == dummyProc.Id)
- {
- isBeingDebugged = true;
- }
- }
-
- Assert.IsTrue(isBeingDebugged, "Visual Studio debugger did not attach");
- }
- finally
- {
- if (dummyProc != null && !dummyProc.HasExited)
- {
- dummyProc.Kill();
- dummyProc.Dispose();
- }
- }
- }
- }
-
- /// <summary>
- /// A test for IsPluginProcess.
- /// </summary>
- [TestMethod]
- [DeploymentItem("NativeClientVSAddIn.dll")]
- public void IsPepperPluginProcessTest()
- {
- PluginDebuggerVS_Accessor target = new PluginDebuggerVS_Accessor(dte_, properties_);
-
- string identifierFlagTarget =
- string.Format(Strings.PepperProcessPluginFlagFormat, target.pluginAssembly_);
- string goodFlags = string.Concat(Strings.ChromeRendererFlag, ' ', identifierFlagTarget);
-
- ProcessInfo badProc1 = new ProcessInfo(
- 1, 1, string.Empty, goodFlags, Strings.NaClProcessName);
- ProcessInfo badProc2 = new ProcessInfo(
- 1, 1, string.Empty, Strings.NaClLoaderFlag, Strings.ChromeProcessName);
- ProcessInfo badProc3 = new ProcessInfo(
- 1, 1, string.Empty, Strings.ChromeRendererFlag, Strings.ChromeProcessName);
- ProcessInfo badProc4 = new ProcessInfo(
- 1, 1, string.Empty, identifierFlagTarget, Strings.ChromeProcessName);
- ProcessInfo goodProc = new ProcessInfo(
- 1, 1, string.Empty, goodFlags, Strings.ChromeProcessName);
-
- Assert.IsTrue(target.IsPluginProcess(goodProc, string.Empty));
- Assert.IsFalse(target.IsPluginProcess(badProc1, string.Empty));
- Assert.IsFalse(target.IsPluginProcess(badProc2, string.Empty));
- Assert.IsFalse(target.IsPluginProcess(badProc3, string.Empty));
- Assert.IsFalse(target.IsPluginProcess(badProc4, string.Empty));
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+ using System.Reflection;
+
+ using EnvDTE80;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using NativeClientVSAddIn;
+
+ /// <summary>
+ /// This is a test class for PluginDebuggerVSTest and is intended
+ /// to contain all PluginDebuggerVS Unit Tests
+ /// </summary>
+ [TestClass]
+ public class PluginDebuggerVSTest
+ {
+ /// <summary>
+ /// The main visual studio object.
+ /// </summary>
+ private DTE2 dte_;
+
+ /// <summary>
+ /// Holds the default properties from property pages to use during tests.
+ /// </summary>
+ private MockPropertyManager properties_;
+
+ /// <summary>
+ /// Gets or sets the test context which provides information about,
+ /// and functionality for the current test run.
+ /// </summary>
+ public TestContext TestContext { get; set; }
+
+ /// <summary>
+ /// This is run before each test to create test resources.
+ /// </summary>
+ [TestInitialize]
+ public void TestSetup()
+ {
+ dte_ = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
+ }
+ catch
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ throw;
+ }
+
+ // Set up mock property manager to return the desired property values.
+ properties_ = new MockPropertyManager(
+ PropertyManager.ProjectPlatformType.Pepper,
+ delegate(string page, string name)
+ {
+ switch (page)
+ {
+ case "ConfigurationGeneral":
+ switch (name)
+ {
+ case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
+ NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
+ }
+
+ break;
+ case "Property":
+ switch (name)
+ {
+ case "ProjectDirectory": return TestContext.DeploymentDirectory;
+ case "PluginAssembly": return @"fake\Assembly\String";
+ }
+
+ break;
+ }
+
+ return null;
+ },
+ null);
+ }
+
+ /// <summary>
+ /// This is run after each test to clean up things created in TestSetup().
+ /// </summary>
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ }
+
+ /// <summary>
+ /// A test for the constructor.
+ /// </summary>
+ [TestMethod]
+ public void PluginDebuggerVSConstructorTest()
+ {
+ // Check that a null dte fails.
+ try
+ {
+ PluginDebuggerBase nullDte = new PluginDebuggerVS(null, properties_);
+ Assert.Fail("Using null DTE instance did not throw exception");
+ }
+ catch (ArgumentNullException)
+ {
+ // This is expected for a correct implementation.
+ }
+ catch
+ {
+ Assert.Fail("Using null DTE instance threw something other than ArgumentNullException");
+ }
+
+ // Check that a null PropertyManager fails.
+ try
+ {
+ PluginDebuggerBase nullDte = new PluginDebuggerVS(dte_, null);
+ Assert.Fail("Using null property manager did not throw exception");
+ }
+ catch (ArgumentNullException)
+ {
+ // This is expected for a correct implementation.
+ }
+ catch
+ {
+ Assert.Fail("Using null property manager threw something other than ArgumentNullException");
+ }
+ }
+
+ /// <summary>
+ /// A test for FindAndAttachToPlugin.
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void FindAndAttachToPepperPluginTest()
+ {
+ MockProcessSearcher processResults = new MockProcessSearcher();
+
+ using (PluginDebuggerVS target = new PluginDebuggerVS(dte_, properties_))
+ {
+ PluginDebuggerBase_Accessor targetBase = new PluginDebuggerBase_Accessor(
+ new PrivateObject(target, new PrivateType(typeof(PluginDebuggerBase))));
+ targetBase.debuggedChromeMainProcess_ = System.Diagnostics.Process.GetCurrentProcess();
+ uint currentProcId = (uint)targetBase.debuggedChromeMainProcess_.Id;
+
+ string pluginLoadFlag = string.Format(
+ Strings.PepperProcessPluginFlagFormat, properties_.PluginAssembly);
+ string pepperCommandLine = string.Concat(
+ pluginLoadFlag, " ", Strings.ChromeRendererFlag);
+
+ // Fake the list of processes on the system.
+ processResults.ProcessList.Add(
+ new ProcessInfo(
+ currentProcId,
+ currentProcId,
+ string.Empty,
+ Strings.NaClDebugFlag,
+ Strings.ChromeProcessName));
+ processResults.ProcessList.Add(
+ new ProcessInfo(1, currentProcId, string.Empty, string.Empty, "MyParentProcess"));
+ processResults.ProcessList.Add(
+ new ProcessInfo(10, 1, string.Empty, pepperCommandLine, Strings.ChromeProcessName));
+
+ // This is missing some relevant command line args, and should not be attached to.
+ processResults.ProcessList.Add(
+ new ProcessInfo(12, 1, string.Empty, pluginLoadFlag, Strings.ChromeProcessName));
+
+ // This doesn't have this process as its parent, and should not be attached to.
+ processResults.ProcessList.Add(
+ new ProcessInfo(14, 14, string.Empty, pepperCommandLine, Strings.ChromeProcessName));
+
+ // Set the private value to the mock object (can't use accessor since no valid cast).
+ FieldInfo processSearcherField = typeof(PluginDebuggerBase).GetField(
+ "processSearcher_",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ processSearcherField.SetValue(targetBase.Target, processResults);
+
+ // Test that the correct processes are attached to.
+ bool goodPepper = false;
+ var handler = new EventHandler<NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs>(
+ delegate(object unused, NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs args)
+ {
+ switch (args.ProcessID)
+ {
+ case 10:
+ if (goodPepper)
+ {
+ Assert.Fail("Should not attach twice to same pepper process");
+ }
+
+ goodPepper = true;
+ break;
+ case 12:
+ Assert.Fail("Should not attach to pepper process with bad args");
+ break;
+ case 14:
+ Assert.Fail("Should not attach to pepper process that is not "
+ + "descendant of Visual Studio");
+ break;
+ default:
+ Assert.Fail("Should not attach to non-pepper/non-nacl process");
+ break;
+ }
+ });
+
+ target.PluginFoundEvent += handler;
+ target.FindAndAttachToPlugin(null, null);
+ target.PluginFoundEvent -= handler;
+
+ Assert.IsTrue(goodPepper, "Failed to attach to pepper process");
+ }
+ }
+
+ /// <summary>
+ /// Checks that VS properly attaches debugger.
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void AttachVSDebuggerTest()
+ {
+ using (System.Diagnostics.Process dummyProc = TestUtilities.StartProcessForKilling(
+ "DummyProc", 20))
+ {
+ try
+ {
+ PluginDebuggerVS_Accessor target = new PluginDebuggerVS_Accessor(dte_, properties_);
+
+ var pluginFoundArgs = new NativeClientVSAddIn.PluginDebuggerBase.PluginFoundEventArgs(
+ (uint)dummyProc.Id);
+ target.Attach(null, pluginFoundArgs);
+
+ bool isBeingDebugged = false;
+ foreach (EnvDTE.Process proc in dte_.Debugger.DebuggedProcesses)
+ {
+ if (proc.ProcessID == dummyProc.Id)
+ {
+ isBeingDebugged = true;
+ }
+ }
+
+ Assert.IsTrue(isBeingDebugged, "Visual Studio debugger did not attach");
+ }
+ finally
+ {
+ if (dummyProc != null && !dummyProc.HasExited)
+ {
+ dummyProc.Kill();
+ dummyProc.Dispose();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// A test for IsPluginProcess.
+ /// </summary>
+ [TestMethod]
+ [DeploymentItem("NativeClientVSAddIn.dll")]
+ public void IsPepperPluginProcessTest()
+ {
+ PluginDebuggerVS_Accessor target = new PluginDebuggerVS_Accessor(dte_, properties_);
+
+ string identifierFlagTarget =
+ string.Format(Strings.PepperProcessPluginFlagFormat, target.pluginAssembly_);
+ string goodFlags = string.Concat(Strings.ChromeRendererFlag, ' ', identifierFlagTarget);
+
+ ProcessInfo badProc1 = new ProcessInfo(
+ 1, 1, string.Empty, goodFlags, Strings.NaClProcessName);
+ ProcessInfo badProc2 = new ProcessInfo(
+ 1, 1, string.Empty, Strings.NaClLoaderFlag, Strings.ChromeProcessName);
+ ProcessInfo badProc3 = new ProcessInfo(
+ 1, 1, string.Empty, Strings.ChromeRendererFlag, Strings.ChromeProcessName);
+ ProcessInfo badProc4 = new ProcessInfo(
+ 1, 1, string.Empty, identifierFlagTarget, Strings.ChromeProcessName);
+ ProcessInfo goodProc = new ProcessInfo(
+ 1, 1, string.Empty, goodFlags, Strings.ChromeProcessName);
+
+ Assert.IsTrue(target.IsPluginProcess(goodProc, string.Empty));
+ Assert.IsFalse(target.IsPluginProcess(badProc1, string.Empty));
+ Assert.IsFalse(target.IsPluginProcess(badProc2, string.Empty));
+ Assert.IsFalse(target.IsPluginProcess(badProc3, string.Empty));
+ Assert.IsFalse(target.IsPluginProcess(badProc4, string.Empty));
+ }
+ }
+}
diff --git a/UnitTests/Properties/AssemblyInfo.cs b/UnitTests/Properties/AssemblyInfo.cs
index de91dbf..699de28 100644
--- a/UnitTests/Properties/AssemblyInfo.cs
+++ b/UnitTests/Properties/AssemblyInfo.cs
@@ -1,39 +1,39 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("UnitTests")]
-[assembly: AssemblyDescription("Unit tests for the Native Client Visual Studio Add-in")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Google Inc.")]
-[assembly: AssemblyProduct("UnitTests")]
-[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM.
-[assembly: Guid("01a004dc-ebdc-47db-91cf-ba8ec4480c48")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("UnitTests")]
+[assembly: AssemblyDescription("Unit tests for the Native Client Visual Studio Add-in")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Google Inc.")]
+[assembly: AssemblyProduct("UnitTests")]
+[assembly: AssemblyCopyright("Copyright © 2012 The Chromium Authors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM.
+[assembly: Guid("01a004dc-ebdc-47db-91cf-ba8ec4480c48")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/UnitTests/PropertyManagerTest.cs b/UnitTests/PropertyManagerTest.cs
index 05b1297..4c701ad 100644
--- a/UnitTests/PropertyManagerTest.cs
+++ b/UnitTests/PropertyManagerTest.cs
@@ -1,237 +1,237 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
- using System.IO;
-
- using EnvDTE;
- using EnvDTE80;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- using NativeClientVSAddIn;
-
- /// <summary>
- /// This is a test class for PropertyManagerTest and is intended
- /// to contain all PropertyManager Unit Tests
- /// </summary>
- [TestClass]
- public class PropertyManagerTest
- {
- /// <summary>
- /// This holds the path to the NaCl solution used in these tests.
- /// The NaCl solution is a valid nacl/pepper plug-in VS solution.
- /// It is copied into the testing deployment directory and opened in some tests.
- /// Because unit-tests run in any order, the solution should not be written to
- /// in any tests.
- /// </summary>
- private static string naclSolution;
-
- /// <summary>
- /// The main visual studio object.
- /// </summary>
- private DTE2 dte_;
-
- /// <summary>
- /// Gets or sets the test context which provides information about,
- /// and functionality for the current test run.
- /// </summary>
- public TestContext TestContext { get; set; }
-
- /// <summary>
- /// This is run one time before any test methods are called. Here we set-up a test-copy of a
- /// new NaCl solution for use in the tests.
- /// </summary>
- /// <param name="testContext">Holds information about the current test run</param>
- [ClassInitialize]
- public static void ClassSetup(TestContext testContext)
- {
- DTE2 dte = TestUtilities.StartVisualStudioInstance();
- try
- {
- naclSolution = TestUtilities.CreateBlankValidNaClSolution(
- dte,
- "PropertyManagerTest",
- NativeClientVSAddIn.Strings.PepperPlatformName,
- NativeClientVSAddIn.Strings.NaClPlatformName,
- testContext);
- }
- finally
- {
- TestUtilities.CleanUpVisualStudioInstance(dte);
- }
- }
-
- /// <summary>
- /// This is run before each test to create test resources.
- /// </summary>
- [TestInitialize]
- public void TestSetup()
- {
- dte_ = TestUtilities.StartVisualStudioInstance();
- try
- {
- TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
- }
- catch
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- throw;
- }
- }
-
- /// <summary>
- /// This is run after each test to clean up things created in TestSetup().
- /// </summary>
- [TestCleanup]
- public void TestCleanup()
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- }
-
- /// <summary>
- /// Tests SetTarget() and SetTargetToActive().
- /// </summary>
- [TestMethod]
- public void SetTargetTest()
- {
- string expectedSDKRootDir =
- Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable);
- Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not set!");
-
- PropertyManager target = new PropertyManager();
- dte_.Solution.Open(naclSolution);
-
- Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
- Project notNacl = dte_.Solution.Projects.Item(TestUtilities.NotNaClProjectUniqueName);
-
- // Invalid project.
- target.SetTarget(notNacl, Strings.PepperPlatformName, "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.Other,
- target.ProjectPlatform,
- "SetTarget should not succeed with non-nacl/pepper project.");
-
- // Try valid project with different platforms.
- target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.NaCl,
- target.ProjectPlatform,
- "SetTarget did not succeed with nacl platform on valid project.");
- Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
-
- target.SetTarget(naclProject, "Win32", "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.Other,
- target.ProjectPlatform,
- "SetTarget did not set 'other' platform on when Win32 platform of valid project.");
-
- target.SetTarget(naclProject, Strings.PepperPlatformName, "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.Pepper,
- target.ProjectPlatform,
- "SetTarget did not succeed with pepper platform on valid project.");
- Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
-
- // Setting the start-up project to a non-cpp project should make loading fail.
- object[] badStartupProj = { TestUtilities.NotNaClProjectUniqueName };
- dte_.Solution.SolutionBuild.StartupProjects = badStartupProj;
- target.SetTargetToActive(dte_);
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.Other,
- target.ProjectPlatform,
- "SetTargetToActive should not succeed with non-nacl/pepper project.");
-
- // Setting the start-up project to correct C++ project, but also setting the platform
- // to non-nacl/pepper should make loading fail.
- object[] startupProj = { TestUtilities.BlankNaClProjectUniqueName };
- dte_.Solution.SolutionBuild.StartupProjects = startupProj;
- TestUtilities.SetSolutionConfiguration(
- dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", "Win32");
- target.SetTargetToActive(dte_);
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.Other,
- target.ProjectPlatform,
- "SetTargetToActive should not succeed with Win32 platform.");
-
- // Now setting the platform to NaCl should make this succeed.
- TestUtilities.SetSolutionConfiguration(
- dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", Strings.NaClPlatformName);
- target.SetTargetToActive(dte_);
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.NaCl,
- target.ProjectPlatform,
- "SetTargetToActive should succeed with NaCl platform and valid project.");
- Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
- }
-
- /// <summary>
- /// A test for GetProperty. Checks some non-trivial C# properties and the GetProperty method.
- /// </summary>
- [TestMethod]
- public void GetPropertyTest()
- {
- string expectedSDKRootDir =
- Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable);
- Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not set!");
-
- // Set up the property manager to read the NaCl platform settings from BlankValidSolution.
- PropertyManager target = new PropertyManager();
- dte_.Solution.Open(naclSolution);
- Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
- target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.NaCl,
- target.ProjectPlatform,
- "SetTarget did not succeed with nacl platform on valid project.");
-
- string projectDir = Path.Combine(
- Path.GetDirectoryName(naclSolution),
- Path.GetDirectoryName(TestUtilities.BlankNaClProjectUniqueName)) + @"\";
- string outputDir = Path.Combine(projectDir, "newlib") + @"\";
- string assembly = Path.Combine(outputDir, TestUtilities.BlankNaClProjectName + ".nexe");
-
- Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root.");
- Assert.AreEqual(projectDir, target.ProjectDirectory, "ProjectDirectory.");
- Assert.AreEqual(outputDir, target.OutputDirectory, "OutputDirectory.");
- Assert.AreEqual(assembly, target.PluginAssembly, "PluginAssembly.");
- Assert.AreEqual(
- @"newlib",
- target.GetProperty("ConfigurationGeneral", "ToolchainName"),
- "GetProperty() with ToolchainName incorrect.");
- }
-
- /// <summary>
- /// A test for SetProperty.
- /// </summary>
- [TestMethod]
- public void SetPropertyTest()
- {
- string setTargetSolution = TestUtilities.CreateBlankValidNaClSolution(
- dte_,
- "PropertyManagerTestSetTarget",
- NativeClientVSAddIn.Strings.NaClPlatformName,
- NativeClientVSAddIn.Strings.NaClPlatformName,
- TestContext);
-
- // Set up the property manager to read the NaCl platform settings from BlankValidSolution.
- PropertyManager target = new PropertyManager();
- dte_.Solution.Open(setTargetSolution);
- Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
- target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
- Assert.AreEqual(
- PropertyManager.ProjectPlatformType.NaCl,
- target.ProjectPlatform,
- "SetTarget did not succeed with nacl platform on valid project.");
-
- string newValue = "ThisIsNew";
- target.SetProperty("ConfigurationGeneral", "VSNaClSDKRoot", newValue);
- Assert.AreEqual(
- newValue,
- target.GetProperty("ConfigurationGeneral", "VSNaClSDKRoot"),
- "SetProperty() did not set property VSNaClSDKRoot.");
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+ using System.IO;
+
+ using EnvDTE;
+ using EnvDTE80;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using NativeClientVSAddIn;
+
+ /// <summary>
+ /// This is a test class for PropertyManagerTest and is intended
+ /// to contain all PropertyManager Unit Tests
+ /// </summary>
+ [TestClass]
+ public class PropertyManagerTest
+ {
+ /// <summary>
+ /// This holds the path to the NaCl solution used in these tests.
+ /// The NaCl solution is a valid nacl/pepper plug-in VS solution.
+ /// It is copied into the testing deployment directory and opened in some tests.
+ /// Because unit-tests run in any order, the solution should not be written to
+ /// in any tests.
+ /// </summary>
+ private static string naclSolution;
+
+ /// <summary>
+ /// The main visual studio object.
+ /// </summary>
+ private DTE2 dte_;
+
+ /// <summary>
+ /// Gets or sets the test context which provides information about,
+ /// and functionality for the current test run.
+ /// </summary>
+ public TestContext TestContext { get; set; }
+
+ /// <summary>
+ /// This is run one time before any test methods are called. Here we set-up a test-copy of a
+ /// new NaCl solution for use in the tests.
+ /// </summary>
+ /// <param name="testContext">Holds information about the current test run</param>
+ [ClassInitialize]
+ public static void ClassSetup(TestContext testContext)
+ {
+ DTE2 dte = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ naclSolution = TestUtilities.CreateBlankValidNaClSolution(
+ dte,
+ "PropertyManagerTest",
+ NativeClientVSAddIn.Strings.PepperPlatformName,
+ NativeClientVSAddIn.Strings.NaClPlatformName,
+ testContext);
+ }
+ finally
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte);
+ }
+ }
+
+ /// <summary>
+ /// This is run before each test to create test resources.
+ /// </summary>
+ [TestInitialize]
+ public void TestSetup()
+ {
+ dte_ = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
+ }
+ catch
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// This is run after each test to clean up things created in TestSetup().
+ /// </summary>
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ }
+
+ /// <summary>
+ /// Tests SetTarget() and SetTargetToActive().
+ /// </summary>
+ [TestMethod]
+ public void SetTargetTest()
+ {
+ string expectedSDKRootDir =
+ Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable);
+ Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not set!");
+
+ PropertyManager target = new PropertyManager();
+ dte_.Solution.Open(naclSolution);
+
+ Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
+ Project notNacl = dte_.Solution.Projects.Item(TestUtilities.NotNaClProjectUniqueName);
+
+ // Invalid project.
+ target.SetTarget(notNacl, Strings.PepperPlatformName, "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.Other,
+ target.ProjectPlatform,
+ "SetTarget should not succeed with non-nacl/pepper project.");
+
+ // Try valid project with different platforms.
+ target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.NaCl,
+ target.ProjectPlatform,
+ "SetTarget did not succeed with nacl platform on valid project.");
+ Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
+
+ target.SetTarget(naclProject, "Win32", "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.Other,
+ target.ProjectPlatform,
+ "SetTarget did not set 'other' platform on when Win32 platform of valid project.");
+
+ target.SetTarget(naclProject, Strings.PepperPlatformName, "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.Pepper,
+ target.ProjectPlatform,
+ "SetTarget did not succeed with pepper platform on valid project.");
+ Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
+
+ // Setting the start-up project to a non-cpp project should make loading fail.
+ object[] badStartupProj = { TestUtilities.NotNaClProjectUniqueName };
+ dte_.Solution.SolutionBuild.StartupProjects = badStartupProj;
+ target.SetTargetToActive(dte_);
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.Other,
+ target.ProjectPlatform,
+ "SetTargetToActive should not succeed with non-nacl/pepper project.");
+
+ // Setting the start-up project to correct C++ project, but also setting the platform
+ // to non-nacl/pepper should make loading fail.
+ object[] startupProj = { TestUtilities.BlankNaClProjectUniqueName };
+ dte_.Solution.SolutionBuild.StartupProjects = startupProj;
+ TestUtilities.SetSolutionConfiguration(
+ dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", "Win32");
+ target.SetTargetToActive(dte_);
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.Other,
+ target.ProjectPlatform,
+ "SetTargetToActive should not succeed with Win32 platform.");
+
+ // Now setting the platform to NaCl should make this succeed.
+ TestUtilities.SetSolutionConfiguration(
+ dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", Strings.NaClPlatformName);
+ target.SetTargetToActive(dte_);
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.NaCl,
+ target.ProjectPlatform,
+ "SetTargetToActive should succeed with NaCl platform and valid project.");
+ Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root incorrect.");
+ }
+
+ /// <summary>
+ /// A test for GetProperty. Checks some non-trivial C# properties and the GetProperty method.
+ /// </summary>
+ [TestMethod]
+ public void GetPropertyTest()
+ {
+ string expectedSDKRootDir =
+ Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable);
+ Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not set!");
+
+ // Set up the property manager to read the NaCl platform settings from BlankValidSolution.
+ PropertyManager target = new PropertyManager();
+ dte_.Solution.Open(naclSolution);
+ Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
+ target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.NaCl,
+ target.ProjectPlatform,
+ "SetTarget did not succeed with nacl platform on valid project.");
+
+ string projectDir = Path.Combine(
+ Path.GetDirectoryName(naclSolution),
+ Path.GetDirectoryName(TestUtilities.BlankNaClProjectUniqueName)) + @"\";
+ string outputDir = Path.Combine(projectDir, "newlib") + @"\";
+ string assembly = Path.Combine(outputDir, TestUtilities.BlankNaClProjectName + ".nexe");
+
+ Assert.AreEqual(expectedSDKRootDir, target.SDKRootDirectory, "SDK Root.");
+ Assert.AreEqual(projectDir, target.ProjectDirectory, "ProjectDirectory.");
+ Assert.AreEqual(outputDir, target.OutputDirectory, "OutputDirectory.");
+ Assert.AreEqual(assembly, target.PluginAssembly, "PluginAssembly.");
+ Assert.AreEqual(
+ @"newlib",
+ target.GetProperty("ConfigurationGeneral", "ToolchainName"),
+ "GetProperty() with ToolchainName incorrect.");
+ }
+
+ /// <summary>
+ /// A test for SetProperty.
+ /// </summary>
+ [TestMethod]
+ public void SetPropertyTest()
+ {
+ string setTargetSolution = TestUtilities.CreateBlankValidNaClSolution(
+ dte_,
+ "PropertyManagerTestSetTarget",
+ NativeClientVSAddIn.Strings.NaClPlatformName,
+ NativeClientVSAddIn.Strings.NaClPlatformName,
+ TestContext);
+
+ // Set up the property manager to read the NaCl platform settings from BlankValidSolution.
+ PropertyManager target = new PropertyManager();
+ dte_.Solution.Open(setTargetSolution);
+ Project naclProject = dte_.Solution.Projects.Item(TestUtilities.BlankNaClProjectUniqueName);
+ target.SetTarget(naclProject, Strings.NaClPlatformName, "Debug");
+ Assert.AreEqual(
+ PropertyManager.ProjectPlatformType.NaCl,
+ target.ProjectPlatform,
+ "SetTarget did not succeed with nacl platform on valid project.");
+
+ string newValue = "ThisIsNew";
+ target.SetProperty("ConfigurationGeneral", "VSNaClSDKRoot", newValue);
+ Assert.AreEqual(
+ newValue,
+ target.GetProperty("ConfigurationGeneral", "VSNaClSDKRoot"),
+ "SetProperty() did not set property VSNaClSDKRoot.");
+ }
+ }
+}
diff --git a/UnitTests/TestUtilities.cs b/UnitTests/TestUtilities.cs
index 788a7a0..20a78dd 100644
--- a/UnitTests/TestUtilities.cs
+++ b/UnitTests/TestUtilities.cs
@@ -1,463 +1,463 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Management;
-
- using EnvDTE;
- using EnvDTE80;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using Microsoft.VisualStudio.VCProjectEngine;
-
- /// <summary>
- /// This class contains utilities for running tests.
- /// </summary>
- public static class TestUtilities
- {
- /// <summary>
- /// Name of the NaCl project in BlankValidSolution.
- /// </summary>
- public const string BlankNaClProjectName = @"NaClProject";
-
- /// <summary>
- /// Uniquename of the NaCl project in BlankValidSolution.
- /// </summary>
- public const string BlankNaClProjectUniqueName = @"NaClProject\NaClProject.vcxproj";
-
- /// <summary>
- /// Uniquename of the non-NaCl project in BlankValidSolution.
- /// </summary>
- public const string NotNaClProjectUniqueName = @"NotNaCl\NotNaCl.csproj";
-
- /// <summary>
- /// A generic boolean statement to be used with RetryWithTimeout.
- /// </summary>
- /// <returns>True if the statement is true, false if false.</returns>
- public delegate bool RetryStatement();
-
- /// <summary>
- /// This starts an instance of Visual Studio and get its DTE object.
- /// </summary>
- /// <returns>DTE of the started instance.</returns>
- public static DTE2 StartVisualStudioInstance()
- {
- // Set up filter to handle threading events and automatically retry calls
- // to dte which fail because dte is busy.
- ComMessageFilter.Register();
-
- Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
- DTE2 visualStudio = Activator.CreateInstance(visualStudioType) as DTE2;
- if (visualStudio == null)
- {
- throw new Exception("Visual Studio failed to start");
- }
-
- visualStudio.MainWindow.Visible = true;
- return visualStudio;
- }
-
- /// <summary>
- /// This properly cleans up after StartVisualStudioInstance().
- /// </summary>
- /// <param name="dte">Dte instance returned by StartVisualStudioInstance().</param>
- public static void CleanUpVisualStudioInstance(DTE2 dte)
- {
- if (dte != null)
- {
- if (dte.Solution != null)
- {
- dte.Solution.Close();
- }
-
- dte.Quit();
- }
-
- // Stop the message filter.
- ComMessageFilter.Revoke();
- }
-
- /// <summary>
- /// Creates a blank valid NaCl project with up-to-date settings. The path to the new solution
- /// is returned.
- /// </summary>
- /// <param name="dte">Interface to an open Visual Studio instance to use.</param>
- /// <param name="name">Name to give newly created solution.</param>
- /// <param name="pepperCopyFrom">Platform name to copy existing settings from to pepper.</param>
- /// <param name="naclCopyFrom">Platform name to copy existing settings from to NaCl.</param>
- /// <param name="testContext">Test context used for finding deployment directory.</param>
- /// <returns>Path to the newly created solution.</returns>
- public static string CreateBlankValidNaClSolution(
- DTE2 dte, string name, string pepperCopyFrom, string naclCopyFrom, TestContext testContext)
- {
- const string BlankSolution = "BlankValidSolution";
- string newSolutionDir = Path.Combine(testContext.DeploymentDirectory, name);
- string newSolution = Path.Combine(newSolutionDir, BlankSolution + ".sln");
- CopyDirectory(Path.Combine(testContext.DeploymentDirectory, BlankSolution), newSolutionDir);
-
- try
- {
- dte.Solution.Open(newSolution);
- Project proj = dte.Solution.Projects.Item(BlankNaClProjectUniqueName);
-
- // Order matters if copying from the other Native Client type.
- if (pepperCopyFrom.Equals(NativeClientVSAddIn.Strings.NaClPlatformName))
- {
- proj.ConfigurationManager.AddPlatform(
- NativeClientVSAddIn.Strings.NaClPlatformName, naclCopyFrom, true);
- proj.ConfigurationManager.AddPlatform(
- NativeClientVSAddIn.Strings.PepperPlatformName, pepperCopyFrom, true);
- }
- else
- {
- proj.ConfigurationManager.AddPlatform(
- NativeClientVSAddIn.Strings.PepperPlatformName, pepperCopyFrom, true);
- proj.ConfigurationManager.AddPlatform(
- NativeClientVSAddIn.Strings.NaClPlatformName, naclCopyFrom, true);
- }
-
- // Set the active solution configuration to Debug|NaCl.
- SetSolutionConfiguration(
- dte, BlankNaClProjectUniqueName, "Debug", NativeClientVSAddIn.Strings.NaClPlatformName);
-
- proj.Save();
- dte.Solution.SaveAs(newSolution);
- }
- finally
- {
- if (dte.Solution != null)
- {
- dte.Solution.Close();
- }
- }
-
- return newSolution;
- }
-
- /// <summary>
- /// This returns the text contained in the given output window pane.
- /// </summary>
- /// <param name="pane">Pane to get text from.</param>
- /// <returns>Text in the window.</returns>
- public static string GetPaneText(OutputWindowPane pane)
- {
- TextSelection selection = pane.TextDocument.Selection;
- selection.StartOfDocument(false);
- selection.EndOfDocument(true);
- return selection.Text;
- }
-
- /// <summary>
- /// This starts a python process that just sleeps waiting to be killed.
- /// It can be used with DoesProcessExist() to verify that a process started/exited.
- /// </summary>
- /// <param name="identifierString">
- /// A unique string to identify the process via its command line arguments.
- /// </param>
- /// <param name="timeout">Time in seconds to wait before process exits on its own.</param>
- /// <returns>The process object that was started.</returns>
- public static System.Diagnostics.Process StartProcessForKilling(
- string identifierString, int timeout)
- {
- string args = string.Format(
- "-c \"import time; time.sleep({0}); print '{1}'\"",
- timeout,
- identifierString);
- System.Diagnostics.Process proc = new System.Diagnostics.Process();
- proc.StartInfo.CreateNoWindow = true;
- proc.StartInfo.UseShellExecute = false;
- proc.StartInfo.FileName = "python.exe";
- proc.StartInfo.Arguments = args;
- proc.Start();
- return proc;
- }
-
- /// <summary>
- /// This returns true if there is a running process that has command line arguments
- /// containing the given Strings. The search is case-insensitive.
- /// </summary>
- /// <param name="processName">Name of the process executable.</param>
- /// <param name="commandLineIdentifiers">Strings to check for.</param>
- /// <returns>True if some process has the Strings in its command line arguments.</returns>
- public static bool DoesProcessExist(string processName, params string[] commandLineIdentifiers)
- {
- List<string> results = new List<string>();
- string query =
- string.Format("select CommandLine from Win32_Process where Name='{0}'", processName);
- using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
- {
- using (ManagementObjectCollection result = searcher.Get())
- {
- foreach (ManagementObject process in result)
- {
- string commandLine = process["CommandLine"] as string;
- if (string.IsNullOrEmpty(commandLine))
- {
- break;
- }
-
- // Check if the command line contains each of the required identifiers.
- if (commandLineIdentifiers.All(i => commandLine.Contains(i)))
- {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- /// <summary>
- /// Sets the active configuration for the solution by specifying the configuration name
- /// and platform name. A solution configuration containing a project configuration that has
- /// the config and platform names specified for the specified project is selected.
- /// </summary>
- /// <param name="dte">The main visual studio object.</param>
- /// <param name="projectUniqueName">UniqueName of the project to match.</param>
- /// <param name="configurationName">Ex: "Debug" or "Release".</param>
- /// <param name="platformName">Ex: "Win32" or "NaCl" or "PPAPI".</param>
- public static void SetSolutionConfiguration(
- DTE2 dte,
- string projectUniqueName,
- string configurationName,
- string platformName)
- {
- foreach (EnvDTE.SolutionConfiguration config in
- dte.Solution.SolutionBuild.SolutionConfigurations)
- {
- EnvDTE.SolutionContext context = null;
- try
- {
- context = config.SolutionContexts.Item(projectUniqueName);
- }
- catch (ArgumentException)
- {
- throw new Exception(
- string.Format("Project unique name not found in solution: {0}", projectUniqueName));
- }
-
- if (context == null)
- {
- throw new Exception("Failed to get solution context");
- }
-
- if (context.PlatformName == platformName && context.ConfigurationName == configurationName)
- {
- config.Activate();
- return;
- }
- }
-
- throw new Exception(string.Format(
- "Matching configuration not found for {0}: {1}|{2}",
- projectUniqueName,
- platformName,
- configurationName));
- }
-
- /// <summary>
- /// Returns a VCConfiguration object with a matching configuration name and platform type.
- /// </summary>
- /// <param name="project">Project to get the configuration from.</param>
- /// <param name="name">Name of configuration (e.g. 'Debug').</param>
- /// <param name="platform">Name of the platform (e.g. 'NaCl').</param>
- /// <returns>A matching VCConfiguration object.</returns>
- public static VCConfiguration GetVCConfiguration(Project project, string name, string platform)
- {
- VCProject vcproj = (VCProject)project.Object;
- IVCCollection configs = vcproj.Configurations;
-
- foreach (VCConfiguration config in configs)
- {
- if (config.ConfigurationName == name && config.Platform.Name == platform)
- {
- return config;
- }
- }
-
- throw new Exception(
- string.Format("Project does not have configuration: {0}|{1}", platform, name));
- }
-
- /// <summary>
- /// Tests that a given property has a specific value in a certain VCConfiguration
- /// </summary>
- /// <param name="configuration">Gives the platform and configuration type</param>
- /// <param name="pageName">Property page name where property resides.</param>
- /// <param name="propertyName">Name of the property to check.</param>
- /// <param name="expectedValue">Expected value of the property.</param>
- /// <param name="ignoreCase">Ignore case when comparing the expected and actual values.</param>
- public static void AssertPropertyEquals(
- VCConfiguration configuration,
- string pageName,
- string propertyName,
- string expectedValue,
- bool ignoreCase)
- {
- IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
- string callInfo = string.Format(
- "Page: {0}, Property: {1}, Configuration: {2}",
- pageName,
- propertyName,
- configuration.ConfigurationName);
-
- Assert.AreEqual(
- expectedValue,
- rule.GetUnevaluatedPropertyValue(propertyName),
- ignoreCase,
- callInfo);
- }
-
- /// <summary>
- /// Tests that a given property contains a specific string in a certain VCConfiguration
- /// </summary>
- /// <param name="configuration">Gives the platform and configuration type</param>
- /// <param name="pageName">Property page name where property resides.</param>
- /// <param name="propertyName">Name of the property to check.</param>
- /// <param name="expectedValue">Expected string to contain.</param>
- /// <param name="ignoreCase">Ignore case when comparing the expected and actual values.</param>
- public static void AssertPropertyContains(
- VCConfiguration configuration,
- string pageName,
- string propertyName,
- string expectedValue,
- bool ignoreCase)
- {
- StringComparison caseSensitive = ignoreCase ?
- StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
-
- IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
- string propertyValue = rule.GetUnevaluatedPropertyValue(propertyName);
-
- string message = string.Format(
- "{0} should be contained in {1}. Page: {2}, Property: {3}, Configuration: {4}",
- expectedValue,
- propertyValue,
- pageName,
- propertyName,
- configuration.ConfigurationName);
-
- Assert.IsTrue(propertyValue.Contains(expectedValue, caseSensitive), message);
- }
-
- /// <summary>
- /// Tests that a given property is not null or empty.
- /// </summary>
- /// <param name="configuration">Gives the platform and configuration type</param>
- /// <param name="pageName">Property page name where property resides.</param>
- /// <param name="propertyName">Name of the property to check.</param>
- public static void AssertPropertyIsNotNullOrEmpty(
- VCConfiguration configuration,
- string pageName,
- string propertyName)
- {
- IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
- string propertyValue = rule.GetUnevaluatedPropertyValue(propertyName);
-
- string message = string.Format(
- "{0} was null or empty. Page: {1}, Configuration: {2}",
- propertyName,
- pageName,
- configuration.ConfigurationName);
-
- Assert.IsFalse(string.IsNullOrEmpty(propertyValue), message);
- }
-
- /// <summary>
- /// Ensures that the add-in is configured to load on start. If it isn't then some tests may
- /// unexpectedly fail, this check helps catch that problem early.
- /// </summary>
- /// <param name="dte">The main Visual Studio interface.</param>
- /// <param name="addInName">The name of the add-in to check if loaded.</param>
- public static void AssertAddinLoaded(DTE2 dte, string addInName)
- {
- bool found = false;
- foreach (AddIn addin in dte.AddIns)
- {
- if (addin.Connected && addInName.Equals(addin.Name))
- {
- found = true;
- break;
- }
- }
-
- Assert.IsTrue(found, "Add-in is not configured to load on start.");
- }
-
- /// <summary>
- /// Will retry the given statement up to maxRetry times while pausing between each try for
- /// the given interval.
- /// </summary>
- /// <param name="test">Generic boolean statement.</param>
- /// <param name="interval">Amount of time to wait between each retry.</param>
- /// <param name="maxRetry">Maximum number of retries.</param>
- /// <param name="message">Message to print on failure.</param>
- public static void AssertTrueWithTimeout(
- RetryStatement test, TimeSpan interval, int maxRetry, string message)
- {
- for (int tryCount = 0; tryCount <= maxRetry; tryCount++)
- {
- if (test.Invoke())
- {
- return;
- }
-
- System.Threading.Thread.Sleep(interval);
- }
-
- throw new Exception(string.Format("Statement timed out. {0}", message));
- }
-
- /// <summary>
- /// Extends the string class to allow checking if a string contains another string
- /// allowing a comparison type (such as case-insensitivity).
- /// </summary>
- /// <param name="source">Base string to search.</param>
- /// <param name="toCheck">String to check if contained within base string.</param>
- /// <param name="comparison">Comparison type.</param>
- /// <returns>True if toCheck is contained in source.</returns>
- public static bool Contains(this string source, string toCheck, StringComparison comparison)
- {
- return source.IndexOf(toCheck, comparison) != -1;
- }
-
- /// <summary>
- /// Copies the entire contents of a directory and sub directories.
- /// </summary>
- /// <param name="source">Directory to copy from.</param>
- /// <param name="dest">Directory to copy to.</param>
- public static void CopyDirectory(string source, string dest)
- {
- DirectoryInfo dir = new DirectoryInfo(source);
-
- if (!dir.Exists)
- {
- throw new DirectoryNotFoundException(source);
- }
-
- if (!Directory.Exists(dest))
- {
- Directory.CreateDirectory(dest);
- }
-
- FileInfo[] files = dir.GetFiles();
- foreach (FileInfo file in files)
- {
- string path = Path.Combine(dest, file.Name);
- file.CopyTo(path, false);
- }
-
- foreach (DirectoryInfo subdir in dir.GetDirectories())
- {
- string path = Path.Combine(dest, subdir.Name);
- CopyDirectory(subdir.FullName, path);
- }
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Management;
+
+ using EnvDTE;
+ using EnvDTE80;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Microsoft.VisualStudio.VCProjectEngine;
+
+ /// <summary>
+ /// This class contains utilities for running tests.
+ /// </summary>
+ public static class TestUtilities
+ {
+ /// <summary>
+ /// Name of the NaCl project in BlankValidSolution.
+ /// </summary>
+ public const string BlankNaClProjectName = @"NaClProject";
+
+ /// <summary>
+ /// Uniquename of the NaCl project in BlankValidSolution.
+ /// </summary>
+ public const string BlankNaClProjectUniqueName = @"NaClProject\NaClProject.vcxproj";
+
+ /// <summary>
+ /// Uniquename of the non-NaCl project in BlankValidSolution.
+ /// </summary>
+ public const string NotNaClProjectUniqueName = @"NotNaCl\NotNaCl.csproj";
+
+ /// <summary>
+ /// A generic boolean statement to be used with RetryWithTimeout.
+ /// </summary>
+ /// <returns>True if the statement is true, false if false.</returns>
+ public delegate bool RetryStatement();
+
+ /// <summary>
+ /// This starts an instance of Visual Studio and get its DTE object.
+ /// </summary>
+ /// <returns>DTE of the started instance.</returns>
+ public static DTE2 StartVisualStudioInstance()
+ {
+ // Set up filter to handle threading events and automatically retry calls
+ // to dte which fail because dte is busy.
+ ComMessageFilter.Register();
+
+ Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
+ DTE2 visualStudio = Activator.CreateInstance(visualStudioType) as DTE2;
+ if (visualStudio == null)
+ {
+ throw new Exception("Visual Studio failed to start");
+ }
+
+ visualStudio.MainWindow.Visible = true;
+ return visualStudio;
+ }
+
+ /// <summary>
+ /// This properly cleans up after StartVisualStudioInstance().
+ /// </summary>
+ /// <param name="dte">Dte instance returned by StartVisualStudioInstance().</param>
+ public static void CleanUpVisualStudioInstance(DTE2 dte)
+ {
+ if (dte != null)
+ {
+ if (dte.Solution != null)
+ {
+ dte.Solution.Close();
+ }
+
+ dte.Quit();
+ }
+
+ // Stop the message filter.
+ ComMessageFilter.Revoke();
+ }
+
+ /// <summary>
+ /// Creates a blank valid NaCl project with up-to-date settings. The path to the new solution
+ /// is returned.
+ /// </summary>
+ /// <param name="dte">Interface to an open Visual Studio instance to use.</param>
+ /// <param name="name">Name to give newly created solution.</param>
+ /// <param name="pepperCopyFrom">Platform name to copy existing settings from to pepper.</param>
+ /// <param name="naclCopyFrom">Platform name to copy existing settings from to NaCl.</param>
+ /// <param name="testContext">Test context used for finding deployment directory.</param>
+ /// <returns>Path to the newly created solution.</returns>
+ public static string CreateBlankValidNaClSolution(
+ DTE2 dte, string name, string pepperCopyFrom, string naclCopyFrom, TestContext testContext)
+ {
+ const string BlankSolution = "BlankValidSolution";
+ string newSolutionDir = Path.Combine(testContext.DeploymentDirectory, name);
+ string newSolution = Path.Combine(newSolutionDir, BlankSolution + ".sln");
+ CopyDirectory(Path.Combine(testContext.DeploymentDirectory, BlankSolution), newSolutionDir);
+
+ try
+ {
+ dte.Solution.Open(newSolution);
+ Project proj = dte.Solution.Projects.Item(BlankNaClProjectUniqueName);
+
+ // Order matters if copying from the other Native Client type.
+ if (pepperCopyFrom.Equals(NativeClientVSAddIn.Strings.NaClPlatformName))
+ {
+ proj.ConfigurationManager.AddPlatform(
+ NativeClientVSAddIn.Strings.NaClPlatformName, naclCopyFrom, true);
+ proj.ConfigurationManager.AddPlatform(
+ NativeClientVSAddIn.Strings.PepperPlatformName, pepperCopyFrom, true);
+ }
+ else
+ {
+ proj.ConfigurationManager.AddPlatform(
+ NativeClientVSAddIn.Strings.PepperPlatformName, pepperCopyFrom, true);
+ proj.ConfigurationManager.AddPlatform(
+ NativeClientVSAddIn.Strings.NaClPlatformName, naclCopyFrom, true);
+ }
+
+ // Set the active solution configuration to Debug|NaCl.
+ SetSolutionConfiguration(
+ dte, BlankNaClProjectUniqueName, "Debug", NativeClientVSAddIn.Strings.NaClPlatformName);
+
+ proj.Save();
+ dte.Solution.SaveAs(newSolution);
+ }
+ finally
+ {
+ if (dte.Solution != null)
+ {
+ dte.Solution.Close();
+ }
+ }
+
+ return newSolution;
+ }
+
+ /// <summary>
+ /// This returns the text contained in the given output window pane.
+ /// </summary>
+ /// <param name="pane">Pane to get text from.</param>
+ /// <returns>Text in the window.</returns>
+ public static string GetPaneText(OutputWindowPane pane)
+ {
+ TextSelection selection = pane.TextDocument.Selection;
+ selection.StartOfDocument(false);
+ selection.EndOfDocument(true);
+ return selection.Text;
+ }
+
+ /// <summary>
+ /// This starts a python process that just sleeps waiting to be killed.
+ /// It can be used with DoesProcessExist() to verify that a process started/exited.
+ /// </summary>
+ /// <param name="identifierString">
+ /// A unique string to identify the process via its command line arguments.
+ /// </param>
+ /// <param name="timeout">Time in seconds to wait before process exits on its own.</param>
+ /// <returns>The process object that was started.</returns>
+ public static System.Diagnostics.Process StartProcessForKilling(
+ string identifierString, int timeout)
+ {
+ string args = string.Format(
+ "-c \"import time; time.sleep({0}); print '{1}'\"",
+ timeout,
+ identifierString);
+ System.Diagnostics.Process proc = new System.Diagnostics.Process();
+ proc.StartInfo.CreateNoWindow = true;
+ proc.StartInfo.UseShellExecute = false;
+ proc.StartInfo.FileName = "python.exe";
+ proc.StartInfo.Arguments = args;
+ proc.Start();
+ return proc;
+ }
+
+ /// <summary>
+ /// This returns true if there is a running process that has command line arguments
+ /// containing the given Strings. The search is case-insensitive.
+ /// </summary>
+ /// <param name="processName">Name of the process executable.</param>
+ /// <param name="commandLineIdentifiers">Strings to check for.</param>
+ /// <returns>True if some process has the Strings in its command line arguments.</returns>
+ public static bool DoesProcessExist(string processName, params string[] commandLineIdentifiers)
+ {
+ List<string> results = new List<string>();
+ string query =
+ string.Format("select CommandLine from Win32_Process where Name='{0}'", processName);
+ using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
+ {
+ using (ManagementObjectCollection result = searcher.Get())
+ {
+ foreach (ManagementObject process in result)
+ {
+ string commandLine = process["CommandLine"] as string;
+ if (string.IsNullOrEmpty(commandLine))
+ {
+ break;
+ }
+
+ // Check if the command line contains each of the required identifiers.
+ if (commandLineIdentifiers.All(i => commandLine.Contains(i)))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Sets the active configuration for the solution by specifying the configuration name
+ /// and platform name. A solution configuration containing a project configuration that has
+ /// the config and platform names specified for the specified project is selected.
+ /// </summary>
+ /// <param name="dte">The main visual studio object.</param>
+ /// <param name="projectUniqueName">UniqueName of the project to match.</param>
+ /// <param name="configurationName">Ex: "Debug" or "Release".</param>
+ /// <param name="platformName">Ex: "Win32" or "NaCl" or "PPAPI".</param>
+ public static void SetSolutionConfiguration(
+ DTE2 dte,
+ string projectUniqueName,
+ string configurationName,
+ string platformName)
+ {
+ foreach (EnvDTE.SolutionConfiguration config in
+ dte.Solution.SolutionBuild.SolutionConfigurations)
+ {
+ EnvDTE.SolutionContext context = null;
+ try
+ {
+ context = config.SolutionContexts.Item(projectUniqueName);
+ }
+ catch (ArgumentException)
+ {
+ throw new Exception(
+ string.Format("Project unique name not found in solution: {0}", projectUniqueName));
+ }
+
+ if (context == null)
+ {
+ throw new Exception("Failed to get solution context");
+ }
+
+ if (context.PlatformName == platformName && context.ConfigurationName == configurationName)
+ {
+ config.Activate();
+ return;
+ }
+ }
+
+ throw new Exception(string.Format(
+ "Matching configuration not found for {0}: {1}|{2}",
+ projectUniqueName,
+ platformName,
+ configurationName));
+ }
+
+ /// <summary>
+ /// Returns a VCConfiguration object with a matching configuration name and platform type.
+ /// </summary>
+ /// <param name="project">Project to get the configuration from.</param>
+ /// <param name="name">Name of configuration (e.g. 'Debug').</param>
+ /// <param name="platform">Name of the platform (e.g. 'NaCl').</param>
+ /// <returns>A matching VCConfiguration object.</returns>
+ public static VCConfiguration GetVCConfiguration(Project project, string name, string platform)
+ {
+ VCProject vcproj = (VCProject)project.Object;
+ IVCCollection configs = vcproj.Configurations;
+
+ foreach (VCConfiguration config in configs)
+ {
+ if (config.ConfigurationName == name && config.Platform.Name == platform)
+ {
+ return config;
+ }
+ }
+
+ throw new Exception(
+ string.Format("Project does not have configuration: {0}|{1}", platform, name));
+ }
+
+ /// <summary>
+ /// Tests that a given property has a specific value in a certain VCConfiguration
+ /// </summary>
+ /// <param name="configuration">Gives the platform and configuration type</param>
+ /// <param name="pageName">Property page name where property resides.</param>
+ /// <param name="propertyName">Name of the property to check.</param>
+ /// <param name="expectedValue">Expected value of the property.</param>
+ /// <param name="ignoreCase">Ignore case when comparing the expected and actual values.</param>
+ public static void AssertPropertyEquals(
+ VCConfiguration configuration,
+ string pageName,
+ string propertyName,
+ string expectedValue,
+ bool ignoreCase)
+ {
+ IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
+ string callInfo = string.Format(
+ "Page: {0}, Property: {1}, Configuration: {2}",
+ pageName,
+ propertyName,
+ configuration.ConfigurationName);
+
+ Assert.AreEqual(
+ expectedValue,
+ rule.GetUnevaluatedPropertyValue(propertyName),
+ ignoreCase,
+ callInfo);
+ }
+
+ /// <summary>
+ /// Tests that a given property contains a specific string in a certain VCConfiguration
+ /// </summary>
+ /// <param name="configuration">Gives the platform and configuration type</param>
+ /// <param name="pageName">Property page name where property resides.</param>
+ /// <param name="propertyName">Name of the property to check.</param>
+ /// <param name="expectedValue">Expected string to contain.</param>
+ /// <param name="ignoreCase">Ignore case when comparing the expected and actual values.</param>
+ public static void AssertPropertyContains(
+ VCConfiguration configuration,
+ string pageName,
+ string propertyName,
+ string expectedValue,
+ bool ignoreCase)
+ {
+ StringComparison caseSensitive = ignoreCase ?
+ StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
+
+ IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
+ string propertyValue = rule.GetUnevaluatedPropertyValue(propertyName);
+
+ string message = string.Format(
+ "{0} should be contained in {1}. Page: {2}, Property: {3}, Configuration: {4}",
+ expectedValue,
+ propertyValue,
+ pageName,
+ propertyName,
+ configuration.ConfigurationName);
+
+ Assert.IsTrue(propertyValue.Contains(expectedValue, caseSensitive), message);
+ }
+
+ /// <summary>
+ /// Tests that a given property is not null or empty.
+ /// </summary>
+ /// <param name="configuration">Gives the platform and configuration type</param>
+ /// <param name="pageName">Property page name where property resides.</param>
+ /// <param name="propertyName">Name of the property to check.</param>
+ public static void AssertPropertyIsNotNullOrEmpty(
+ VCConfiguration configuration,
+ string pageName,
+ string propertyName)
+ {
+ IVCRulePropertyStorage rule = configuration.Rules.Item(pageName);
+ string propertyValue = rule.GetUnevaluatedPropertyValue(propertyName);
+
+ string message = string.Format(
+ "{0} was null or empty. Page: {1}, Configuration: {2}",
+ propertyName,
+ pageName,
+ configuration.ConfigurationName);
+
+ Assert.IsFalse(string.IsNullOrEmpty(propertyValue), message);
+ }
+
+ /// <summary>
+ /// Ensures that the add-in is configured to load on start. If it isn't then some tests may
+ /// unexpectedly fail, this check helps catch that problem early.
+ /// </summary>
+ /// <param name="dte">The main Visual Studio interface.</param>
+ /// <param name="addInName">The name of the add-in to check if loaded.</param>
+ public static void AssertAddinLoaded(DTE2 dte, string addInName)
+ {
+ bool found = false;
+ foreach (AddIn addin in dte.AddIns)
+ {
+ if (addin.Connected && addInName.Equals(addin.Name))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ Assert.IsTrue(found, "Add-in is not configured to load on start.");
+ }
+
+ /// <summary>
+ /// Will retry the given statement up to maxRetry times while pausing between each try for
+ /// the given interval.
+ /// </summary>
+ /// <param name="test">Generic boolean statement.</param>
+ /// <param name="interval">Amount of time to wait between each retry.</param>
+ /// <param name="maxRetry">Maximum number of retries.</param>
+ /// <param name="message">Message to print on failure.</param>
+ public static void AssertTrueWithTimeout(
+ RetryStatement test, TimeSpan interval, int maxRetry, string message)
+ {
+ for (int tryCount = 0; tryCount <= maxRetry; tryCount++)
+ {
+ if (test.Invoke())
+ {
+ return;
+ }
+
+ System.Threading.Thread.Sleep(interval);
+ }
+
+ throw new Exception(string.Format("Statement timed out. {0}", message));
+ }
+
+ /// <summary>
+ /// Extends the string class to allow checking if a string contains another string
+ /// allowing a comparison type (such as case-insensitivity).
+ /// </summary>
+ /// <param name="source">Base string to search.</param>
+ /// <param name="toCheck">String to check if contained within base string.</param>
+ /// <param name="comparison">Comparison type.</param>
+ /// <returns>True if toCheck is contained in source.</returns>
+ public static bool Contains(this string source, string toCheck, StringComparison comparison)
+ {
+ return source.IndexOf(toCheck, comparison) != -1;
+ }
+
+ /// <summary>
+ /// Copies the entire contents of a directory and sub directories.
+ /// </summary>
+ /// <param name="source">Directory to copy from.</param>
+ /// <param name="dest">Directory to copy to.</param>
+ public static void CopyDirectory(string source, string dest)
+ {
+ DirectoryInfo dir = new DirectoryInfo(source);
+
+ if (!dir.Exists)
+ {
+ throw new DirectoryNotFoundException(source);
+ }
+
+ if (!Directory.Exists(dest))
+ {
+ Directory.CreateDirectory(dest);
+ }
+
+ FileInfo[] files = dir.GetFiles();
+ foreach (FileInfo file in files)
+ {
+ string path = Path.Combine(dest, file.Name);
+ file.CopyTo(path, false);
+ }
+
+ foreach (DirectoryInfo subdir in dir.GetDirectories())
+ {
+ string path = Path.Combine(dest, subdir.Name);
+ CopyDirectory(subdir.FullName, path);
+ }
+ }
+ }
+}
diff --git a/UnitTests/WebServerTest.cs b/UnitTests/WebServerTest.cs
index 08e8ef9..a4b432a 100644
--- a/UnitTests/WebServerTest.cs
+++ b/UnitTests/WebServerTest.cs
@@ -1,132 +1,132 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-namespace UnitTests
-{
- using System;
-
- using EnvDTE;
- using EnvDTE80;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- using NativeClientVSAddIn;
-
- /// <summary>
- /// This is a test class for WebServerTest and is intended
- /// to contain all WebServer Unit Tests
- /// </summary>
- [TestClass]
- public class WebServerTest
- {
- /// <summary>
- /// The main visual studio object.
- /// </summary>
- private DTE2 dte_;
-
- /// <summary>
- /// Gets or sets the test context which provides
- /// information about and functionality for the current test run.
- /// </summary>
- public TestContext TestContext { get; set; }
-
- /// <summary>
- /// This is run before each test to create test resources.
- /// </summary>
- [TestInitialize]
- public void TestSetup()
- {
- dte_ = TestUtilities.StartVisualStudioInstance();
- try
- {
- TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
- }
- catch
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- throw;
- }
- }
-
- /// <summary>
- /// This is run after each test to clean up things created in TestSetup().
- /// </summary>
- [TestCleanup]
- public void TestCleanup()
- {
- TestUtilities.CleanUpVisualStudioInstance(dte_);
- }
-
- /// <summary>
- /// A test for WebServer Constructor. Starts the web server.
- /// </summary>
- [TestMethod]
- public void WebServerConstructorTest()
- {
- OutputWindowPane outputWindowPane = dte_.ToolWindows.OutputWindow.OutputWindowPanes.Add(
- Strings.WebServerOutputWindowTitle);
-
- // Set up mock property manager to return the desired property values.
- MockPropertyManager properties = new MockPropertyManager(
- PropertyManager.ProjectPlatformType.Pepper,
- delegate(string page, string name)
- {
- switch (page)
- {
- case "ConfigurationGeneral":
- switch (name)
- {
- case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
- NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
- case "NaClWebServerPort": return "5105";
- }
-
- break;
- case "Property":
- switch (name)
- {
- case "ProjectDirectory": return TestContext.DeploymentDirectory;
- }
-
- break;
- }
-
- return null;
- },
- null);
-
- WebServer target = null;
- try
- {
- target = new WebServer(outputWindowPane, properties);
-
- TestUtilities.AssertTrueWithTimeout(
- () => !string.IsNullOrEmpty(TestUtilities.GetPaneText(outputWindowPane)),
- TimeSpan.FromMilliseconds(500),
- 20,
- "Pane text never appeared");
-
- TestUtilities.AssertTrueWithTimeout(
- () => TestUtilities.DoesProcessExist("python.exe", "5105", "httpd.py"),
- TimeSpan.FromMilliseconds(500),
- 20,
- "Web server failed to start.");
-
- target.Dispose();
-
- TestUtilities.AssertTrueWithTimeout(
- () => !TestUtilities.DoesProcessExist("python.exe", "5105", "httpd.py"),
- TimeSpan.FromMilliseconds(500),
- 20,
- "Web server failed to shut down.");
- }
- finally
- {
- if (target != null)
- {
- target.Dispose();
- }
- }
- }
- }
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace UnitTests
+{
+ using System;
+
+ using EnvDTE;
+ using EnvDTE80;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using NativeClientVSAddIn;
+
+ /// <summary>
+ /// This is a test class for WebServerTest and is intended
+ /// to contain all WebServer Unit Tests
+ /// </summary>
+ [TestClass]
+ public class WebServerTest
+ {
+ /// <summary>
+ /// The main visual studio object.
+ /// </summary>
+ private DTE2 dte_;
+
+ /// <summary>
+ /// Gets or sets the test context which provides
+ /// information about and functionality for the current test run.
+ /// </summary>
+ public TestContext TestContext { get; set; }
+
+ /// <summary>
+ /// This is run before each test to create test resources.
+ /// </summary>
+ [TestInitialize]
+ public void TestSetup()
+ {
+ dte_ = TestUtilities.StartVisualStudioInstance();
+ try
+ {
+ TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInName);
+ }
+ catch
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// This is run after each test to clean up things created in TestSetup().
+ /// </summary>
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ TestUtilities.CleanUpVisualStudioInstance(dte_);
+ }
+
+ /// <summary>
+ /// A test for WebServer Constructor. Starts the web server.
+ /// </summary>
+ [TestMethod]
+ public void WebServerConstructorTest()
+ {
+ OutputWindowPane outputWindowPane = dte_.ToolWindows.OutputWindow.OutputWindowPanes.Add(
+ Strings.WebServerOutputWindowTitle);
+
+ // Set up mock property manager to return the desired property values.
+ MockPropertyManager properties = new MockPropertyManager(
+ PropertyManager.ProjectPlatformType.Pepper,
+ delegate(string page, string name)
+ {
+ switch (page)
+ {
+ case "ConfigurationGeneral":
+ switch (name)
+ {
+ case "VSNaClSDKRoot": return System.Environment.GetEnvironmentVariable(
+ NativeClientVSAddIn.Strings.SDKPathEnvironmentVariable);
+ case "NaClWebServerPort": return "5105";
+ }
+
+ break;
+ case "Property":
+ switch (name)
+ {
+ case "ProjectDirectory": return TestContext.DeploymentDirectory;
+ }
+
+ break;
+ }
+
+ return null;
+ },
+ null);
+
+ WebServer target = null;
+ try
+ {
+ target = new WebServer(outputWindowPane, properties);
+
+ TestUtilities.AssertTrueWithTimeout(
+ () => !string.IsNullOrEmpty(TestUtilities.GetPaneText(outputWindowPane)),
+ TimeSpan.FromMilliseconds(500),
+ 20,
+ "Pane text never appeared");
+
+ TestUtilities.AssertTrueWithTimeout(
+ () => TestUtilities.DoesProcessExist("python.exe", "5105", "httpd.py"),
+ TimeSpan.FromMilliseconds(500),
+ 20,
+ "Web server failed to start.");
+
+ target.Dispose();
+
+ TestUtilities.AssertTrueWithTimeout(
+ () => !TestUtilities.DoesProcessExist("python.exe", "5105", "httpd.py"),
+ TimeSpan.FromMilliseconds(500),
+ 20,
+ "Web server failed to shut down.");
+ }
+ finally
+ {
+ if (target != null)
+ {
+ target.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/check_test_results.py b/check_test_results.py
index 09172b5..a4542a3 100644
--- a/check_test_results.py
+++ b/check_test_results.py
@@ -1,49 +1,49 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" This script will parse the results file produced by MSTest.
-
-The script takes a single argument containing the path to the Results.trx
-file to parse. It will log relevant test run information, and exit with code 0
-if all tests passed, or code 1 if some test failed.
-"""
-
-import sys
-import xml.etree.ElementTree
-
-MSTEST_NAMESPACE = 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010'
-
-def main():
- if len(sys.argv) < 2:
- print 'Must provide path to the Results.trx file'
- return 1
-
- # Parse the xml results file
- tree = xml.etree.ElementTree.parse(sys.argv[1])
- root = tree.getroot()
- results_node = root.find('{%s}Results' % MSTEST_NAMESPACE)
- results = results_node.findall('{%s}UnitTestResult' % MSTEST_NAMESPACE)
- test_run_name = root.attrib['name']
-
- exit_code = 0
-
- # Print the results, note any failures by setting exit_code to 1
- print test_run_name
- for result in results:
- fail_message = 'None.'
- if result.attrib['outcome'] != 'Passed':
- exit_code = 1
- fail_element = result.find('{%s}Output/{%s}ErrorInfo/{%s}Message' % (
- MSTEST_NAMESPACE, MSTEST_NAMESPACE, MSTEST_NAMESPACE))
- if fail_element is not None:
- fail_message = fail_element.text
- print 'Test: %s, Duration: %s, Outcome: %s, Reason: %s\n' % (
- result.attrib['testName'], result.attrib['duration'],
- result.attrib['outcome'], fail_message)
-
- return exit_code
-
-if __name__ == '__main__':
- sys.exit(main())
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" This script will parse the results file produced by MSTest.
+
+The script takes a single argument containing the path to the Results.trx
+file to parse. It will log relevant test run information, and exit with code 0
+if all tests passed, or code 1 if some test failed.
+"""
+
+import sys
+import xml.etree.ElementTree
+
+MSTEST_NAMESPACE = 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010'
+
+def main():
+ if len(sys.argv) < 2:
+ print 'Must provide path to the Results.trx file'
+ return 1
+
+ # Parse the xml results file
+ tree = xml.etree.ElementTree.parse(sys.argv[1])
+ root = tree.getroot()
+ results_node = root.find('{%s}Results' % MSTEST_NAMESPACE)
+ results = results_node.findall('{%s}UnitTestResult' % MSTEST_NAMESPACE)
+ test_run_name = root.attrib['name']
+
+ exit_code = 0
+
+ # Print the results, note any failures by setting exit_code to 1
+ print test_run_name
+ for result in results:
+ fail_message = 'None.'
+ if result.attrib['outcome'] != 'Passed':
+ exit_code = 1
+ fail_element = result.find('{%s}Output/{%s}ErrorInfo/{%s}Message' % (
+ MSTEST_NAMESPACE, MSTEST_NAMESPACE, MSTEST_NAMESPACE))
+ if fail_element is not None:
+ fail_message = fail_element.text
+ print 'Test: %s, Duration: %s, Outcome: %s, Reason: %s\n' % (
+ result.attrib['testName'], result.attrib['duration'],
+ result.attrib['outcome'], fail_message)
+
+ return exit_code
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/create_package.py b/create_package.py
index da135b8..018faa8 100644
--- a/create_package.py
+++ b/create_package.py
@@ -1,124 +1,124 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Takes the output of the build step and zips the distributable package.
-
-This script assumes the build script has been run to compile the add-in.
-It zips up all files required for the add-in installation and places the
-result in out/NativeClientVSAddin.zip
-"""
-
-import os
-import re
-import fileinput
-import win32api
-import shutil
-import zipfile
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-
-# Root output directory.
-BUILD_OUTPUT_DIRECTORY = os.path.join(
- SCRIPT_DIR,
- "../../out/NativeClientVSAddIn")
-
-# Directory that contains the build assemblies.
-ASSEMBLY_DIRECTORY = os.path.join(BUILD_OUTPUT_DIRECTORY, "Debug")
-
-# Directory containing static installer resources.
-RESOURCE_DIRECTORY = os.path.join(SCRIPT_DIR, "InstallerResources")
-
-# Base name of the final zip file.
-OUTPUT_NAME = os.path.join(BUILD_OUTPUT_DIRECTORY, "NativeClientVSAddIn.zip")
-
-# AddIn metadata file path. We will modify this with the version #.
-ADDIN_METADATA = os.path.join(RESOURCE_DIRECTORY, "NativeClientVSAddIn.AddIn")
-
-# AddIn dll file path. We will obtain our add-in version from this.
-ADDIN_ASSEMBLY = os.path.join(ASSEMBLY_DIRECTORY, "NativeClientVSAddIn.dll")
-
-# Regex list to exclude from the zip. If a file path matches any of the
-# expressions during a call to AddFolderToZip it is excluded from the zip file.
-EXCLUDES = [
- '.*\.svn.*', # Exclude .svn directories.
- # Exclude .AddIn file for now since we need to modify it with version info.
- re.escape(ADDIN_METADATA)]
-
-# List of source/destination pairs to include in zip file.
-FILE_LIST = [
- (ADDIN_ASSEMBLY, ''),
- (os.path.join(ASSEMBLY_DIRECTORY, "NaCl.Build.CPPTasks.dll"), 'NaCl')]
-
-
-def AddFolderToZip(path, zip_file):
- """Adds an entire folder and sub folders to an open zipfile object.
-
- The zip_file must already be open and it is not closed by this function.
-
- Args:
- path: Folder to add.
- zipfile: Already open zip file.
-
- Returns:
- Nothing.
- """
- # Ensure the path ends in trailing slash.
- path = path.rstrip("/\\") + "\\"
- for dir_path, dir_names, files in os.walk(path):
- for file in files:
- read_path = os.path.join(dir_path, file)
-
- # If the file path matches an exclude, don't include it.
- if any(re.search(expr, read_path) is not None for expr in EXCLUDES):
- continue
-
- zip_based_dir = dir_path[len(path):]
- write_path = os.path.join(zip_based_dir, file)
- zip_file.write(read_path, write_path, zipfile.ZIP_DEFLATED)
-
-
-def AddVersionModifiedAddinFile(zip_file):
- """Modifies the .AddIn file with the build version and adds to the zip.
-
- The version number is obtained from the NativeClientAddIn.dll assembly which
- is built during the build process.
-
- Args:
- zip_file: Already open zip file.
- """
- info = win32api.GetFileVersionInfo(ADDIN_ASSEMBLY, "\\")
- ms = info['FileVersionMS']
- ls = info['FileVersionLS']
- version = "[%i.%i.%i.%i]" % (
- win32api.HIWORD(ms), win32api.LOWORD(ms),
- win32api.HIWORD(ls), win32api.LOWORD(ls))
- print "\nNaCl VS Add-in Build version: %s\n" % (version)
-
- metadata_filename = os.path.basename(ADDIN_METADATA)
- modified_file = os.path.join(ASSEMBLY_DIRECTORY, metadata_filename)
-
- # Copy the metadata file to new location and modify the version info.
- with open(ADDIN_METADATA, 'r') as source_file:
- with open(modified_file, 'w') as dest_file:
- for line in source_file:
- dest_file.write(line.replace("[REPLACE_ADDIN_VERSION]", version))
-
- zip_file.write(modified_file, metadata_filename, zipfile.ZIP_DEFLATED)
-
-
-def main():
- # Zip the package.
- out_file = zipfile.ZipFile(OUTPUT_NAME, 'w')
- for source_dest in FILE_LIST:
- file_name = os.path.basename(source_dest[0])
- dest = os.path.join(source_dest[1], file_name)
- out_file.write(source_dest[0], dest, zipfile.ZIP_DEFLATED)
- AddFolderToZip(RESOURCE_DIRECTORY, out_file)
- AddVersionModifiedAddinFile(out_file)
- out_file.close()
-
-
-if __name__ == '__main__':
- main()
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Takes the output of the build step and zips the distributable package.
+
+This script assumes the build script has been run to compile the add-in.
+It zips up all files required for the add-in installation and places the
+result in out/NativeClientVSAddin.zip
+"""
+
+import os
+import re
+import fileinput
+import win32api
+import shutil
+import zipfile
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+# Root output directory.
+BUILD_OUTPUT_DIRECTORY = os.path.join(
+ SCRIPT_DIR,
+ "../../out/NativeClientVSAddIn")
+
+# Directory that contains the build assemblies.
+ASSEMBLY_DIRECTORY = os.path.join(BUILD_OUTPUT_DIRECTORY, "Debug")
+
+# Directory containing static installer resources.
+RESOURCE_DIRECTORY = os.path.join(SCRIPT_DIR, "InstallerResources")
+
+# Base name of the final zip file.
+OUTPUT_NAME = os.path.join(BUILD_OUTPUT_DIRECTORY, "NativeClientVSAddIn.zip")
+
+# AddIn metadata file path. We will modify this with the version #.
+ADDIN_METADATA = os.path.join(RESOURCE_DIRECTORY, "NativeClientVSAddIn.AddIn")
+
+# AddIn dll file path. We will obtain our add-in version from this.
+ADDIN_ASSEMBLY = os.path.join(ASSEMBLY_DIRECTORY, "NativeClientVSAddIn.dll")
+
+# Regex list to exclude from the zip. If a file path matches any of the
+# expressions during a call to AddFolderToZip it is excluded from the zip file.
+EXCLUDES = [
+ '.*\.svn.*', # Exclude .svn directories.
+ # Exclude .AddIn file for now since we need to modify it with version info.
+ re.escape(ADDIN_METADATA)]
+
+# List of source/destination pairs to include in zip file.
+FILE_LIST = [
+ (ADDIN_ASSEMBLY, ''),
+ (os.path.join(ASSEMBLY_DIRECTORY, "NaCl.Build.CPPTasks.dll"), 'NaCl')]
+
+
+def AddFolderToZip(path, zip_file):
+ """Adds an entire folder and sub folders to an open zipfile object.
+
+ The zip_file must already be open and it is not closed by this function.
+
+ Args:
+ path: Folder to add.
+ zipfile: Already open zip file.
+
+ Returns:
+ Nothing.
+ """
+ # Ensure the path ends in trailing slash.
+ path = path.rstrip("/\\") + "\\"
+ for dir_path, dir_names, files in os.walk(path):
+ for file in files:
+ read_path = os.path.join(dir_path, file)
+
+ # If the file path matches an exclude, don't include it.
+ if any(re.search(expr, read_path) is not None for expr in EXCLUDES):
+ continue
+
+ zip_based_dir = dir_path[len(path):]
+ write_path = os.path.join(zip_based_dir, file)
+ zip_file.write(read_path, write_path, zipfile.ZIP_DEFLATED)
+
+
+def AddVersionModifiedAddinFile(zip_file):
+ """Modifies the .AddIn file with the build version and adds to the zip.
+
+ The version number is obtained from the NativeClientAddIn.dll assembly which
+ is built during the build process.
+
+ Args:
+ zip_file: Already open zip file.
+ """
+ info = win32api.GetFileVersionInfo(ADDIN_ASSEMBLY, "\\")
+ ms = info['FileVersionMS']
+ ls = info['FileVersionLS']
+ version = "[%i.%i.%i.%i]" % (
+ win32api.HIWORD(ms), win32api.LOWORD(ms),
+ win32api.HIWORD(ls), win32api.LOWORD(ls))
+ print "\nNaCl VS Add-in Build version: %s\n" % (version)
+
+ metadata_filename = os.path.basename(ADDIN_METADATA)
+ modified_file = os.path.join(ASSEMBLY_DIRECTORY, metadata_filename)
+
+ # Copy the metadata file to new location and modify the version info.
+ with open(ADDIN_METADATA, 'r') as source_file:
+ with open(modified_file, 'w') as dest_file:
+ for line in source_file:
+ dest_file.write(line.replace("[REPLACE_ADDIN_VERSION]", version))
+
+ zip_file.write(modified_file, metadata_filename, zipfile.ZIP_DEFLATED)
+
+
+def main():
+ # Zip the package.
+ out_file = zipfile.ZipFile(OUTPUT_NAME, 'w')
+ for source_dest in FILE_LIST:
+ file_name = os.path.basename(source_dest[0])
+ dest = os.path.join(source_dest[1], file_name)
+ out_file.write(source_dest[0], dest, zipfile.ZIP_DEFLATED)
+ AddFolderToZip(RESOURCE_DIRECTORY, out_file)
+ AddVersionModifiedAddinFile(out_file)
+ out_file.close()
+
+
+if __name__ == '__main__':
+ main()