//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.BuildTasks { using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using System.Xml.Linq; using System.IO; using Microsoft.Build.BuildEngine; using System.Diagnostics.Contracts; public class MergeProjectWithVSTemplate : Task { internal const string VSTemplateNamespace = "http://schemas.microsoft.com/developer/vstemplate/2005"; [Required] public string[] ProjectItemTypes { get; set; } [Required] public string[] ReplaceParametersExtensions { get; set; } [Required] public ITaskItem[] Templates { get; set; } /// /// Executes this instance. /// public override bool Execute() { foreach(ITaskItem sourceTemplateTaskItem in this.Templates) { var template = XElement.Load(sourceTemplateTaskItem.ItemSpec); var templateContentElement = template.Element(XName.Get("TemplateContent", VSTemplateNamespace)); var projectElement = templateContentElement.Element(XName.Get("Project", VSTemplateNamespace)); if (projectElement == null) { Log.LogMessage("Skipping merge of \"{0}\" with a project because no project was referenced from the template.", sourceTemplateTaskItem.ItemSpec); continue; } var projectPath = Path.Combine(Path.GetDirectoryName(sourceTemplateTaskItem.ItemSpec), projectElement.Attribute("File").Value); Log.LogMessage("Merging project \"{0}\" with \"{1}\".", projectPath, sourceTemplateTaskItem.ItemSpec); var sourceProject = new Project(); sourceProject.Load(projectPath); // Collect the project items from the project that are appropriate // to include in the .vstemplate file. var itemsByFolder = from item in sourceProject.EvaluatedItems.Cast() where this.ProjectItemTypes.Contains(item.Name) orderby item.Include group item by Path.GetDirectoryName(item.Include); foreach (var folder in itemsByFolder) { XElement parentNode = FindOrCreateParent(folder.Key, projectElement); foreach (var item in folder) { bool replaceParameters = this.ReplaceParametersExtensions.Contains(Path.GetExtension(item.Include)); var itemName = XName.Get("ProjectItem", VSTemplateNamespace); var projectItem = parentNode.Elements(itemName).FirstOrDefault(el => string.Equals(el.Value, Path.GetFileName(item.Include), StringComparison.OrdinalIgnoreCase)); if (projectItem == null) { projectItem = new XElement(itemName, Path.GetFileName(item.Include)); parentNode.Add(projectItem); } if (replaceParameters) { projectItem.SetAttributeValue("ReplaceParameters", "true"); } } } template.Save(sourceTemplateTaskItem.ItemSpec); } return !Log.HasLoggedErrors; } private static XElement FindOrCreateParent(string directoryName, XElement projectElement) { Contract.Requires(projectElement != null); if (string.IsNullOrEmpty(directoryName)) { return projectElement; } string[] segments = directoryName.Split(Path.DirectorySeparatorChar); XElement parent = projectElement; for (int i = 0; i < segments.Length; i++) { var candidateName = XName.Get("Folder", VSTemplateNamespace); var candidate = parent.Elements(XName.Get("Folder", VSTemplateNamespace)).FirstOrDefault(n => n.Attribute("Name").Value == segments[i]); if (candidate == null) { candidate = new XElement( candidateName, new XAttribute("Name", segments[i])); parent.Add(candidate); } parent = candidate; } return parent; } } }