Skip to content

Commit

Permalink
[Devenv] support of latest API v1.3
Browse files Browse the repository at this point in the history
* Update of loading and initialization with new loader. /Provider v3.0
* Added support of the `Build.Cancel` command for user scripts.

Also:

* wrapped OutOfMemoryException in main lib - Environment.exec
  • Loading branch information
3F committed Sep 29, 2015
1 parent 3a3798c commit 0162d4c
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 77 deletions.
43 changes: 43 additions & 0 deletions Devenv/AbortException.cs
@@ -0,0 +1,43 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2015 Denis Kuzmin (reg) <entry.reg@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;

namespace net.r_eg.vsSBE.Devenv
{
[Serializable]
public class AbortException: Exception
{
public AbortException()
{

}

public AbortException(string message)
: base(message)
{

}
}
}
219 changes: 144 additions & 75 deletions Devenv/Connect.cs
Expand Up @@ -33,16 +33,36 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using net.r_eg.vsSBE.Bridge;
using net.r_eg.vsSBE.Provider;

namespace net.r_eg.vsSBE.Devenv
{
/// <summary>
///
/// ! https://connect.microsoft.com/VisualStudio/feedback/details/1075033/
/// https://bitbucket.org/3F/vssolutionbuildevent/issues/25/#comment-14586721
/// http://vssbe.r-eg.net/doc/Scheme/
///
/// Alternative variant with MSBuild:
/// http://vssbe.r-eg.net/doc/CI/CI.MSBuild/
/// </summary>
public sealed class Connect: IDTExtensibility2, IVsSolutionEvents, IVsUpdateSolutionEvents2
{
/// <summary>
/// Our the vsSolutionBuildEvent library
/// Used logger
/// </summary>
internal ILog log;

/// <summary>
/// Our vsSolutionBuildEvent library
/// </summary>
private Provider.ILibrary library;

/// <summary>
/// Support of the core commands.
/// </summary>
private CoreCommand coreCommand;

/// <summary>
/// For IVsSolutionEvents events
/// http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivssolution.aspx
Expand Down Expand Up @@ -70,17 +90,12 @@ public sealed class Connect: IDTExtensibility2, IVsSolutionEvents, IVsUpdateSolu
/// <summary>
/// DTE2 Context from the root object of the host application.
/// </summary>
private DTE2 _dte2;
private DTE2 dte2;

/// <summary>
/// Representing this Add-in.
/// </summary>
private AddIn _addIn;

/// <summary>
/// Loader of main library
/// </summary>
private Provider.ILoader loader;
private AddIn addIn;


#region pingpong
Expand All @@ -97,7 +112,12 @@ public int OnAfterCloseSolution(object pUnkReserved)

public int UpdateSolution_Begin(ref int pfCancelUpdate)
{
return library.Event.onPre(ref pfCancelUpdate);
try {
return library.Event.onPre(ref pfCancelUpdate);
}
finally {
termination();
}
}

public int UpdateSolution_Cancel()
Expand All @@ -112,12 +132,22 @@ public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand

public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel)
{
return library.Event.onProjectPre(pHierProj, pCfgProj, pCfgSln, dwAction, ref pfCancel);
try {
return library.Event.onProjectPre(pHierProj, pCfgProj, pCfgSln, dwAction, ref pfCancel);
}
finally {
termination();
}
}

public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel)
{
return library.Event.onProjectPost(pHierProj, pCfgProj, pCfgSln, dwAction, fSuccess, fCancel);
try {
return library.Event.onProjectPost(pHierProj, pCfgProj, pCfgSln, dwAction, fSuccess, fCancel);
}
finally {
termination();
}
}

#endregion
Expand All @@ -129,87 +159,121 @@ public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg
/// <seealso class='IDTExtensibility2' />
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{

//#if !DEBUG
if(connectMode != ext_ConnectMode.ext_cm_CommandLine) {
msg("[Ignored] Allowed only Command line mode /'{0}'", connectMode);
log.info("[Ignored] Allowed only Command-line mode /'{0}'", connectMode);
return;
}
//#endif

loader = new Provider.Loader();
loader.Settings.DebugMode = Environment.GetCommandLineArgs().Contains("verbosity:diagnostic");
_dte2 = (DTE2)application;
_addIn = (AddIn)addInInst;
dte2 = (DTE2)application;
addIn = (AddIn)addInInst;

ILoader loader = new Loader(
new Provider.Settings()
{
DebugMode = log.IsDiagnostic,
LibSettings = new LibSettings()
{
DebugMode = log.IsDiagnostic,
},
}
);

init(loader, dte2, addIn);
}

/// <summary>Receives notification that the Add-in is being unloaded.</summary>
/// <param term='disconnectMode'>Describes how the Add-in is being unloaded.</param>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
unadviseEvents();
coreCommand.detachCoreCommandListener();
}

public Connect()
{
log = new Log(Environment.GetCommandLineArgs().Contains("verbosity:diagnostic"));
header();
}

