//------------------------------------------------------------------------------
//
// Copyright (c) Company. All rights reserved.
//
//------------------------------------------------------------------------------
using System;
using System.ComponentModel.Design;
using System.Globalization;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Collections.Generic;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio;
using System.Linq;
using TestStack.White.UIItems.Finders;
using TestStack.White.InputDevices;
using TestStack.White.UIItems;
using VSLangProj;
using System.Runtime.InteropServices;
using TestStack.White.WindowsAPI;
using System.IO;
namespace Tango.BuildExtensions
{
///
/// Command handler
///
internal sealed class TangoBuildCommand : VSIXBase
{
private IList _projects;
private TestStack.White.Application _application;
private TestStack.White.UIItems.WindowItems.Window _window;
private System.Diagnostics.Process _vsProcess;
private const String dalProjectName = "Tango.DAL.Remote";
private const String edmxModelName = "RemoteADO.edmx";
private const String observablesGeneratorProjectName = "Tango.DBObservablesGenerator.CLI";
private const String observablesProjectName = "Tango.BL";
private const String observablesContextName = "ObservablesContext.cs";
private const String pmrGeneratorProjectName = "Tango.PMRGenerator.CLI";
private const String pmrProjectName = "Tango.PMR";
private const String protoCliProjectName = "Tango.Protobuf.CLI";
private const String sqliteProjectName = "Tango.SQLiteGenerator.CLI";
#region Redundant
///
/// Command ID.
///
public const int CommandId = 0x0100;
///
/// Command menu group (command set GUID).
///
public static readonly Guid CommandSet = new Guid("c03a7b01-8109-4ec5-8f90-858bed027e5d");
///
/// VS Package that provides this command, not null.
///
private readonly Package package;
///
/// Initializes a new instance of the class.
/// Adds our command handlers for menu (commands must exist in the command table file)
///
/// Owner package, not null.
private TangoBuildCommand(Package package) : base(package)
{
if (package == null)
{
throw new ArgumentNullException("package");
}
this.package = package;
OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
{
var menuCommandID = new CommandID(CommandSet, CommandId);
var menuItem = new MenuCommand(this.MenuItemCallback, menuCommandID);
commandService.AddCommand(menuItem);
}
}
///
/// Gets the instance of the command.
///
public static TangoBuildCommand Instance
{
get;
private set;
}
///
/// Gets the service provider from the owner package.
///
private IServiceProvider ServiceProvider
{
get
{
return this.package;
}
}
///
/// Initializes the singleton instance of the command.
///
/// Owner package, not null.
public static void Initialize(Package package)
{
Instance = new TangoBuildCommand(package);
}
///
/// This function is the callback used to execute the command when the menu item is clicked.
/// See the constructor to see how the menu item is associated with this function using
/// OleMenuCommandService service and MenuCommand class.
///
/// Event sender.
/// Event args.
private void MenuItemCallback(object sender, EventArgs e)
{
Start();
}
#endregion
#region Main
private void Start()
{
BuildForm buildForm = new BuildForm();
if (buildForm.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
#pragma warning disable VSTHRD105 // Avoid method overloads that assume TaskScheduler.Current
System.Threading.Tasks.Task.Factory.StartNew(() =>
#pragma warning restore VSTHRD105 // Avoid method overloads that assume TaskScheduler.Current
{
_projects = GetSolutionProjects().ToList();
String vsWindowTitle = DTE.DTE.MainWindow.Caption;
_vsProcess = System.Diagnostics.Process.GetProcesses().ToList().SingleOrDefault(x => x.MainWindowTitle == vsWindowTitle);
_application = TestStack.White.Application.Attach(_vsProcess);
_window = _application.GetWindow(vsWindowTitle);
OpenVSProgress("Tango Build Engine", "Initializing...", true);
String current_startup_project = DTE.Solution.Properties.Item("StartupProject").Value.ToString();
try
{
if (buildForm.UpdateDataBaseEntities)
{
UpdateDatabaseEntities();
}
if (buildForm.GenerateAndBuildObservables)
{
GenerateAndBuildObservables();
}
if (buildForm.GenerateAutoPmrMessages)
{
GenerateAutoPMRMessages();
}
if (buildForm.UpdateAndBuildPmrMessages)
{
UpdateAndBuildPmrMessages();
}
if (buildForm.GenerateSQLite)
{
GenerateSQLite();
}
if (buildForm.BuildSolution)
{
BuildSolution();
}
SetVSProgress("Done!");
Wait(1000);
CloseVSProgress();
ShowMessage("Tango Build Completed Successfully!");
DTE.Solution.Properties.Item("StartupProject").Value = current_startup_project;
}
catch (Exception ex)
{
CloseVSProgress();
ShowMessage($"Tango Build Failed.\n{ex.Message}");
DTE.Solution.Properties.Item("StartupProject").Value = current_startup_project;
}
});
}
private void UpdateDatabaseEntities()
{
var project = _projects.SingleOrDefault(x => x.Name == dalProjectName);
if (project == null)
{
throw new NullReferenceException("Could not find the Tango solution!");
}
var projectItems = project.ProjectItems.OfType().ToList();
SetVSProgress("Locating " + edmxModelName + " scheme...");
var items = GetProjectItems(project);
var edmx = GetProjectItems(project).SingleOrDefault(x => x.Name == edmxModelName);
if (edmx == null)
{
throw new NullReferenceException("Could not locate " + edmxModelName + "!");
}
SetVSProgress("Expanding diagram...");
edmx.ExpandView();
SetVSProgress("Opening EDMX diagram window...");
Window win = edmx.Open(EnvDTE.Constants.vsViewKindPrimary);
win.Visible = true;
SetVSProgress("Waiting for EDMX diagram window...");
_window.WaitTill(() => _window.Get(SearchCriteria.ByText(edmxModelName + " [Diagram1]")) != null,TimeSpan.FromSeconds(30));
SetVSProgress("Cleaning up EDMX scheme...");
DTE.MainWindow.Activate();
DTE.ExecuteCommand("Edit.SelectAll");
Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.DELETE);
WaitForWindowOpen("Delete Unmapped Tables and Views").PressKey(KeyboardInput.SpecialKeys.RETURN);
WaitForWindowClose("Delete Unmapped Tables and Views");
_window.WaitWhileBusy();
SetVSProgress("Reinitializing EDMX scheme...");
var window = WindowInfo.GetWindow(edmxModelName + " [Diagram1]*");
window.SetActive();
Keyboard.Instance.HoldKey(KeyboardInput.SpecialKeys.SHIFT);
Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.F10);
Keyboard.Instance.LeaveAllKeys();
Wait(100);
for (int i = 0; i < 7; i++)
{
Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.DOWN);
Wait(10);
}
Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.RETURN);
var updateWindow = WaitForWindowOpen("Update Wizard");
_window.WaitWhileBusy();
Wait(1000);
updateWindow.PressKey(KeyboardInput.SpecialKeys.SPACE);
Wait(50);
updateWindow.PressKey(KeyboardInput.SpecialKeys.RETURN);
SetVSProgress("Generating EDMX scheme...");
WaitForWindowClose("Update Wizard");
_window.WaitWhileBusy();
SetVSProgress("Saving changes...");
win.Close(vsSaveChanges.vsSaveChangesYes);
_window.WaitWhileBusy();
foreach (var template in edmx.ProjectItems.OfType().Where(x => x.Name.EndsWith(".tt")))
{
SetVSProgress("Running custom tool for " + template.Name + "...");
(template.Object as VSProjectItem).RunCustomTool();
_window.WaitWhileBusy();
}
_window.WaitWhileBusy();
SetVSProgress("Building project " + dalProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
if (DTE.Solution.SolutionBuild.LastBuildInfo > 0)
{
throw new ExternalException(dalProjectName + " failed to build!");
}
}
private void GenerateAndBuildObservables()
{
var project = _projects.SingleOrDefault(x => x.Name == observablesGeneratorProjectName);
if (project == null)
{
throw new NullReferenceException("Could not locate project " + observablesGeneratorProjectName);
}
SetVSProgress("Building project " + observablesGeneratorProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
DTE.Solution.Properties.Item("StartupProject").Value = observablesGeneratorProjectName;
SetVSProgress("Executing observables generator...");
DTE.ExecuteCommand("Debug.Start");
WaitForWindowOpen("Tango Observables Generator");
WaitForWindowClose("Tango Observables Generator");
var observablesProject = _projects.SingleOrDefault(x => x.Name == observablesProjectName);
if (observablesProject == null)
{
throw new NullReferenceException("Could not locate project " + observablesProjectName);
}
SetVSProgress("Updating " + observablesProjectName + "...");
foreach (var file in Directory.GetFiles(Path.GetDirectoryName(observablesProject.FileName), "*.cs", SearchOption.AllDirectories))
{
String parentFolderName = Path.GetFileName(Path.GetDirectoryName(file));
if (parentFolderName != "Debug" && parentFolderName != "Release" && parentFolderName != "obj")
{
SetVSProgress("Adding/Updating file " + Path.GetFileName(file) + "...");
observablesProject.ProjectItems.AddFromFile(file);
Wait(5);
}
}
SetVSProgress("Building project " + observablesProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", observablesProject.FullName, true);
if (DTE.Solution.SolutionBuild.LastBuildInfo > 0)
{
throw new ExternalException(observablesProjectName + " failed to build!");
}
project = _projects.SingleOrDefault(x => x.Name == observablesProjectName);
if (project == null)
{
throw new NullReferenceException("Could not locate project " + observablesProjectName);
}
SetVSProgress("Generating views for ObservablesContext...");
var views_file = GetProjectItems(project).SingleOrDefault(x => x.Name == observablesContextName);
if (views_file == null)
{
throw new NullReferenceException("Could not locate " + observablesContextName + "!");
}
//Wait(1000);
//DTE.MainWindow.Activate();
//ExpandSolutionExplorerNode($"Tango\\{observablesProjectName}");
//Wait(1000);
//SelectSolutionExplorerNode($"Tango\\{observablesProjectName}\\{observablesContextName}");
//Wait(1000);
//Keyboard.Instance.HoldKey(KeyboardInput.SpecialKeys.SHIFT);
//Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.F10);
//Keyboard.Instance.LeaveAllKeys();
//Wait(1000);
//for (int i = 0; i < 3; i++)
//{
// Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.DOWN);
// Wait(100);
//}
//Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT);
//Wait(100);
//for (int i = 0; i < 3; i++)
//{
// Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.DOWN);
// Wait(100);
//}
//Keyboard.Instance.PressSpecialKey(KeyboardInput.SpecialKeys.RETURN);
//_window.WaitWhileBusy();
}
private void GenerateAutoPMRMessages()
{
var project = _projects.SingleOrDefault(x => x.Name == pmrGeneratorProjectName);
if (project == null)
{
throw new NullReferenceException("Could not locate project " + pmrGeneratorProjectName);
}
SetVSProgress("Building project " + pmrGeneratorProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
DTE.Solution.Properties.Item("StartupProject").Value = pmrGeneratorProjectName;
SetVSProgress("Executing PMR generator...");
DTE.ExecuteCommand("Debug.Start");
WaitForWindowOpen("Tango PMR Generator");
WaitForWindowClose("Tango PMR Generator");
}
private void UpdateAndBuildPmrMessages()
{
var protoProject = _projects.SingleOrDefault(x => x.Name == protoCliProjectName);
if (protoProject == null)
{
throw new NullReferenceException("Could not locate project " + protoCliProjectName);
}
SetVSProgress("Building project " + protoCliProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", protoProject.FullName, true);
if (DTE.Solution.SolutionBuild.LastBuildInfo > 0)
{
throw new ExternalException(protoCliProjectName + " failed to build!");
}
DTE.Solution.Properties.Item("StartupProject").Value = protoCliProjectName;
SetVSProgress("Executing Tango Proto Compiler...");
DTE.ExecuteCommand("Debug.Start");
WaitForWindowOpen("Tango Protobuf Compiler");
WaitForWindowClose("Tango Protobuf Compiler");
var project = _projects.SingleOrDefault(x => x.Name == pmrProjectName);
if (project == null)
{
throw new NullReferenceException("Could not locate project " + pmrProjectName);
}
SetVSProgress("Updating " + pmrProjectName + "...");
foreach (var file in Directory.GetFiles(Path.GetDirectoryName(project.FileName), "*.cs", SearchOption.AllDirectories))
{
String parentFolderName = Path.GetFileName(Path.GetDirectoryName(file));
if (parentFolderName != "Debug" && parentFolderName != "Release" && parentFolderName != "obj")
{
SetVSProgress("Adding/Updating file " + Path.GetFileName(file) + "...");
project.ProjectItems.AddFromFile(file);
Wait(10);
}
}
SetVSProgress("Building project " + pmrProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
if (DTE.Solution.SolutionBuild.LastBuildInfo > 0)
{
throw new ExternalException(pmrProjectName + " failed to build!");
}
}
private void GenerateSQLite()
{
var project = _projects.SingleOrDefault(x => x.Name == sqliteProjectName);
if (project == null)
{
throw new NullReferenceException("Could not locate project " + sqliteProjectName);
}
SetVSProgress("Building project " + sqliteProjectName + "...");
DTE.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
DTE.Solution.Properties.Item("StartupProject").Value = sqliteProjectName;
SetVSProgress("Executing SQLite generator...");
DTE.ExecuteCommand("Debug.Start");
WaitForWindowOpen("Tango SQLite Generator");
WaitForWindowClose("Tango SQLite Generator");
}
private void BuildSolution()
{
SetVSProgress("Building solution...");
DTE.Solution.SolutionBuild.Build(true);
if (DTE.Solution.SolutionBuild.LastBuildInfo > 0)
{
throw new ExternalException("Error building solution!");
}
}
#endregion
}
}