Various improvements to ProjectTask handling; still need to move Build launcher from SolutionExplorer to a generic Command (e.g. BuildAllProjects)

This commit is contained in:
Michael Becker 2014-12-10 14:45:10 -05:00
parent 12effa63da
commit f1ab02f7a9
12 changed files with 395 additions and 89 deletions

View File

@ -21,12 +21,25 @@
</Command>
<Command ID="FileNew" DefaultCommandID="FileNewDocument">
<Items>
<CommandReference CommandID="FileNewDocumentFileSystem" />
<Separator />
<CommandReference CommandID="FileNewDocument" />
<CommandReference CommandID="FileNewProject" />
</Items>
</Command>
<Command ID="FileNewDocument">
<Shortcut Modifiers="Control" Key="N" />
<Parameters>
<!-- This command takes one parameter which is not set by default -->
<Parameter Name="ObjectModelTypeName" />
</Parameters>
</Command>
<Command ID="FileNewDocumentFileSystem" ParentCommandID="FileNewDocument">
<!-- Execute FileNewDocument with the specified parameters -->
<ParameterValues>
<ParameterValue Name="ObjectModelTypeName" Value="UniversalEditor.ObjectModels.FileSystem.FileSystemObjectModel" />
</ParameterValues>
</Command>
<Command ID="FileNewProject">
<Shortcut Modifiers="Control,Shift" Key="N" />

View File

@ -12,21 +12,9 @@
<Action TypeID="{EE505E05-F125-4718-BA0A-879C72B5125A}">
<!-- ExecutableAction -->
<CommandLine>
<Conditional>
<Conditions>
<Condition Variable="OperatingSystemPlatform" Comparison="Equals" Value="Windows" />
</Conditions>
<TrueResult>
<GlobalVariableReference ID="MinGWPath" />
<PathSeparator />
<Literal Value="g++.exe" />
</TrueResult>
<FalseResult>
<Literal Value="g++" />
</FalseResult>
</Conditional>
<VariableReference Scope="Global" ID="CompilerExecutablePath" />
<Literal Value=" -o &quot;" />
<ProjectVariableReference ID="OutputFileName" />
<VariableReference Scope="Project" ID="OutputFileName" />
<Literal Value="&quot; " />
<Conditional>
<Conditions>
@ -49,7 +37,7 @@
<Condition VariableName="IncludeFiles.Length" Comparison="GreaterThan" Value="0" />
</Conditions>
<TrueResult>
<VariableArray Name="IncludeFiles" Prefix="-I" Separator=" " />
<VariableReference Scope="Project" Name="IncludeFiles" Prefix="-I" Separator=" " />
</TrueResult>
</Conditional>
<Conditional>
@ -57,7 +45,7 @@
<Condition VariableName="LibraryPaths.Length" Comparison="GreaterThan" Value="0" />
</Conditions>
<TrueResult>
<VariableArray Name="LibraryPaths" Prefix="-L" Separator=" " />
<VariableReference Scope="Project" Name="LibraryPaths" Prefix="-L" Separator=" " />
</TrueResult>
</Conditional>
<Conditional>
@ -65,10 +53,10 @@
<Condition VariableName="LibraryReferences.Length" Comparison="GreaterThan" Value="0" />
</Conditions>
<TrueResult>
<VariableArray Name="LibraryReferences" Prefix="-l" Separator=" " />
<VariableReference Scope="Project" Name="LibraryReferences" Prefix="-l" Separator=" " />
</TrueResult>
</Conditional>
<VariableArray Name="ProjectFiles" Separator=" " />
<ConstantReference Scope="Project" Name="ProjectFiles" Separator=" " />
</CommandLine>
</Action>
</Actions>

View File

