public override void Execute()
{
if (!(hostContext.Data["EnabledRenderers"] as StringCollection).Contains(this.Identifier)) return;
// Get parameters
Dictionary<String, StringCollection> parameters = hostContext.Data["CommandParameters"] as Dictionary<String, StringCollection>;
System.Diagnostics.Trace.WriteLine("\r\nStarting RIMBA Renderer", "information");
StringCollection genFormatters = new StringCollection();
bool makeWP7Proj = false;
if (hostContext.Mode == Pipeline.OperationModeType.Quirks)
System.Diagnostics.Trace.WriteLine("--- WARNING ---\r\n Host context is operating in Quirks mode, GPMR cannot guarantee output will be accurate\r\n--- WARNING ---");
#region Validate all parameters
// Validate parameters
if (!parameters.ContainsKey("rimbapi-api-ns"))
{
parameters.Add("rimbapi-api-ns", new StringCollection());
parameters["rimbapi-api-ns"].Add("MARC.Everest");
}
if (!parameters.ContainsKey("rimbapi-target-ns"))
{
parameters.Add("rimbapi-target-ns", new StringCollection());
parameters["rimbapi-target-ns"].Add("output");
}
if (parameters.ContainsKey("rimbapi-root-class"))
RootClass = parameters["rimbapi-root-class"][0];
if (parameters.ContainsKey("rimbapi-gen-vocab"))
GenerateVocab = Convert.ToBoolean(parameters["rimbapi-gen-vocab"][0]);
if(parameters.ContainsKey("rimbapi-gen-rim"))
GenerateRim = Convert.ToBoolean(parameters["rimbapi-gen-rim"][0]);
if (parameters.ContainsKey("rimbapi-profileid"))
InteractionRenderer.profileId = parameters["rimbapi-profileid"][0];
if (parameters.ContainsKey("rimbapi-oid-profileid"))
InteractionRenderer.profileIdOid = parameters["rimbapi-oid-profileid"][0];
if (parameters.ContainsKey("rimbapi-oid-interactionid"))
InteractionRenderer.interactionIdOid = parameters["rimbapi-oid-interactionid"][0];
if (parameters.ContainsKey("rimbapi-oid-triggerevent"))
InteractionRenderer.triggerEventOid = parameters["rimbapi-oid-triggerevent"][0];
if (parameters.ContainsKey("rimbapi-gen-its"))
genFormatters = parameters["rimbapi-gen-its"];
if (parameters.ContainsKey("rimbapi-phone"))
makeWP7Proj = bool.Parse(parameters["rimbapi-phone"][0]);
#endregion
// Initialize Heuristics
MohawkCollege.EHR.gpmr.Pipeline.Renderer.RimbaCS.HeuristicEngine.Datatypes.Initialize(parameters["rimbapi-api-ns"][0]);
MohawkCollege.EHR.gpmr.Pipeline.Renderer.RimbaCS.HeuristicEngine.Interfaces.Initialize(parameters["rimbapi-api-ns"][0]);
// Get our repository ready
ClassRepository classRep = hostContext.Data["SourceCR"] as ClassRepository;
string ProjectFileName = "output.csproj"; // Set the output file name
if (parameters.ContainsKey("rimbapi-target-ns"))
ProjectFileName = parameters["rimbapi-target-ns"][0];
if(parameters.ContainsKey("rimbapi-partials"))
RenderPartials = Boolean.Parse(parameters["rimbapi-partials"][0]);
if (parameters.ContainsKey("rimbapi-realm-pref"))
prefRealm = parameters["rimbapi-realm-pref"][0];
if (parameters.ContainsKey("rimbapi-max-literals"))
MaxLiterals = Int32.Parse(parameters["rimbapi-max-literals"][0]);
if (parameters.ContainsKey("rimbapi-suppress-doc"))
SuppressDoc = Boolean.Parse(parameters["rimbapi-suppress-doc"][0]);
// Setup the template parameters
string[][] templateFields = new string[][]
{
new string[] { "$license$", parameters.ContainsKey("rimbapi-license") ? Licenses.ResourceManager.GetString(parameters["rimbapi-license"][0].ToUpper()) : "" },
new string[] { "$org$", parameters.ContainsKey("rimbapi-org") ? parameters["rimbapi-org"][0] : "" },
new string[] { "$date$", DateTime.Now.ToString("yyyy-MM-dd") },
new string[] { "$clrversion$", Environment.Version.ToString() },
new string[] { "$time$", DateTime.Now.ToString("HH:mm:ss") },
new string[] { "$author$", SystemInformation.UserName },
new string[] { "$year$", DateTime.Now.Year.ToString() },
new string[] { "$version$", Assembly.GetEntryAssembly().GetName().Version.ToString() },
new string[] { "$guid$", Guid.NewGuid().ToString() },
new string[] { "$name$", ProjectFileName },
new string[] { "$mrversion$", InteractionRenderer.profileId ?? "" }
};
// Now we want to scan our assembly for FeatureRenderers
List<KeyValuePair<FeatureRendererAttribute, IFeatureRenderer>> renderers = new List<KeyValuePair<FeatureRendererAttribute, IFeatureRenderer>>();
foreach(Type t in this.GetType().Assembly.GetTypes())
if (t.GetInterface("MohawkCollege.EHR.gpmr.Pipeline.Renderer.RimbaCS.Interfaces.IFeatureRenderer") != null &&
t.GetCustomAttributes(typeof(FeatureRendererAttribute), true).Length > 0)
{
foreach(FeatureRendererAttribute feature in (t.GetCustomAttributes(typeof(FeatureRendererAttribute), true)))
{
// Only one feature renderer per feature, so if the dictionary throws an exception
// on the add it is ok
renderers.Add(new KeyValuePair<FeatureRendererAttribute,IFeatureRenderer>(feature, (IFeatureRenderer)t.Assembly.CreateInstance(t.FullName)));
}
}
#region Setup the project
// Create engine reference
Microsoft.Build.BuildEngine.Engine engine = new Microsoft.Build.BuildEngine.Engine(
Path.Combine(Path.Combine(Path.Combine(System.Environment.SystemDirectory, "..\\Microsoft.NET"), "Framework"), "v3.5")),
phoneEngine = new Microsoft.Build.BuildEngine.Engine(
Path.Combine(Path.Combine(Path.Combine(System.Environment.SystemDirectory, "..\\Microsoft.NET"), "Framework"), "v4.0.30319"));
// Create MSPROJ
Microsoft.Build.BuildEngine.Project project = new Microsoft.Build.BuildEngine.Project(engine),
phoneProj = new Project(phoneEngine, "4.0");
phoneProj.DefaultTargets = project.DefaultTargets = "Build";
// Setup project attributes
Microsoft.Build.BuildEngine.BuildPropertyGroup pg = project.AddNewPropertyGroup(false);
Microsoft.Build.BuildEngine.BuildProperty property = pg.AddNewProperty("Configuration", "Release");
property.Condition = "'$(Configuration)' == ''";
property = pg.AddNewProperty("Platform", "AnyCPU");
property.Condition = "'$(Platform)' == ''";
pg.AddNewProperty("ProductVersion", "10.0.20506");
pg.AddNewProperty("SchemaVersion", "2.0");
pg.AddNewProperty("ProjectGuid", Guid.NewGuid().ToString());
pg.AddNewProperty("OutputType", "Library");
pg.AddNewProperty("AppDesignerFolder", "Properties");
pg.AddNewProperty("RootNamespace", parameters["rimbapi-target-ns"][0]);
pg.AddNewProperty("AssemblyName", parameters["rimbapi-target-ns"][0]);
// Release AnyCPU
pg = project.AddNewPropertyGroup(false);
pg.Condition = "'$(Configuration)|$(Platform)' == 'Release|AnyCPU'";
pg.AddNewProperty("DebugType", "pdbonly");
pg.AddNewProperty("Optimize", "true");
pg.AddNewProperty("OutputPath", "bin\\release");
pg.AddNewProperty("DefineConstants", "TRACE");
pg.AddNewProperty("ErrorReport", "prompt");
pg.AddNewProperty("WarningLevel", "4");
pg.AddNewProperty("DocumentationFile", "bin\\release\\" + parameters["rimbapi-target-ns"][0] + ".xml");
// Create Dir Structure
Directory.CreateDirectory(Path.Combine(hostContext.Output, "bin"));
Directory.CreateDirectory(Path.Combine(hostContext.Output, "lib"));
Directory.CreateDirectory(Path.Combine(hostContext.Output, "Properties"));
Directory.CreateDirectory(Path.Combine(hostContext.Output, "Vocabulary"));
Directory.CreateDirectory(Path.Combine(hostContext.Output, "Interaction"));
// Add reference structure
Microsoft.Build.BuildEngine.BuildItemGroup refItemGroup = project.AddNewItemGroup();
// Add References
File.Copy(Path.Combine(System.Windows.Forms.Application.StartupPath, "MARC.Everest.dll"), Path.Combine(Path.Combine(hostContext.Output, "lib"), "MARC.Everest.dll"), true);
if(makeWP7Proj)
File.Copy(Path.Combine(Path.Combine(System.Windows.Forms.Application.StartupPath, "lib"), "MARC.Everest.Phone.dll"), Path.Combine(Path.Combine(hostContext.Output, "lib"), "MARC.Everest.Phone.dll"), true);
File.Copy(Path.Combine(System.Windows.Forms.Application.StartupPath, "MARC.Everest.xml"), Path.Combine(Path.Combine(hostContext.Output, "lib"), "MARC.Everest.xml"), true);
refItemGroup.AddNewItem("Reference", "System");
refItemGroup.AddNewItem("Reference", "System.Drawing");
refItemGroup.AddNewItem("Reference", "System.Xml");
Microsoft.Build.BuildEngine.BuildItem buildItem = refItemGroup.AddNewItem("Reference", @"MARC.Everest");
buildItem.SetMetadata("SpecificVersion", "false");
buildItem.SetMetadata("HintPath", "lib\\MARC.Everest.dll");
project.AddNewImport("$(MSBuildBinPath)\\Microsoft.CSharp.targets", null);
Microsoft.Build.BuildEngine.BuildItemGroup fileItemGroup = project.AddNewItemGroup(),
phoneFileItemGroup = phoneProj.AddNewItemGroup();
#region Assembly Info
try
{
TextWriter tw = File.CreateText(Path.Combine(Path.Combine(hostContext.Output, "Properties"), "AssemblyInfo.cs"));
try
{
string Header = Template.AssemblyInfo; // Set the header to the default
// Populate template fields
foreach (String[] st in templateFields)
Header = Header.Replace(st[0], st[1]);
// Write header
tw.Write(Header);
}
finally
{
tw.Close();
}
fileItemGroup.AddNewItem("Compile", Path.Combine("Properties", "AssemblyInfo.cs"));
phoneFileItemGroup.AddNewItem("Compile", Path.Combine("Properties", "AssemblyInfo.cs"));
}
catch(Exception)
{
System.Diagnostics.Trace.WriteLine("Couldn't generate the AssemblyInfo.cs file for this project", "warn");
}
#endregion
#endregion
#region Code Create
// Convert class rep to list
List<Feature> features = new List<Feature>();
foreach (KeyValuePair<String, Feature> kv in classRep)
features.Add(kv.Value);
// Sort so classes are processed first
features.Sort(delegate(Feature a, Feature b)
{
if ((a is SubSystem) && !(b is SubSystem)) return -1;
else if ((b is SubSystem) && !(a is SubSystem)) return 1;
else return a.GetType().Name.CompareTo(b.GetType().Name);
});
RenderFeatureList(features, templateFields, renderers, fileItemGroup, phoneFileItemGroup, parameters);
// Any added features?
// HACK: This should be fixed soon, but meh... I'll get around to it
List<Feature> addlFeatures = new List<Feature>();
foreach (KeyValuePair<String, Feature> kv in classRep)
if(!features.Contains(kv.Value))
addlFeatures.Add(kv.Value);
RenderFeatureList(addlFeatures, templateFields, renderers, fileItemGroup, phoneFileItemGroup, parameters);
// Save the project
project.Save(Path.Combine(hostContext.Output, ProjectFileName) + ".csproj");
#endregion
// Compile?
#region Compile this project
// Does the user want to compile?
if (parameters.ContainsKey("rimbapi-compile") && Convert.ToBoolean(parameters["rimbapi-compile"][0]))
{
string logPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); // Create log
Microsoft.Build.BuildEngine.FileLogger logger = new Microsoft.Build.BuildEngine.FileLogger();
logger.Parameters = "logfile=" + logPath;
engine.RegisterLogger(logger);
System.Diagnostics.Trace.Write(String.Format("Compiling project (Build log {0})...", logPath), "information");
// Compile
if (engine.BuildProject(project))
System.Diagnostics.Trace.WriteLine("Success!", "information");
else
{
System.Diagnostics.Trace.WriteLine("Fail", "information");
throw new InvalidOperationException("Failed compilation, operation cannot continue");
}
engine.UnregisterAllLoggers();
}
#endregion
#region Windows Phone
if (makeWP7Proj)
{
// Setup project attributes
pg = phoneProj.AddNewPropertyGroup(false);
property = pg.AddNewProperty("Configuration", "Release");
property.Condition = "'$(Configuration)' == ''";
property = pg.AddNewProperty("Platform", "AnyCPU");
property.Condition = "'$(Platform)' == ''";
pg.AddNewProperty("ProductVersion", "10.0.20506");
pg.AddNewProperty("SchemaVersion", "2.0");
pg.AddNewProperty("ProjectGuid", Guid.NewGuid().ToString());
pg.AddNewProperty("OutputType", "Library");
pg.AddNewProperty("AppDesignerFolder", "Properties");
pg.AddNewProperty("RootNamespace", parameters["rimbapi-target-ns"][0]);
pg.AddNewProperty("AssemblyName", parameters["rimbapi-target-ns"][0] + ".Phone");
pg.AddNewProperty("ProjectTypeGuids", "{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}");
pg.AddNewProperty("TargetFrameworkVersion", "v4.0");
pg.AddNewProperty("SilverlightVersion", "$(TargetFrameworkVersion)");
pg.AddNewProperty("TargetFrameworkProfile", "WindowsPhone71");
pg.AddNewProperty("TargetFrameworkIdentifier", "Silverlight");
pg.AddNewProperty("SilverlightApplication", "false");
pg.AddNewProperty("ValidateXaml", "true");
pg.AddNewProperty("ThrowErrorsInValidation", "true");
// Release AnyCPU
pg = phoneProj.AddNewPropertyGroup(false);
pg.Condition = "'$(Configuration)|$(Platform)' == 'Release|AnyCPU'";
pg.AddNewProperty("DebugType", "pdbonly");
pg.AddNewProperty("Optimize", "true");
pg.AddNewProperty("OutputPath", "bin\\release");
pg.AddNewProperty("DefineConstants", "TRACE;SILVERLIGHT;WINDOWS_PHONE");
pg.AddNewProperty("ErrorReport", "prompt");
pg.AddNewProperty("NoStdLib", "true");
pg.AddNewProperty("NoConfig", "true");
pg.AddNewProperty("WarningLevel", "4");
pg.AddNewProperty("DocumentationFile", "bin\\release\\" + parameters["rimbapi-target-ns"][0] + ".Phone.xml");
// Add reference structure
refItemGroup = phoneProj.AddNewItemGroup();
refItemGroup.AddNewItem("Reference", "System");
refItemGroup.AddNewItem("Reference", "System.Xml");
BuildItem evReference = refItemGroup.AddNewItem("Reference", @"MARC.Everest.Phone");
evReference.SetMetadata("SpecificVersion", "false");
evReference.SetMetadata("HintPath", "lib\\MARC.Everest.Phone.dll");
// Add WP7 Imports
phoneProj.AddNewImport(@"$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets", null);
phoneProj.AddNewImport(@"$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets", null);
// HACK: Add tools version
string fileName = Path.Combine(hostContext.Output, ProjectFileName) + ".Phone.csproj";
phoneProj.Save(fileName);
XmlDocument doc = new XmlDocument();
doc.Load(fileName);
doc.DocumentElement.Attributes.Append(doc.CreateAttribute("ToolsVersion"));
doc.DocumentElement.Attributes["ToolsVersion"].Value = "4.0";
doc.Save(fileName);
if (parameters.ContainsKey("rimbapi-compile") && Convert.ToBoolean(parameters["rimbapi-compile"][0]))
{
System.Diagnostics.Trace.Write(String.Format("Compiling phone project..."), "information");
// Compile
if (phoneEngine.BuildProjectFile(fileName))
System.Diagnostics.Trace.WriteLine("Success!", "information");
else
{
System.Diagnostics.Trace.WriteLine("Fail", "information");
throw new InvalidOperationException("Failed compilation, operation cannot continue");
}
}
}
#endregion
#region Generate Formatter Assemblies
// Generate the formatter assemblies
if (genFormatters.Count > 0 && parameters.ContainsKey("rimbapi-compile") && Convert.ToBoolean(parameters["rimbapi-compile"][0]))
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Trace.WriteLine("Generating ITS Formatter Types:", "information");
// Load the assembly
Assembly genAsm = Assembly.LoadFile(Path.Combine(Path.Combine(Path.Combine(hostContext.Output, "bin"), "release"), ProjectFileName + ".dll"));
foreach (string s in genFormatters)
GenerateFormatterAssembly(s, genAsm, InteractionRenderer.profileId ?? "formatter");
// Assembly resolve
AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
else if (genFormatters.Count > 0)
Trace.WriteLine("Can't use --rimbapi-gen-its when --rimbapi-compile is not true, skipping ITS generation", "warn");
#endregion
// Does the user only want asm?
#region dllonly
if (parameters.ContainsKey("rimbapi-dllonly") && parameters.ContainsKey("rimbapi-compile") && Convert.ToBoolean(parameters["rimbapi-dllonly"][0]))
try
{
// Move the assemblies up to root
foreach (string file in Directory.GetFiles(Path.Combine(Path.Combine(hostContext.Output, "bin"), "release")))
{
if (File.Exists(Path.Combine(hostContext.Output, Path.GetFileName(file))))
File.Delete(Path.Combine(hostContext.Output, Path.GetFileName(file)));
File.Move(file, Path.Combine(hostContext.Output, Path.GetFileName(file)));
}
// Clean all in the projects and remove all directories
List<String> directories = new List<string>(new string[] {
Path.Combine(Path.Combine(hostContext.Output, "bin"), "release"),
Path.Combine(hostContext.Output, "bin"),
Path.Combine(hostContext.Output, "lib"),
Path.Combine(hostContext.Output, "Vocabulary"),
Path.Combine(hostContext.Output, "Interaction"),
Path.Combine(hostContext.Output, "obj")
});
// Gather files and clean
foreach (Microsoft.Build.BuildEngine.BuildItem fi in fileItemGroup)
{
// Add directory on the "to be deleted"
string dirName = Path.GetDirectoryName(Path.Combine(hostContext.Output, fi.Include));
if (!directories.Contains(dirName))
directories.Add(dirName);
Trace.WriteLine(String.Format("Deleting {0}...", fi.Include), "debug");
File.Delete(Path.Combine(hostContext.Output, fi.Include));
}
// Clean dirs
foreach (string s in directories)
Directory.Delete(s, true);
File.Delete(project.FullFileName);
}
catch(Exception)
{
System.Diagnostics.Trace.WriteLine("Could not clean working files!", "warn");
}
#endregion
}