public void InstallExtension(string vsixPath) { if (!Exists()) { throw new InvalidOperationException("Cannot install VSIX in non-existing instance."); } using (var settings = ExternalSettingsManager.CreateForApplication(GetExePath(), Suffix)) { var ems = new ExtensionManagerService(settings); IInstallableExtension vsix = ExtensionManagerService.CreateInstallableExtension(vsixPath); if (ems.IsInstalled(vsix)) { IInstalledExtension installedVsix = ems.GetInstalledExtension(vsix.Header.Identifier); ems.Uninstall(installedVsix); if (ems.IsInstalled(vsix)) { throw new InvalidOperationException("Could not uninstall already installed GoogleTestAdapter."); } } ems.Install(vsix, perMachine: false); if (!ems.IsInstalled(vsix)) { throw new InvalidOperationException("Could not install GoogleTestAdapter."); } ems.Close(); } }
public static int Main(string[] args) { if (args.Length == 0) { PrintUsage(); return(0); } var argList = new List <string>(args); var rootSuffix = ExtractArg(argList, "rootSuffix") ?? "Exp"; var skipIfEqualOrNewerInstalled = FindArg(argList, "skipIfEqualOrNewerInstalled"); var uninstall = FindArg(argList, "u"); var uninstallAll = FindArg(argList, "uninstallAll"); var printHelp = FindArg(argList, "?") || FindArg(argList, "h") || FindArg(argList, "help"); var vsInstallDir = ExtractArg(argList, "vsInstallDir") ?? Environment.GetEnvironmentVariable("VsInstallDir"); var expectedArgCount = uninstallAll ? 0 : 1; if (argList.Count != expectedArgCount) { PrintUsage(); return(1); } string extensionPath = uninstallAll ? string.Empty : argList[0]; string devenvPath; try { devenvPath = GetDevenvPath(vsInstallDir); var assemblyResolutionPaths = new string[] { Path.Combine(vsInstallDir, @"Common7\IDE"), Path.Combine(vsInstallDir, @"Common7\IDE\PrivateAssemblies"), Path.Combine(vsInstallDir, @"Common7\IDE\PublicAssemblies") }; AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs eventArgs) => { var assemblyFileName = $"{eventArgs.Name.Split(',')[0]}.dll"; foreach (var assemblyResolutionPath in assemblyResolutionPaths) { var assemblyFilePath = Path.Combine(assemblyResolutionPath, assemblyFileName); if (File.Exists(assemblyFilePath)) { return(Assembly.LoadFrom(assemblyFilePath)); } } return(null); }; Console.WriteLine(Environment.CommandLine); if (IsRunningAsAdmin()) { Console.WriteLine(" Running as Admin."); } RunProgram(); // Move all of this into a local method so that it only causes the assembly loads after the resolver has been hooked up void RunProgram() { var installedExtensionComparer = Comparer <IInstalledExtension> .Create((left, right) => { if (left.References.Count() == 0) { // When left.References.Count() is zero, then we have two scenarios: // * right.References.Count() is zero, and the order of the two components doesn't matter, so we return 0 // * right.References.Count() is not zero, which means it should be uninstalled after left, so we return -1 return(right.References.Count() == 0 ? 0 : -1); } else if (right.References.Count() == 0) { // When left.References.Count() is not zero, but right.References.Count() is, then we have one scenario: // * right should be uninstalled before left, so we return 1 return(1); } if (left.References.Any((extensionReference) => extensionReference.Identifier == right.Header.Identifier)) { // When left.References contains right, then we have one scenario: // * left is dependent on right, which means it must be uninstalled afterwards, so we return 1 return(1); } else if (right.References.Any((extensionReference) => extensionReference.Identifier == left.Header.Identifier)) { // When right.References contains left, then we have one scenario: // * right is dependent on left, which means it must be uninstalled afterwards, so we return -1 return(-1); } // Finally, if both projects contain references, but neither depends on the other, we have one scenario: // * left and right are independent of each other, and the order of the two components doesn't matter, so we return 0 return(0); }); using (var settingsManager = ExternalSettingsManager.CreateForApplication(devenvPath, rootSuffix)) { ExtensionManagerService extensionManagerService = null; try { extensionManagerService = new ExtensionManagerService(settingsManager); if (uninstallAll) { Console.WriteLine(" Uninstalling all local extensions..."); UninstallAll(); } else { var extensionManager = (IVsExtensionManager)(extensionManagerService); var installableExtension = extensionManager.CreateInstallableExtension(extensionPath); var status = GetInstallStatus(installableExtension.Header); var installedVersionIsEqualOrNewer = installableExtension.Header.Version < status.installedExtension?.Header.Version; if (uninstall) { if (status.installed) { if (installedVersionIsEqualOrNewer && skipIfEqualOrNewerInstalled) { Environment.ExitCode = INSTALL_OR_UNINSTALL_SKIPPED_EXCEPTION_CODE; throw new Exception($"Skipping uninstall of version ({status.installedExtension.Header.Version}), which is equal to or newer than the one supplied on the command line ({installableExtension.Header.Version})."); } if (status.installedGlobally) { Console.WriteLine($" Skipping uninstall for global extension: '{status.installedExtension.InstallPath}'"); } else { Console.WriteLine($" Uninstalling local extension: '{status.installedExtension.InstallPath}'"); Uninstall(status.installedExtension); } } else { Console.WriteLine(" Nothing to uninstall..."); } } else { if (status.installed) { if (installedVersionIsEqualOrNewer && skipIfEqualOrNewerInstalled) { Environment.ExitCode = INSTALL_OR_UNINSTALL_SKIPPED_EXCEPTION_CODE; throw new Exception($"Skipping install of version ({installableExtension.Header.Version}), which is older than the one currently installed ({status.installedExtension.Header.Version})."); } if (status.installedGlobally) { if (installedVersionIsEqualOrNewer) { Environment.ExitCode = GLOBAL_VERSION_NEWER_EXCEPTION_CODE; throw new Exception($"The version you are attempting to install ({installableExtension.Header.Version}) has a version that is less than the one installed globally ({status.installedExtension.Header.Version})."); } else { Console.WriteLine($" Installing local extension ({extensionPath}) over global extension ({status.installedExtension.InstallPath})"); } } else { Console.WriteLine($" Updating local extension ({status.installedExtension.InstallPath}) to '{extensionPath}'"); Uninstall(status.installedExtension); } } else { Console.WriteLine($" Installing local extension: '{extensionPath}'"); } Install(installableExtension); } } } finally { extensionManagerService?.Close(); extensionManagerService = null; } bool IsInstalledGlobally(IInstalledExtension installedExtension) { return(installedExtension.InstalledPerMachine || installedExtension.InstallPath.StartsWith(vsInstallDir, StringComparison.OrdinalIgnoreCase)); } (bool installed, bool installedGlobally, IInstalledExtension installedExtension) GetInstallStatus(IExtensionHeader extensionHeader) { var installed = extensionManagerService.TryGetInstalledExtension(extensionHeader.Identifier, out var installedExtension); var installedGlobally = installed && IsInstalledGlobally(installedExtension); return(installed, installedGlobally, installedExtension); } void Install(IInstallableExtension installableExtension) { extensionManagerService.Install(installableExtension, perMachine: false); var settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); EnableLoadingAllExtensions(settingsStore); RemoveExtensionFromPendingDeletions(settingsStore, installableExtension.Header); UpdateLastExtensionsChange(settingsStore); // Recreate the extensionManagerService to force the extension cache to recreate extensionManagerService?.Close(); extensionManagerService = new ExtensionManagerService(settingsManager); var status = GetInstallStatus(installableExtension.Header); if (!status.installed) { Environment.ExitCode = INSTALL_FAILED_NOTFOUND_EXCEPTION_CODE; throw new Exception($"The extension failed to install. It could not be located."); } else if (status.installedExtension.Header.Version != installableExtension.Header.Version) { Environment.ExitCode = INSTALL_FAILED_VERSION_EXCEPTION_CODE; throw new Exception($"The extension failed to install. The located version ({status.installedExtension.Header.Version}) does not match the expected version ({installableExtension.Header.Version})."); } else if (status.installedGlobally) { Console.WriteLine($" The extension was succesfully installed globally: '{status.installedExtension.InstallPath}'"); } else { Console.WriteLine($" The extension was succesfully installed locally: '{status.installedExtension.InstallPath}'"); } } void Uninstall(IInstalledExtension installedExtension) { extensionManagerService.Uninstall(installedExtension); // Recreate the extensionManagerService to force the extension cache to recreate extensionManagerService?.Close(); extensionManagerService = new ExtensionManagerService(settingsManager); var status = GetInstallStatus(installedExtension.Header); if (status.installed) { var wasInstalledGlobally = IsInstalledGlobally(installedExtension); if (wasInstalledGlobally) { // We should never hit this case, as we shouldn't be passing in gobally installed extensions if (status.installedGlobally) { Environment.ExitCode = GLOBAL_UNINSTALL_FAILED_EXCEPTION_CODE; throw new Exception("The global extension failed to uninstall."); } else { // This should be impossible even if we tried to uninstall a global extension... Environment.ExitCode = LOCAL_UNINSTALL_FAILED_EXCEPTION_CODE; throw new Exception($"The global extension was uninstalled. A local extension still exists: '{status.installedExtension.InstallPath}'"); } } else if (status.installedGlobally) { Console.WriteLine($" The local extension was succesfully uninstalled. A global extension still exists: '{status.installedExtension.InstallPath}'"); } else { throw new Exception("The local extension failed to uninstall."); } } else { Console.WriteLine(" The local extension was succesfully uninstalled."); } } void UninstallAll() { // We only want extensions which are not installed per machine and we want them sorted by their dependencies. var installedExtensions = extensionManagerService.GetInstalledExtensions() .Where((installedExtension) => !IsInstalledGlobally(installedExtension)) .OrderBy((installedExtension) => installedExtension, installedExtensionComparer); foreach (var installedExtension in installedExtensions) { Console.WriteLine($" Uninstalling local extension: '{installedExtension.InstallPath}'"); Uninstall(installedExtension); } } } } } catch (Exception e) when(Environment.ExitCode != 0) { if (Environment.ExitCode < 0) { Console.Error.WriteLine(e); } else { Console.WriteLine(" " + e.Message); } } return(Environment.ExitCode); }
public static int Main(string[] args) { if (args.Length == 0) { PrintUsage(); return(0); } var argList = new List <string>(args); var rootSuffix = ExtractArg(argList, "rootSuffix") ?? "Exp"; var uninstall = FindArg(argList, "u"); var uninstallAll = FindArg(argList, "uninstallAll"); var printHelp = FindArg(argList, "?") || FindArg(argList, "h") || FindArg(argList, "help"); var vsInstallDir = ExtractArg(argList, "vsInstallDir") ?? Environment.GetEnvironmentVariable("VsInstallDir"); var expectedArgCount = uninstallAll ? 0 : 1; if (argList.Count != expectedArgCount) { PrintUsage(); return(1); } string vsixPath = uninstallAll ? string.Empty : argList[0]; string devenvPath; try { devenvPath = GetDevenvPath(vsInstallDir); var assemblyResolutionPaths = new string[] { Path.Combine(vsInstallDir, @"Common7\IDE"), Path.Combine(vsInstallDir, @"Common7\IDE\PrivateAssemblies"), Path.Combine(vsInstallDir, @"Common7\IDE\PublicAssemblies") }; AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs eventArgs) => { var assemblyFileName = $"{eventArgs.Name.Split(',')[0]}.dll"; foreach (var assemblyResolutionPath in assemblyResolutionPaths) { var assemblyFilePath = Path.Combine(assemblyResolutionPath, assemblyFileName); if (File.Exists(assemblyFilePath)) { return(Assembly.LoadFrom(assemblyFilePath)); } } return(null); }; RunProgram(); // Move all of this into a local method so that it only causes the assembly loads after the resolver has been hooked up void RunProgram() { using (var settingsManager = ExternalSettingsManager.CreateForApplication(devenvPath, rootSuffix)) { ExtensionManagerService extensionManagerService = null; try { extensionManagerService = new ExtensionManagerService(settingsManager); if (uninstallAll) { Console.WriteLine("Uninstalling all... "); UninstallAll(extensionManagerService); } else { var extensionManager = (IVsExtensionManager)(extensionManagerService); var vsixToInstall = extensionManager.CreateInstallableExtension(vsixPath); var vsixToInstallHeader = vsixToInstall.Header; var foundBefore = extensionManagerService.TryGetInstalledExtension(vsixToInstallHeader.Identifier, out var installedVsixBefore); var installedGloballyBefore = foundBefore && installedVsixBefore.InstallPath.StartsWith(vsInstallDir, StringComparison.OrdinalIgnoreCase); if (uninstall) { if (foundBefore && !installedGloballyBefore) { Console.WriteLine("Uninstalling {0}... ", vsixPath); extensionManagerService.Uninstall(installedVsixBefore); } else { Console.WriteLine("Nothing to uninstall... "); } } else { if (foundBefore && installedGloballyBefore && (vsixToInstallHeader.Version < installedVsixBefore.Header.Version)) { throw new Exception($"The version you are attempting to install ({vsixToInstallHeader.Version}) has a version that is less than the one installed globally ({installedVsixBefore.Header.Version})."); } else if (foundBefore && !installedGloballyBefore) { Console.WriteLine("Updating {0}... ", vsixPath); extensionManagerService.Uninstall(installedVsixBefore); } else { Console.WriteLine("Installing {0}... ", vsixPath); } extensionManagerService.Install(vsixToInstall, perMachine: false); var settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); EnableLoadingAllExtensions(settingsStore); RemoveExtensionFromPendingDeletions(settingsStore, vsixToInstallHeader); UpdateLastExtensionsChange(settingsStore); // Recreate the extensionManagerService to force the extension cache to recreate extensionManagerService?.Close(); extensionManagerService = new ExtensionManagerService(settingsManager); var foundAfter = extensionManagerService.TryGetInstalledExtension(vsixToInstallHeader.Identifier, out var installedVsixAfter); var installedGloballyAfter = foundAfter && installedVsixAfter.InstallPath.StartsWith(vsInstallDir, StringComparison.OrdinalIgnoreCase); if (uninstall && foundAfter) { if (installedGloballyBefore && installedGloballyAfter) { throw new Exception($"The extension failed to uninstall. It is still installed globally."); } else if (!installedGloballyBefore && installedGloballyAfter) { Console.WriteLine("The local extension was succesfully uninstalled. However, the global extension is still installed."); } else { Console.WriteLine("The extension was succesfully uninstalled."); } } else if (!uninstall) { if (!foundAfter) { throw new Exception($"The extension failed to install. It could not be located."); } else if (installedVsixAfter.Header.Version != vsixToInstallHeader.Version) { throw new Exception("The extension failed to install. The located version does not match the expected version."); } else { Console.WriteLine("The extension was succesfully installed."); } } } } } finally { extensionManagerService?.Close(); extensionManagerService = null; } Console.WriteLine("Done!"); } } } catch (Exception e) { string message = e.GetType().Name + ": " + e.Message + Environment.NewLine + e.ToString(); Console.Error.WriteLine(message); return(2); } return(0); }
internal void InstallExtension(string vsixPath) { if (!Exists()) throw new InvalidOperationException("Cannot install VSIX in non-existing instance."); using (var settings = ExternalSettingsManager.CreateForApplication(GetExePath(), Suffix)) { var ems = new ExtensionManagerService(settings); IInstallableExtension vsix = ExtensionManagerService.CreateInstallableExtension(vsixPath); if (ems.IsInstalled(vsix)) { IInstalledExtension installedVsix = ems.GetInstalledExtension(vsix.Header.Identifier); ems.Uninstall(installedVsix); if (ems.IsInstalled(vsix)) throw new InvalidOperationException("Could not uninstall already installed GoogleTestAdapter."); } ems.Install(vsix, perMachine: false); if (!ems.IsInstalled(vsix)) throw new InvalidOperationException("Could not install GoogleTestAdapter."); ems.Close(); } }