Post-processing the compiled web project

Custom msbuild task performs heavy lifting over csproj xml
Project references are changed to file references, additional content files are added, and code files are copied over

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-02-08 01:09:38 -08:00
parent 6267c938de
commit 17d063fa21
12 changed files with 921 additions and 3 deletions

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{5E5E7A21-C7B2-44D8-8593-2F9541AE041D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MSBuild.Orchard.Tasks</RootNamespace>
<AssemblyName>MSBuild.Orchard.Tasks</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.Build.Utilities.v3.5">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="StageProjectAlteration.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MSBuild.Orchard.Tasks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft IT")]
[assembly: AssemblyProduct("MSBuild.Orchard.Tasks")]
[assembly: AssemblyCopyright("Copyright © Microsoft IT 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e0a78419-51a9-4612-932c-4b0143bfff5d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,164 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace MSBuild.Orchard.Tasks {
public class StageProjectAlteration : Task {
public string ProjectFileName { get; set; }
public ITaskItem[] AddContentFiles { get; set; }
[Output]
public ITaskItem[] ExtraFiles { get; set; }
public override bool Execute() {
Log.LogMessage("Altering \"{0}\"", ProjectFileName);
var context = new Context(this);
if (context.LoadProject() &&
context.ChangeProjectReferencesToFileReferences() &&
context.FindExtraFiles() &&
context.AddContentFiles() &&
context.SaveProject()) {
Log.LogMessage("Stage project altered successfully");
return true;
}
Log.LogWarning("Stage project alteration failed");
return false;
}
class Context {
private readonly StageProjectAlteration _task;
XDocument _document;
private const string Xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";
private static readonly XName Project = XName.Get("Project", Xmlns);
private static readonly XName ItemGroup = XName.Get("ItemGroup", Xmlns);
private static readonly XName ProjectReference = XName.Get("ProjectReference", Xmlns);
private static readonly XName Reference = XName.Get("Reference", Xmlns);
private static readonly XName Name = XName.Get("Name", Xmlns);
private static readonly XName Include = XName.Get("Include");
private static readonly XName HintPath = XName.Get("HintPath", Xmlns);
private static readonly XName SpecificVersion = XName.Get("SpecificVersion", Xmlns);
private static readonly XName Content = XName.Get("Content", Xmlns);
private static readonly XName Compile = XName.Get("Compile", Xmlns);
private static readonly XName None = XName.Get("None", Xmlns);
public Context(StageProjectAlteration task) {
_task = task;
}
public bool LoadProject() {
try {
_document = XDocument.Load(_task.ProjectFileName);
return true;
}
catch (Exception) {
_task.Log.LogError("Unable to load project file");
return false;
}
}
public bool SaveProject() {
_document.Save(_task.ProjectFileName);
return true;
}
public bool ChangeProjectReferencesToFileReferences() {
var projectReferences = _document
.Elements(Project)
.Elements(ItemGroup)
.Elements(ProjectReference);
var referenceItemGroup = _document
.Elements(Project)
.Elements(ItemGroup)
.FirstOrDefault(elt => elt.Elements(Reference).Any());
if (referenceItemGroup == null) {
referenceItemGroup = new XElement(ItemGroup);
_document.Root.Add(referenceItemGroup);
}
foreach (var projectReferenceName in projectReferences.Elements(Name)) {
var reference = new XElement(
Reference,
new XAttribute(Include, (string)projectReferenceName),
new XElement(SpecificVersion, "False"),
new XElement(HintPath, string.Format("bin\\{0}.dll", (string)projectReferenceName)));
referenceItemGroup.Add(reference);
}
foreach (var projectReference in projectReferences.ToArray()) {
projectReference.Remove();
}
return true;
}
public bool FindExtraFiles() {
var extraFiles = _document
.Elements(Project)
.Elements(ItemGroup)
.Elements().Where(elt => elt.Name == Compile || elt.Name == None)
.Attributes(Include)
.Select(attr => (string)attr);
_task.ExtraFiles = extraFiles
.Select(file => {
_task.Log.LogMessage("Detected extra file \"{0}\"", file);
var item = new TaskItem(file);
item.SetMetadata("RecursiveDir", Path.GetDirectoryName(file));
return item;
})
.ToArray();
return true;
}
public bool AddContentFiles() {
var existingContent = _document
.Elements(Project)
.Elements(ItemGroup)
.Elements(Content)
.Attributes(Include)
.Select(attr => (string)attr);
var contentItemGroup = _document
.Elements(Project)
.Elements(ItemGroup)
.FirstOrDefault(elt => elt.Elements(Content).Any());
if (contentItemGroup == null) {
contentItemGroup = new XElement(ItemGroup);
_document.Root.Add(contentItemGroup);
}
if (_task.AddContentFiles != null) {
foreach (var addContent in _task.AddContentFiles) {
if (existingContent.Contains(addContent.ItemSpec)) {
// don't add more than once
continue;
}
_task.Log.LogMessage("Adding Content file \"{0}\"", addContent.ItemSpec);
var content = new XElement(
Content,
new XAttribute(Include, addContent.ItemSpec));
contentItemGroup.Add(content);
}
}
return true;
}
}
}
}