//------------------------------------------------------------------------------ // // 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 } }