/// <summary>
/// Initialize library
/// </summary>
/// <param name="loader"></param>
/// <param name="dte2"></param>
/// <param name="addIn"></param>
private void init(ILoader loader, DTE2 dte2, AddIn addIn)
{
try
{
library = loader.load(application, _addIn.SatelliteDllPath, _dte2.RegistryRoot);
msg("Library: loaded from '{0}' :: v{1} [{2}] API: v{3} /'{4}':{5}",
library = loader.load(dte2, addIn.SatelliteDllPath, dte2.RegistryRoot);
log.info("Library: loaded from '{0}' :: v{1} [{2}] API: v{3} /'{4}':{5}",
library.Dllpath,
library.Version.Number.ToString(),
library.Version.BranchSha1,
library.Version.Bridge.Number.ToString(2),
library.Version.BranchName,
library.Version.BranchRevCount);


coreCommand = new CoreCommand(library);
coreCommand.attachCoreCommandListener();

updateBuildType(Environment.GetCommandLineArgs());
adviseEvents();
return;
}
catch(DllNotFoundException ex)
{
msg(ex.Message);
msg("You can install vsSolutionBuildEvent as plugin for this Visual Studio v{0} or manually place the {1} into the current add-in folder",
_dte2.Version,
"vsSolutionBuildEvent.dll with dependencies");

msg("https://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/");
msg("Minimum requirements: vsSolutionBuildEvent.dll v{0}", loader.MinVersion.ToString());
msg(new String('=', 80));
log.info(ex.Message);
log.info(new String('.', 80));
log.info("How about:");

log.info("");
log.info("* Install vsSolutionBuildEvent as plugin for your Visual Studio v{0}", dte2.Version);
log.info("* Or manually place the 'vsSolutionBuildEvent.dll' with dependencies into AddIn folder: '{0}\\'", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
log.info("");

log.info("See documentation for more details:");
log.info("- http://vssbe.r-eg.net");
log.info("- http://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/");
log.info("");

log.info("Minimum requirements: vsSolutionBuildEvent.dll v{0}", loader.MinVersion.ToString());
log.info(new String('.', 80));
}
catch(ReflectionTypeLoadException ex)
{
log.info(ex.ToString());
log.info(new String('.', 80));

foreach(FileNotFoundException le in ex.LoaderExceptions) {
msg("{2} {0}{3} {0}{0}{4} {0}{1}",
Environment.NewLine, new String('~', 80),
le.FileName, le.Message, le.FusionLog);
log.info("{2} {0}{3} {0}{0}{4} {0}{1}",
Environment.NewLine,
new String('~', 80),
le.FileName,
le.Message,
le.FusionLog);
}
}
catch(Exception ex) {
msg("Error with advising '{0}'", ex.ToString());
log.info("Error with advising '{0}'", ex.ToString());
}
}

/// <summary>Receives notification that the Add-in is being unloaded.</summary>
/// <param term='disconnectMode'>Describes how the Add-in is being unloaded.</param>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
unadviseEvents();
}

public Connect()
{
msg(new String('=', 60));
msg("[[ vsSolutionBuildEvent Devenv Command-Line ]] Welcomes You!");
msg(new String('=', 60));
msg("Version: v{0}", System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion);
msg("Feedback: entry.reg@gmail.com");
msg(new String('_', 60));
termination(true);
}


/// <summary>
/// Defines listeners for main events.
/// </summary>
private void adviseEvents()
{
// To listen events fires from IVsSolutionEvents
// To listen events that fired as a IVsSolutionEvents
spSolution = (IVsSolution)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution));
spSolution.AdviseSolutionEvents(this, out _pdwCookieSolution);

// To listen events fires from IVsUpdateSolutionEvents2
// To listen events that fired as a IVsUpdateSolutionEvents2
spSolutionBM = (IVsSolutionBuildManager2)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager));
spSolutionBM.AdviseUpdateSolutionEvents(this, out _pdwCookieSolutionBM);
}
Expand All @@ -225,6 +289,23 @@ private void unadviseEvents()
}
}

/// <summary>
/// Logic of termination of the devenv job
/// </summary>
/// <param name="force">Terminate manually if true.</param>
private void termination(bool force = false)
{
if(!force && (coreCommand == null || !coreCommand.IsAborted)) {
return;
}

//TODO: Another way ? fix me
//throw new AbortException(); // not effective for devenv case. See also in CIM

log.info("The build has been canceled{0}.", (force)? "" : " by user script");
Environment.Exit(VSConstants.S_FALSE); // we work in command line mode with devenv, stop it immediately
}

/// <summary>
/// Updates the type by command-line switches if it exists in BuildType list
/// https://msdn.microsoft.com/en-us/library/vstudio/xee0c8y7.aspx
Expand All @@ -234,37 +315,25 @@ private void updateBuildType(string[] switches)
{
foreach(string type in switches.Where(p => p.StartsWith("/")).Select(p => p.Substring(1)))
{
debug("updateBuildType: check '{0}'", type);
log.debug("updateBuildType: check '{0}'", type);
if(Enum.IsDefined(typeof(BuildType), type))
{
BuildType buildType = (BuildType)Enum.Parse(typeof(BuildType), type);
library.Build.updateBuildType(buildType);
debug("updateBuildType: updated as a '{0}'", buildType);
log.debug("updateBuildType: updated as a '{0}'", buildType);
return;
}
}
}

/// <summary>
/// TODO: logger
/// </summary>
/// <param name="data"></param>
/// <param name="args"></param>
private void msg(string data, params object[] args)
{
Console.WriteLine(data, args);
}

/// <summary>
/// TODO: logger
/// </summary>
/// <param name="data"></param>
/// <param name="args"></param>
private void debug(string data, params object[] args)
private void header()
{
if(loader.Settings.DebugMode) {
msg(data, args);
}
log.info(new String('=', 60));
log.info("[[ vsSolutionBuildEvent Devenv ]] Welcomes You!");
log.info(new String('=', 60));
log.info("Version: v{0}", System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion);
log.info("Feedback: entry.reg@gmail.com | vssbe.r-eg.net");
log.info(new String('_', 60));
}


Expand Down

0 comments on commit 0162d4c

Please sign in to comment.