@ -9,31 +9,19 @@
<Actions>
<Action TypeID="{EE505E05-F125-4718-BA0A-879C72B5125A}">
<CommandLine>
<Conditional>
<Conditions>
<Condition Variable="OperatingSystemPlatform" Comparison="Equals" Value="Windows" />
</Conditions>
<TrueResult>
<GlobalVariableReference ID="FrameworkPath" />
<PathSeparator />
<Literal Value="vbc.exe" />
</TrueResult>
<FalseResult>
<Literal Value="vbnc" />
</FalseResult>
</Conditional>
<VariableReference Scope="Global" ID="CompilerExecutablePath" />
<Literal Value=" /target:" />
<ProjectVariableReference ID="ProjectTarget" />
<VariableReference Scope="Project" ID="ProjectTarget" />
<Literal Value=" /out:&quot;" />
<ProjectVariableReference ID="OutputFileName" />
<VariableReference Scope="Project" ID="OutputFileName" />
<Literal Value="&quot;" />
<Literal Value=" /rootnamespace:" />
<ProjectVariableReference ID="RootNamespace" />
<VariableReference Scope="Project" ID="RootNamespace" />
<ProjectReferenceList ArrayItemPrefix="/reference:" ArrayItemSeparator=" " />
<ProjectFileList ArrayItemSeparator=" " />
<ConstantReference Scope="Project" ID="LibraryReferences" Prefix="/reference:" Separator=" " />
<ConstantReference Scope="Project" Separator=" " />
</CommandLine>
</Action>
</Actions>

View File

@ -11,25 +11,13 @@
<Actions>
<Action TypeID="{EE505E05-F125-4718-BA0A-879C72B5125A}">
<CommandLine>
<Conditional>
<Conditions>
<Condition Variable="OperatingSystemPlatform" Comparison="Equals" Value="Windows" />
</Conditions>
<TrueResult>
<GlobalVariableReference ID="FrameworkPath" />
<PathSeparator />
<Literal Value="csc.exe" />
</TrueResult>
<FalseResult>
<Literal Value="csc" />
</FalseResult>
</Conditional>
<VariableReference Scope="Global" ID="CompilerExecutablePath" />
<Literal Value=" /target:" />
<ProjectVariableReference ID="ProjectTarget" />
<VariableReference Scope="Project" ID="ProjectTarget" />
<Literal Value=" /out:&quot;" />
<ProjectVariableReference ID="OutputFileName" />
<VariableReference Scope="Project" ID="OutputFileName" />
<Literal Value="&quot; " />
<ProjectFiles Separator=" " />
<ConstantReference Scope="Project" ID="ProjectFiles" Separator=" " />
</CommandLine>
</Action>
</Actions>

View File

@ -10,12 +10,11 @@
<Task Title="Transform">
<Actions>
<Action TypeID="{EE505E05-F125-4718-BA0A-879C72B5125A}">
<FileName>C:\Program Files\Saxonica\bin\saxon.exe</FileName>
<Arguments>
<StringBuilder>
<ProjectFiles Separator=" " />
</StringBuilder>
</Arguments>
<CommandLine>
<VariableReference Scope="Global" ID="CompilerExecutablePath" />
<Literal Value=" " />
<ConstantReference Scope="Project" ID="ProjectFiles" />
</CommandLine>
</Action>
</Actions>
</Task>

View File

@ -52,6 +52,8 @@
<!-- File -->
<Command ID="File" Title="_File" />
<Command ID="FileNew" Title="_New" />
<Command ID="FileNewDocumentFileSystem" Title="_File System" />
<Command ID="FileNewDocument" Title="_Document..." />
<Command ID="FileNewProject" Title="_Project/Solution..." />

View File

@ -17,15 +17,13 @@
<Task Title="Build">
<Actions>
<Action TypeID="{EE505E05-F125-4718-BA0A-879C72B5125A}">
<FileName>$(ArduinoPath)\avr-gcc.exe</FileName>
<Arguments>
<StringBuilder>
<Literal Value="-o &quot;" />
<Variable Name="OutputFileName" />
<Literal Value="&quot; " />
<ProjectFiles Separator=" " />
</StringBuilder>
</Arguments>
<CommandLine>
<VariableReference Scope="Global" ID="ArduinoCompilerPath" />
<Literal Value=" -o &quot;" />
<VariableReference Scope="Project" ID="OutputFileName" />
<Literal Value="&quot; " />
<ConstantReference Scope="Project" ID="ProjectFiles" Separator=" " />
</CommandLine>
</Action>
</Actions>
</Task>

View File

