aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs')
-rw-r--r--Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs598
1 files changed, 598 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs b/Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs
new file mode 100644
index 000000000..d462e5f75
--- /dev/null
+++ b/Software/Visual_Studio/Tango.BuildExtensions/TangoBuildCommand.cs
@@ -0,0 +1,598 @@
+//------------------------------------------------------------------------------
+// <copyright file="TangoBuildCommand.cs" company="Company">
+// Copyright (c) Company. All rights reserved.
+// </copyright>
+//------------------------------------------------------------------------------
+
+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
+{
+ /// <summary>
+ /// Command handler
+ /// </summary>
+ internal sealed class TangoBuildCommand
+ {
+ private DTE2 _dte;
+ private IList<Project> _projects;
+ private SelectForm _form;
+ 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 pmrGeneratorProjectName = "Tango.PMRGenerator.CLI";
+ private const String pmrProjectName = "Tango.PMR";
+
+ #region Redundant
+
+ /// <summary>
+ /// Command ID.
+ /// </summary>
+ public const int CommandId = 0x0100;
+
+ /// <summary>
+ /// Command menu group (command set GUID).
+ /// </summary>
+ public static readonly Guid CommandSet = new Guid("c03a7b01-8109-4ec5-8f90-858bed027e5d");
+
+ /// <summary>
+ /// VS Package that provides this command, not null.
+ /// </summary>
+ private readonly Package package;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TangoBuildCommand"/> class.
+ /// Adds our command handlers for menu (commands must exist in the command table file)
+ /// </summary>
+ /// <param name="package">Owner package, not null.</param>
+ private TangoBuildCommand(Package 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);
+ }
+ }
+
+ /// <summary>
+ /// Gets the instance of the command.
+ /// </summary>
+ public static TangoBuildCommand Instance
+ {
+ get;
+ private set;
+ }
+
+ /// <summary>
+ /// Gets the service provider from the owner package.
+ /// </summary>
+ private IServiceProvider ServiceProvider
+ {
+ get
+ {
+ return this.package;
+ }
+ }
+
+ /// <summary>
+ /// Initializes the singleton instance of the command.
+ /// </summary>
+ /// <param name="package">Owner package, not null.</param>
+ public static void Initialize(Package package)
+ {
+ Instance = new TangoBuildCommand(package);
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="sender">Event sender.</param>
+ /// <param name="e">Event args.</param>
+ private void MenuItemCallback(object sender, EventArgs e)
+ {
+ Start();
+ }
+
+ #endregion
+
+ #region Main
+
+ private void Start()
+ {
+ _form = null;
+
+ BuildForm buildForm = new BuildForm();
+ if (buildForm.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
+
+ System.Threading.Tasks.Task.Factory.StartNew(() =>
+ {
+ _projects = Projects().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);
+
+ OpenProgressForm();
+
+ try
+ {
+ if (buildForm.UpdateDataBaseEntities)
+ {
+ UpdateDatabaseEntities();
+ }
+ if (buildForm.GenerateAndBuildObservables)
+ {
+ GenerateAndBuildObservables();
+ }
+ if (buildForm.GenerateAutoPmrMessages)
+ {
+ GenerateAutoPMRMessages();
+ }
+ if (buildForm.UpdateAndBuildPmrMessages)
+ {
+ UpdateAndBuildPmrMessages();
+ }
+ if (buildForm.BuildSolution)
+ {
+ BuildSolution();
+ }
+
+ SetStatusText("Done!");
+ Wait(1000);
+ CloseProgressForm();
+ }
+ catch (Exception ex)
+ {
+ CloseProgressForm();
+ ShowMessage(ex.Message);
+ }
+ });
+ }
+
+ 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<ProjectItem>().ToList();
+
+ SetStatusText("Locating " + edmxModelName + " scheme...");
+
+ var items = GetProjectItemsDeep(project);
+
+ var edmx = GetProjectItemsDeep(project).SingleOrDefault(x => x.Name == edmxModelName);
+
+ if (edmx == null)
+ {
+ throw new NullReferenceException("Could not locate " + edmxModelName + "!");
+ }
+
+ SetStatusText("Expanding diagram...");
+
+ edmx.ExpandView();
+
+ SetStatusText("Opening edmx diagram window...");
+
+ Window win = edmx.Open(EnvDTE.Constants.vsViewKindPrimary);
+ win.Visible = true;
+
+ SetStatusText("Waiting for edmx diagram window...");
+
+ _window.WaitTill(() => _window.Get(SearchCriteria.ByText(edmxModelName + " [Diagram1]")) != null);
+
+ SetStatusText("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();
+
+ SetStatusText("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);
+
+ SetStatusText("Generating edmx scheme...");
+
+ WaitForWindowClose("Update Wizard");
+
+ _window.WaitWhileBusy();
+
+ SetStatusText("Saving changes...");
+
+ win.Close(vsSaveChanges.vsSaveChangesYes);
+
+ _window.WaitWhileBusy();
+
+ foreach (var template in edmx.ProjectItems.OfType<ProjectItem>().Where(x => x.Name.EndsWith(".tt")))
+ {
+ SetStatusText("Running custom tool for " + template.Name + "...");
+ (template.Object as VSProjectItem).RunCustomTool();
+ _window.WaitWhileBusy();
+ }
+
+ _window.WaitWhileBusy();
+
+ SetStatusText("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);
+ }
+
+ SetStatusText("Building project " + observablesGeneratorProjectName + "...");
+
+ _dte.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
+
+ _dte.Solution.Properties.Item("StartupProject").Value = observablesGeneratorProjectName;
+
+ SetStatusText("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);
+ }
+
+ SetStatusText("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")
+ {
+ SetStatusText("Adding/Updating file " + Path.GetFileName(file) + "...");
+ observablesProject.ProjectItems.AddFromFile(file);
+ Wait(10);
+ }
+ }
+
+ SetStatusText("Building project " + observablesProjectName + "...");
+
+ _dte.Solution.SolutionBuild.BuildProject("Debug", observablesProject.FullName, true);
+
+ if (_dte.Solution.SolutionBuild.LastBuildInfo > 0)
+ {
+ throw new ExternalException(observablesProjectName + " failed to build!");
+ }
+ }
+
+ private void GenerateAutoPMRMessages()
+ {
+ var project = _projects.SingleOrDefault(x => x.Name == pmrGeneratorProjectName);
+
+ if (project == null)
+ {
+ throw new NullReferenceException("Could not locate project " + pmrGeneratorProjectName);
+ }
+
+ SetStatusText("Building project " + pmrGeneratorProjectName + "...");
+
+ _dte.Solution.SolutionBuild.BuildProject("Debug", project.FullName, true);
+
+ _dte.Solution.Properties.Item("StartupProject").Value = pmrGeneratorProjectName;
+
+ SetStatusText("Executing PMR generator...");
+
+ _dte.ExecuteCommand("Debug.Start");
+
+ WaitForWindowOpen("Tango PMR Generator");
+
+ WaitForWindowClose("Tango PMR Generator");
+ }
+
+ private void UpdateAndBuildPmrMessages()
+ {
+ var project = _projects.SingleOrDefault(x => x.Name == pmrProjectName);
+
+ if (project == null)
+ {
+ throw new NullReferenceException("Could not locate project " + pmrProjectName);
+ }
+
+ SetStatusText("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")
+ {
+ SetStatusText("Adding/Updating file " + Path.GetFileName(file) + "...");
+ project.ProjectItems.AddFromFile(file);
+ Wait(10);
+ }
+ }
+
+ SetStatusText("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 BuildSolution()
+ {
+ SetStatusText("Building solution...");
+ _dte.Solution.SolutionBuild.Build(true);
+
+ if (_dte.Solution.SolutionBuild.LastBuildInfo > 0)
+ {
+ throw new ExternalException("Error building solution!");
+ }
+ }
+
+ #endregion
+
+ #region Solution & Projects
+
+ public DTE2 GetActiveIDE()
+ {
+ // Get an instance of currently running Visual Studio IDE.
+ DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2;
+ _dte = dte2;
+ return dte2;
+ }
+
+ public IList<Project> Projects()
+ {
+ Projects projects = GetActiveIDE().Solution.Projects;
+ List<Project> list = new List<Project>();
+ var item = projects.GetEnumerator();
+ while (item.MoveNext())
+ {
+ var project = item.Current as Project;
+ if (project == null)
+ {
+ continue;
+ }
+
+ if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder)
+ {
+ list.AddRange(GetSolutionFolderProjects(project));
+ }
+ else
+ {
+ list.Add(project);
+ }
+ }
+
+ return list;
+ }
+
+ private IEnumerable<Project> GetSolutionFolderProjects(Project solutionFolder)
+ {
+ List<Project> list = new List<Project>();
+ for (var i = 1; i <= solutionFolder.ProjectItems.Count; i++)
+ {
+ var subProject = solutionFolder.ProjectItems.Item(i).SubProject;
+ if (subProject == null)
+ {
+ continue;
+ }
+
+ // If this is another solution folder, do a recursive call, otherwise add
+ if (subProject.Kind == ProjectKinds.vsProjectKindSolutionFolder)
+ {
+ list.AddRange(GetSolutionFolderProjects(subProject));
+ }
+ else
+ {
+ list.Add(subProject);
+ }
+ }
+ return list;
+ }
+
+ private List<ProjectItem> GetProjectItemsDeep(Project project)
+ {
+ List<ProjectItem> results = new List<ProjectItem>();
+ FillProjectItems(project.ProjectItems.OfType<ProjectItem>().ToList(), results);
+ return results;
+ }
+
+ private void FillProjectItems(List<ProjectItem> rootItems, List<ProjectItem> results)
+ {
+ foreach (var item in rootItems)
+ {
+ results.Add(item);
+
+ if (item.ProjectItems.Count > 0)
+ {
+ FillProjectItems(item.ProjectItems.OfType<ProjectItem>().ToList(), results);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Notifications
+
+ private void WriteToConsole(String text)
+ {
+ // Get the output window
+ var outputWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
+
+ // Ensure that the desired pane is visible
+ var paneGuid = Microsoft.VisualStudio.VSConstants.OutputWindowPaneGuid.GeneralPane_guid;
+ IVsOutputWindowPane pane;
+ outputWindow.CreatePane(paneGuid, "General", 1, 0);
+ outputWindow.GetPane(paneGuid, out pane);
+
+ // Output the message
+ pane.OutputString(text + Environment.NewLine);
+ }
+
+ private void ShowMessage(String text)
+ {
+ // Show a message box to prove we were here
+
+ VsShellUtilities.ShowMessageBox(
+ ServiceProvider,
+ text,
+ "Tango Initializer",
+ OLEMSGICON.OLEMSGICON_INFO,
+ OLEMSGBUTTON.OLEMSGBUTTON_OK,
+ OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
+ }
+
+ #endregion
+
+ #region Windows API
+
+ private WindowInfo WaitForWindowOpen(String title)
+ {
+ WindowInfo window = null;
+
+ do
+ {
+ window = WindowInfo.GetAllWindows().SelectMany(x => x.Children).FirstOrDefault(x => x.Caption == title);
+ } while (window == null);
+
+ return window;
+ }
+
+ private void WaitForWindowClose(String title)
+ {
+ while (WindowInfo.GetAllWindows().SelectMany(x => x.Children).ToList().Exists(x => x.Caption == title))
+ {
+ System.Threading.Thread.Sleep(100);
+ }
+ }
+
+ #endregion
+
+ #region Threading
+
+ private void Wait(int milli)
+ {
+ System.Threading.Thread.Sleep(milli);
+ }
+
+ #endregion
+
+ #region Status Form
+
+ private void OpenProgressForm()
+ {
+ System.Threading.Thread thread = new System.Threading.Thread(() =>
+ {
+ _form = new SelectForm();
+ var handle = _form.Handle;
+ _form.ShowDialog();
+ });
+
+ thread.SetApartmentState(System.Threading.ApartmentState.STA);
+ thread.Start();
+
+ while (_form == null || !_form.IsHandleCreated) { }
+ }
+
+ private void SetStatusText(String text)
+ {
+ _form.Invoke(new Action(() =>
+ {
+ _form.SetStatus(text);
+ }));
+ }
+
+ private void CloseProgressForm()
+ {
+ _form.Invoke(new Action(() =>
+ {
+ _form.Close();
+ _form = null;
+ }));
+ }
+
+ #endregion
+ }
+}