@ -430,7 +430,11 @@ namespace UniversalEditor.DataFormats.UEPackage
if (attTypeID != null)
{
Guid id = new Guid(attTypeID.Value);
task.Actions.Add(ProjectTaskActionReference.GetByTypeID(id).Create());
ProjectTaskActionReference ptar = ProjectTaskActionReference.GetByTypeID(id);
ProjectTaskAction pta = ptar.Create();
pta.LoadFromMarkup(tagAction);
task.Actions.Add(pta);
}
}
}

View File

@ -2,9 +2,63 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniversalEditor.ObjectModels.Markup;
namespace UniversalEditor
{
public class ExpandedStringVariableStore
{
private ExpandedStringVariable.ExpandedStringVariableCollection mvarConstants = new ExpandedStringVariable.ExpandedStringVariableCollection();
public ExpandedStringVariable.ExpandedStringVariableCollection Constants { get { return mvarConstants; } }
private ExpandedStringVariable.ExpandedStringVariableCollection mvarVariables = new ExpandedStringVariable.ExpandedStringVariableCollection();
public ExpandedStringVariable.ExpandedStringVariableCollection Variables { get { return mvarVariables; } }
}
public class ExpandedStringVariable
{
private string mvarID = String.Empty;
public string ID { get { return mvarID; } set { mvarID = value; } }
private object mvarValue = null;
public object Value { get { return mvarValue; } set { mvarValue = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(mvarID);
sb.Append("=");
if (mvarValue == null)
{
sb.Append("(null)");
}
else
{
sb.Append("\"");
sb.Append(mvarValue.ToString());
sb.Append("\"");
}
return sb.ToString();
}
public class ExpandedStringVariableCollection
{
private Dictionary<ExpandedStringSegmentVariableScope, Dictionary<string, ExpandedStringVariable>> variables = new Dictionary<ExpandedStringSegmentVariableScope, Dictionary<string, ExpandedStringVariable>>();
public ExpandedStringVariable this[ExpandedStringSegmentVariableScope scope, string id]
{
get
{
if (!variables.ContainsKey(scope)) variables.Add(scope, new Dictionary<string, ExpandedStringVariable>());
if (!variables[scope].ContainsKey(id)) return null;
return variables[scope][id];
}
set
{
if (!variables.ContainsKey(scope)) variables.Add(scope, new Dictionary<string, ExpandedStringVariable>());
variables[scope][id] = value;
}
}
}
}
public class ExpandedString
{
public static readonly ExpandedString Empty = new ExpandedString();
@ -25,14 +79,76 @@ namespace UniversalEditor
public ExpandedStringSegment.ExpandedStringSegmentCollection Segments { get { return mvarSegments; } }
public override string ToString()
{
return mvarSegments.Count.ToString() + " segments";
}
public string ToString(ExpandedStringVariableStore variables)
{
StringBuilder sb = new StringBuilder();
foreach (ExpandedStringSegment segment in mvarSegments)
{
sb.Append(segment.ToString());
sb.Append(segment.ToString(variables));
}
return sb.ToString();
}
public static ExpandedString FromMarkup(MarkupTagElement markup)
{
ExpandedString value = new ExpandedString();
foreach (MarkupElement el in markup.Elements)
{
MarkupTagElement tag = (el as MarkupTagElement);
if (tag == null) continue;
switch (tag.FullName)
{
case "VariableReference":
case "ConstantReference":
{
MarkupAttribute attScope = tag.Attributes["Scope"];
ExpandedStringSegmentVariableScope scope = ExpandedStringSegmentVariableScope.None;
if (attScope != null)
{
switch (attScope.Value.ToLower())
{
case "file": scope = ExpandedStringSegmentVariableScope.File; break;
case "project": scope = ExpandedStringSegmentVariableScope.Project; break;
case "solution": scope = ExpandedStringSegmentVariableScope.Solution; break;
case "global": scope = ExpandedStringSegmentVariableScope.Global; break;
}
}
MarkupAttribute attID = tag.Attributes["ID"];
if (attID == null) continue;
string separator = ";";
MarkupAttribute attSeparator = tag.Attributes["Separator"];
if (attSeparator != null)
{
separator = attSeparator.Value;
}
if (tag.FullName == "VariableReference")
{
value.Segments.Add(new ExpandedStringSegmentVariable(attID.Value, scope, separator));
}
else if (tag.FullName == "ConstantReference")
{
value.Segments.Add(new ExpandedStringSegmentConstant(attID.Value, scope, separator));
}
break;
}
case "Literal":
{
MarkupAttribute attValue = tag.Attributes["Value"];
if (attValue == null) continue;
value.Segments.Add(new ExpandedStringSegmentLiteral(attValue.Value));
break;
}
}
}
return value;
}
}
public abstract class ExpandedStringSegment
{
@ -42,9 +158,9 @@ namespace UniversalEditor
}
private static readonly Dictionary<string, string> _empty = new Dictionary<string, string>();
private static readonly ExpandedStringVariableStore _empty = new ExpandedStringVariableStore();
public abstract string ToString(Dictionary<string, string> variables);
public abstract string ToString(ExpandedStringVariableStore variables);
public override string ToString()
{
return ToString(_empty);
@ -52,14 +168,51 @@ namespace UniversalEditor
}
public class ExpandedStringSegmentLiteral : ExpandedStringSegment
{
public ExpandedStringSegmentLiteral()
{
mvarValue = String.Empty;
}
public ExpandedStringSegmentLiteral(string value)
{
mvarValue = value;
}
private string mvarValue = String.Empty;
public string Value { get { return mvarValue; } set { mvarValue = value; } }
public override string ToString(Dictionary<string, string> variables)
public override string ToString(ExpandedStringVariableStore variables)
{
return mvarValue;
}
}
/// <summary>
/// The scope of an <see cref="ExpandedStringSegmentVariable" />.
/// </summary>
public enum ExpandedStringSegmentVariableScope
{
/// <summary>
/// No scope is defined for this variable. Automatically searches for the variable in this scope order: first
/// file scope, then project scope, then solution scope, and finally global scope.
/// </summary>
None = 0,
/// <summary>
/// The variable is defined at the file level.
/// </summary>
File = 1,
/// <summary>
/// The variable is defined at the project level.
/// </summary>
Project = 2,
/// <summary>
/// The variable is defined at the solution level.
/// </summary>
Solution = 3,
/// <summary>
/// The variable is defined at the global level.
/// </summary>
Global = 4
}
/// <summary>
/// Represents a string segment whose value is populated by a variable.
/// </summary>
@ -71,13 +224,36 @@ namespace UniversalEditor
/// </summary>
public string VariableName { get { return mvarVariableName; } set { mvarVariableName = value; } }
private ExpandedStringSegmentVariableScope mvarScope = ExpandedStringSegmentVariableScope.None;
/// <summary>
/// The scope of the variable to search for, or <see cref="ExpandedStringSegmentVariableScope.None" /> to
/// search all scopes in the order of file, project, solution, global.
/// </summary>
public ExpandedStringSegmentVariableScope Scope { get { return mvarScope; } set { mvarScope = value; } }
private string mvarSeparator = String.Empty;
/// <summary>
/// The array separator to use when the value of the variable is an array.
/// </summary>
public string Separator { get { return mvarSeparator; } set { mvarSeparator = value; } }
/// <summary>
/// Creates a new instance of <see cref="ExpandedStringSegmentVariable" /> with the given variable name.
/// </summary>
/// <param name="variableName">The name of the variable in the variables dictionary from which to retrieve the value for this <see cref="ExpandedStringSegment" />.</param>
public ExpandedStringSegmentVariable(string variableName)
/// <param name="variableName">
/// The name of the variable in the variables dictionary from which to retrieve the value for this
/// <see cref="ExpandedStringSegment" />.
/// </param>
/// <param name="scope">
/// The scope of the variable to search for, or <see cref="ExpandedStringSegmentVariableScope.None" /> to
/// search all scopes in the order of file, project, solution, global.
/// </param>
/// <param name="separator">The array separator to use when the value of the variable is an array.</param>
public ExpandedStringSegmentVariable(string variableName, ExpandedStringSegmentVariableScope scope = ExpandedStringSegmentVariableScope.None, string separator = null)
{
mvarVariableName = variableName;
mvarScope = scope;
mvarSeparator = separator;
}
/// <summary>
@ -85,9 +261,71 @@ namespace UniversalEditor
/// </summary>
/// <param name="variables">The variables to pass into the <see cref="ExpandedStringSegment" />.</param>
/// <returns>A <see cref="String" /> that contains the value of this <see cref="ExpandedStringSegment" />.</returns>
public override string ToString(Dictionary<string, string> variables)
public override string ToString(ExpandedStringVariableStore variables)
{
return variables[mvarVariableName];
ExpandedStringVariable varr = variables.Variables[mvarScope, mvarVariableName];
if (varr != null && varr.Value != null) return varr.Value.ToString();
return String.Empty;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Variable: \"");
sb.Append(mvarVariableName);
sb.Append("\" (");
sb.Append(mvarScope.ToString());
sb.Append(" scope)");
if (!String.IsNullOrEmpty(mvarSeparator))
{
sb.Append(" (Array; separator=\"");
sb.Append(mvarSeparator);
sb.Append("\")");
}
return sb.ToString();
}
}
public class ExpandedStringSegmentConstant : ExpandedStringSegmentVariable
{
/// <summary>
/// Creates a new instance of <see cref="ExpandedStringSegmentVariable" /> with the given variable name.
/// </summary>
/// <param name="variableName">
/// The name of the variable in the variables dictionary from which to retrieve the value for this
/// <see cref="ExpandedStringSegment" />.
/// </param>
/// <param name="scope">
/// The scope of the variable to search for, or <see cref="ExpandedStringSegmentVariableScope.None" /> to
/// search all scopes in the order of file, project, solution, global.
/// </param>
/// <param name="separator">The array separator to use when the value of the variable is an array.</param>
public ExpandedStringSegmentConstant(string variableName, ExpandedStringSegmentVariableScope scope = ExpandedStringSegmentVariableScope.None, string separator = null)
: base(variableName, scope, separator)
{
}
public override string ToString(ExpandedStringVariableStore variables)
{
ExpandedStringVariable varr = variables.Constants[Scope, VariableName];
if (varr != null && varr.Value != null) return varr.Value.ToString();
return String.Empty;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Constant: \"");
sb.Append(VariableName);
sb.Append("\" (");
sb.Append(Scope.ToString());
sb.Append(" scope)");
if (!String.IsNullOrEmpty(Separator))
{
sb.Append(" (Array; separator=\"");
sb.Append(Separator);
sb.Append("\")");
}
return sb.ToString();
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniversalEditor.ObjectModels.Markup;
namespace UniversalEditor
{
@ -13,32 +14,73 @@ namespace UniversalEditor
}
public event EventHandler TaskStarted;
public event ProjectTaskEventHandler TaskCompleted;
public event ProjectTaskEventHandler TaskFailed;
public event ProgressEventHandler TaskProgress;
protected virtual void OnTaskStarted(EventArgs e)
{
if (TaskStarted != null) TaskStarted(this, e);
}
protected virtual void OnTaskCompleted(ProjectTaskEventArgs e)
{
if (TaskCompleted != null) TaskCompleted(this, e);
}
protected virtual void OnTaskFailed(ProjectTaskEventArgs e)
{
if (TaskFailed != null) TaskFailed(this, e);
}
protected virtual void OnTaskProgress(ProgressEventArgs e)
{
if (TaskProgress != null) TaskProgress(this, e);
}
private ProjectTaskAction.ProjectTaskActionCollection mvarActions = new ProjectTaskAction.ProjectTaskActionCollection();
public ProjectTaskAction.ProjectTaskActionCollection Actions { get { return mvarActions; } }
private string mvarTitle = String.Empty;
public string Title { get { return mvarTitle; } set { mvarTitle = value; } }
public void Execute(ProgressEventHandler progressEventHandler = null)
public void Execute()
{
OnTaskStarted(EventArgs.Empty);
ExpandedStringVariableStore variables = new ExpandedStringVariableStore();
ExpandedStringVariable varr = new ExpandedStringVariable();
varr.ID = "CompilerExecutablePath";
varr.Value = @"C:\Applications\MinGW\bin\gcc.exe";
variables.Variables[ExpandedStringSegmentVariableScope.Global, "CompilerExecutablePath"] = varr;
varr = new ExpandedStringVariable();
varr.ID = "OutputFileName";
varr.Value = @"C:\Temp\ProjectOutput.exe";
variables.Variables[ExpandedStringSegmentVariableScope.Project, "OutputFileName"] = varr;
for (int i = 0; i < mvarActions.Count; i++)
{
mvarActions[i].Execute();
if (progressEventHandler != null)
try
{
progressEventHandler(this, new ProgressEventArgs(i, mvarActions.Count, mvarActions[i].Title));
mvarActions[i].Execute(variables);
}
catch (Exception ex)
{
OnTaskFailed(new ProjectTaskEventArgs(ex.Message));
return;
}
OnTaskProgress(new ProgressEventArgs(i, mvarActions.Count, mvarActions[i].Title));
}
}
}
public abstract class ProjectTaskAction : References<ProjectTaskActionReference>
{
public abstract string Title { get; }
protected abstract void ExecuteInternal();
protected abstract void ExecuteInternal(ExpandedStringVariableStore variables);
public void Execute()
public void Execute(ExpandedStringVariableStore variables)
{
ExecuteInternal();
ExecuteInternal(variables);
}
public class ProjectTaskActionCollection
@ -51,6 +93,14 @@ namespace UniversalEditor
{
return new ProjectTaskActionReference(GetType());
}
public void LoadFromMarkup(MarkupTagElement tag)
{
if (tag == null) return;
if (tag.FullName != "Action") return;
LoadFromMarkupInternal(tag);
}
protected abstract void LoadFromMarkupInternal(MarkupTagElement tag);
}
public class ProjectTaskActionReference : ReferencedBy<ProjectTaskAction>
{
@ -148,9 +198,9 @@ namespace UniversalEditor
}
}
protected override void ExecuteInternal()
protected override void ExecuteInternal(ExpandedStringVariableStore variables)
{
string fileNameWithArguments = mvarCommandLine.ToString();
string fileNameWithArguments = mvarCommandLine.ToString(variables);
if (String.IsNullOrEmpty(fileNameWithArguments)) return;
string[] fileNameArgumentsSplit = fileNameWithArguments.Split(new char[] { ' ' }, "\"", StringSplitOptions.None, 2);
@ -160,12 +210,30 @@ namespace UniversalEditor
if (!System.IO.File.Exists(fileName)) throw new System.IO.FileNotFoundException(fileName);
System.Diagnostics.Process p = new System.Diagnostics.Process();
StringBuilder sbArguments = new StringBuilder();
// TODO: complete loading arguments
p.StartInfo = new System.Diagnostics.ProcessStartInfo(fileName, arguments);
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
p.WaitForExit();
string error = p.StandardError.ReadToEnd();
string output = p.StandardOutput.ReadToEnd();
if (!String.IsNullOrEmpty(error))
{
throw new Exception(error);
}
}
protected override void LoadFromMarkupInternal(MarkupTagElement tag)
{
MarkupTagElement tagCommandLine = (tag.Elements["CommandLine"] as MarkupTagElement);
if (tagCommandLine != null)
{
mvarCommandLine = ExpandedString.FromMarkup(tagCommandLine);
}
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor
{
public delegate void ProjectTaskEventHandler(object sender, ProjectTaskEventArgs e);
public class ProjectTaskEventArgs : EventArgs
{
private string mvarMessage = String.Empty;
public string Message { get { return mvarMessage; } set { mvarMessage = value; } }
public ProjectTaskEventArgs(string message)
{
mvarMessage = message;
}
}
}

View File

@ -111,6 +111,7 @@
<Compile Include="ObjectModels\Text\Plain\PlainTextObjectModel.cs" />
<Compile Include="ObjectModels\UEPackage\UEPackageObjectModel.cs" />
<Compile Include="ProjectTask.cs" />
<Compile Include="ProjectTaskEvent.cs" />
<Compile Include="ProjectType.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Template.cs" />