- fixed a minor bug in ANX content project loader

- added support to translate XNA content project files to ANX content project format and vice versa (still some work needed)
This commit is contained in:
Glatzemann 2012-10-27 06:47:35 +00:00 committed by Konstantin Koch
parent 87dd600ffe
commit 9817ecf2e5
7 changed files with 450 additions and 58 deletions

View File

@ -112,6 +112,8 @@ namespace ANX.Framework.Content.Pipeline.Tasks
/// <param name="path">The path to save the project</param>
public void Save(string path)
{
//TODO: check file extension and throw exception when wrong (or silently change it?)
if (!Directory.Exists(Path.GetDirectoryName(path)))
Directory.CreateDirectory(Path.GetDirectoryName(path));
XmlWriter writer = XmlTextWriter.Create(path, new XmlWriterSettings() {Encoding = Encoding.UTF8, Indent = true, NewLineHandling = NewLineHandling.Entitize} );
@ -183,7 +185,7 @@ namespace ANX.Framework.Content.Pipeline.Tasks
// <Parameter Name="DoThis">True</Parameter>
// <ProcessorParams>
// </BuildItem>
//</BuildItems
//</BuildItems>
writer.WriteStartElement("BuildItems");
foreach (var buildItem in BuildItems)
{
@ -360,7 +362,7 @@ namespace ANX.Framework.Content.Pipeline.Tasks
lastBuildItem.SourceFilename = reader.ReadElementContentAsString();
}
break;
case "ProcessorParameter":
case "Parameter":
if (versionMajor == 1 && versionMinor >= 0)
{
string key;

View File

@ -30,6 +30,30 @@ namespace ProjectConverter
/// </summary>
public abstract string Name { get; }
/// <summary>
/// When set to false the source project file will not be written to disk after conversion
/// </summary>
public virtual bool WriteSourceProjectToDestination
{
get { return true; }
}
/// <summary>
/// Nex extension to use for the target file
/// </summary>
public virtual string TargetFileExtension
{
get { return string.Empty; }
}
public virtual string ProjectFileTemplate
{
get
{
return string.Empty;
}
}
#region ConvertAllProjects
public void ConvertAllProjects(string solutionFilepath, string destinationPath)
{
@ -44,10 +68,19 @@ namespace ProjectConverter
}
#endregion
#region ConvertProject
#region ConvertAnxContentProject
public void ConvertAnxContentProject(string projectFilePath, string destinationPath)
{
ProjectPath projectPath = new ProjectPath(this, projectFilePath, ".", destinationPath, TargetFileExtension, ProjectFileTemplate);
ConvertProject(projectPath);
}
#endregion
#region ConvertProject
public void ConvertProject(string projectFilePath, string destinationPath)
{
ProjectPath projectPath = new ProjectPath(this, projectFilePath, ".", destinationPath);
ProjectPath projectPath = new ProjectPath(this, projectFilePath, ".", destinationPath, TargetFileExtension);
ConvertProject(projectPath);
}
@ -55,6 +88,8 @@ namespace ProjectConverter
{
CurrentProject = project;
PreConvert();
string namespaceName = project.Root.Name.NamespaceName;
XName importName = XName.Get("Import", namespaceName);
XName rootNamespaceName = XName.Get("RootNamespace", namespaceName);
@ -67,7 +102,10 @@ namespace ProjectConverter
XName outputPathName = XName.Get("OutputPath", namespaceName);
var groups = project.Root.Elements().ToList();
foreach (var group in groups)
ConvertProject(project.Root);
foreach (var group in groups)
{
if (group.Name == propertyGroupName)
{
@ -93,31 +131,32 @@ namespace ProjectConverter
ConvertPropertyGroup(group);
}
}
else if (group.Name == importName)
{
XAttribute projectAttribute = group.Attribute("Project");
ConvertImport(group, projectAttribute);
}
else if (group.Name == itemGroupName)
{
var allReferences = group.Elements(referenceName).ToList();
foreach (var reference in allReferences)
ConvertReference(reference);
else if (group.Name == importName)
{
XAttribute projectAttribute = group.Attribute("Project");
ConvertImport(group, projectAttribute);
}
else if (group.Name == itemGroupName)
{
var allReferences = group.Elements(referenceName).ToList();
foreach (var reference in allReferences)
ConvertReference(reference);
var allProjectReferences = group.Elements(projectReferenceName).ToList();
foreach (var projectReference in allProjectReferences)
{
FixProjectReferencePath(projectReference);
ConvertProjectReference(projectReference);
}
var allProjectReferences = group.Elements(projectReferenceName).ToList();
foreach (var projectReference in allProjectReferences)
{
FixProjectReferencePath(projectReference);
ConvertProjectReference(projectReference);
}
ConvertItemGroup(group);
}
ConvertItemGroup(group);
}
}
PostConvert();
project.Save();
if (WriteSourceProjectToDestination)
project.Save();
}
#endregion
@ -151,8 +190,14 @@ namespace ProjectConverter
}
#endregion
#region ConvertImport
protected virtual void ConvertImport(XElement element, XAttribute projectAttribute)
#region ConvertProject
protected virtual void ConvertProject(XElement element)
{
}
#endregion
#region ConvertImport
protected virtual void ConvertImport(XElement element, XAttribute projectAttribute)
{
}
#endregion
@ -164,14 +209,20 @@ namespace ProjectConverter
}
#endregion
#region PreConvert
protected virtual void PreConvert()
{
}
#endregion
#region PostConvert
protected virtual void PostConvert()
{
}
#endregion
#region DeleteNodeIfExists
protected void DeleteNodeIfExists(XElement group, string nodeName)
#region DeleteNodeIfExists
protected void DeleteNodeIfExists(XElement group, string nodeName)
{
XName name = XName.Get(nodeName, group.Name.NamespaceName);
XElement element = group.Element(name);
@ -246,7 +297,7 @@ namespace ProjectConverter
foreach (var project in solution.Projects)
if (project.IsCsProject && project.RelativePath.Contains("Tools") == false)
result.Add(new ProjectPath(this, project.RelativePath, basePath, destinationPath));
result.Add(new ProjectPath(this, project.RelativePath, basePath, destinationPath, string.Empty));
return result.ToArray();
}

View File

@ -0,0 +1,144 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ANX.Framework.Content.Pipeline.Tasks;
using System.Xml.Linq;
#endregion
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ProjectConverter.Platforms
{
public class AnxContentProjectConverter : Converter
{
private ContentProject sourceContentProject = null;
public override string Name
{
get { return "content2xna"; }
}
public override string Postfix
{
get { return string.Empty; }
}
public override string TargetFileExtension
{
get
{
return ".contentproj";
}
}
public override bool WriteSourceProjectToDestination
{
get { return true; }
}
protected override void PreConvert()
{
this.sourceContentProject = ContentProject.Load(CurrentProject.FullSourcePath);
}
protected override void ConvertMainPropertyGroup(XElement element)
{
var rootNameSpaceNode = GetOrCreateNode(element, "RootNamespace");
rootNameSpaceNode.Value = sourceContentProject.ContentRoot;
}
protected override void ConvertProject(XElement element)
{
var itemGroupName = GetXName("ItemGroup");
var includeName = XName.Get("Include");
var referenceName = GetXName("Reference");
//
// add build items
//
foreach (var buildItem in sourceContentProject.BuildItems)
{
XElement buildItemElement = new XElement(itemGroupName);
var compileElement = GetOrCreateNode(buildItemElement, "Compile");
compileElement.SetAttributeValue(includeName, buildItem.SourceFilename);
var nameElement = GetOrCreateNode(compileElement, "Name");
nameElement.Value = buildItem.AssetName;
var importerElement = GetOrCreateNode(compileElement, "Importer");
importerElement.Value = buildItem.ImporterName;
var processorElement = GetOrCreateNode(compileElement, "Processor");
processorElement.Value = buildItem.ProcessorName;
foreach (var processorParameter in buildItem.ProcessorParameters)
{
var parameterElement = GetOrCreateNode(compileElement, "ProcessorParamters_" + processorParameter.Key);
parameterElement.Value = processorParameter.Value.ToString();
}
element.Add(buildItemElement);
}
//
// add references
//
XElement referenceItemGroup = new XElement(itemGroupName);
foreach (var reference in sourceContentProject.References)
{
var referenceElement = new XElement(referenceName);
referenceElement.SetAttributeValue(includeName, reference);
referenceItemGroup.Add(referenceElement);
}
element.Add(referenceItemGroup);
}
protected override void PostConvert()
{
}
public override string ProjectFileTemplate
{
get
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
<PropertyGroup>
<ProjectGuid>{FA6E229D-4504-47B1-8A23-2D3FCC13F778}</ProjectGuid>
<ProjectTypeGuids>{96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>
<Platform Condition="" '$(Platform)' == '' "">x86</Platform>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
</PropertyGroup>
<PropertyGroup>
<RootNamespace />
</PropertyGroup>
<Import Project=""$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.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,150 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ANX.Framework.Content.Pipeline.Tasks;
using System.IO;
using System.Xml.Linq;
using System.Reflection;
#endregion
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ProjectConverter.Platforms
{
public class XnaContentProjectConverter : Converter
{
#region Private Members
private ContentProject targetContentProject = null;
string targetProjectFile;
#endregion
public override string Name
{
get { return "content2anx"; }
}
public override string Postfix
{
get { return string.Empty; }
}
public override bool WriteSourceProjectToDestination
{
get { return false; }
}
protected override void PreConvert()
{
this.targetContentProject = new ContentProject(CurrentProject.ProjectName);
this.targetContentProject.Creator = String.Format("ANX {0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version);
this.targetProjectFile = Path.Combine(Path.GetDirectoryName(CurrentProject.FullDestinationPath),
Path.GetFileNameWithoutExtension(CurrentProject.FullDestinationPath) + ".cproj");
}
protected override void PostConvert()
{
targetContentProject.Save(this.targetProjectFile);
}
protected override void ConvertMainPropertyGroup(XElement element)
{
ConvertPropertyGroup(element);
}
protected override void ConvertPropertyGroup(XElement element)
{
targetContentProject.ContentRoot = GetSubNodeValue(element, "RootNamespace");
}
protected override void ConvertItemGroup(System.Xml.Linq.XElement element)
{
var groups = element.Elements().ToList();
foreach (var group in groups)
{
var attributes = group.Attributes().ToList();
if (group.Name.LocalName.Equals("reference", StringComparison.InvariantCultureIgnoreCase))
{
string include = GetAttributeValue(attributes, "include");
targetContentProject.References.Add(include);
}
else if (group.Name.LocalName.Equals("compile", StringComparison.InvariantCultureIgnoreCase))
{
string include = GetAttributeValue(attributes, "include");
string name = GetSubNodeValue(group, "Name");
string importer = GetSubNodeValue(group, "importer");
string processor = GetSubNodeValue(group, "processor");
Dictionary<string, string> parameters = GetSubNodeValues(group, "ProcessorParameters", "_");
BuildItem buildItem = new BuildItem()
{
AssetName = name,
SourceFilename = include,
OutputFilename = name + ".xnb",
ImporterName = importer,
ProcessorName = processor,
};
foreach (KeyValuePair<string, string> parameter in parameters)
{
buildItem.ProcessorParameters.Add(parameter.Key, parameter.Value);
}
targetContentProject.BuildItems.Add(buildItem);
}
}
base.ConvertItemGroup(element);
}
private string GetAttributeValue(IEnumerable<XAttribute> attributes, string name)
{
foreach (XAttribute attribute in attributes)
{
if (attribute.Name.LocalName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
return attribute.Value;
}
}
return string.Empty;
}
private string GetSubNodeValue(XElement node, string subNodeName)
{
var elements = node.Elements().ToList();
foreach (var element in elements)
{
if (element.Name.LocalName.Equals(subNodeName, StringComparison.InvariantCultureIgnoreCase))
{
return element.Value;
}
}
return string.Empty;
}
private Dictionary<string, string> GetSubNodeValues(XElement node, string subNodeNameStartingWith, string splitter)
{
Dictionary<string, string> values = new Dictionary<string, string>();
var elements = node.Elements().ToList();
foreach (var element in elements)
{
if (element.Name.LocalName.StartsWith(subNodeNameStartingWith, StringComparison.InvariantCultureIgnoreCase))
{
string[] parts = element.Name.LocalName.Split(new string[] { splitter }, StringSplitOptions.RemoveEmptyEntries);
values[parts[1]] = element.Value;
}
}
return values;
}
}
}

View File

@ -21,6 +21,8 @@ namespace ProjectConverter
new PsVitaConverter(),
new AnxConverter(),
new XnaConverter(),
new XnaContentProjectConverter(),
new AnxContentProjectConverter(),
};
private static readonly List<string> switches = new List<string>();
@ -39,21 +41,22 @@ namespace ProjectConverter
foreach (string arg in args)
{
if (arg.StartsWith("/") || arg.StartsWith("-"))
string larg = arg.Trim();
if (larg.StartsWith("/") || larg.StartsWith("-"))
{
if (arg.Contains("="))
if (larg.Contains("="))
{
string[] parts = arg.Split('=');
string[] parts = larg.Split('=');
keyValueParameters[parts[0].Trim().ToLowerInvariant()] = parts[1].Trim().ToLowerInvariant();
}
else
{
switches.Add(arg.Substring(1).Trim().ToLowerInvariant());
switches.Add(larg.Substring(1).Trim().ToLowerInvariant());
}
}
else if (File.Exists(arg))
else if (File.Exists(larg))
{
files.Add(arg);
files.Add(larg);
}
}
@ -70,8 +73,12 @@ namespace ProjectConverter
converter.ConvertAllProjects(file, TryGetDestinationPath());
break;
case ".csproj":
case ".contentproj":
converter.ConvertProject(file, TryGetDestinationPath());
break;
case ".cproj":
converter.ConvertAnxContentProject(file, TryGetDestinationPath());
break;
default:
throw new NotImplementedException("unsupported file type '" + fileExt + "'");
}
@ -86,7 +93,7 @@ namespace ProjectConverter
{
if (string.Equals(kvp.Key, "/O", StringComparison.InvariantCultureIgnoreCase))
{
return kvp.Value;
return Path.GetDirectoryName(kvp.Value);
}
}

View File

@ -50,7 +50,9 @@
<Compile Include="DefinesConverter.cs" />
<Compile Include="NamespaceMapper.cs" />
<Compile Include="Platforms\AbstractXna2AnxConverter.cs" />
<Compile Include="Platforms\AnxContentProjectConverter.cs" />
<Compile Include="Platforms\AnxConverter.cs" />
<Compile Include="Platforms\XnaContentProjectConverter.cs" />
<Compile Include="Platforms\XnaConverter.cs" />
<Compile Include="Platforms\LinuxConverter.cs" />
<Compile Include="Platforms\MetroConverter.cs" />
@ -67,6 +69,12 @@
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ANX.Framework.Content.Pipeline\ANX.Framework.Content.Pipeline.csproj">
<Project>{2DAFDFC1-223B-4741-87BB-BE3D0A7617DB}</Project>
<Name>ANX.Framework.Content.Pipeline</Name>
</ProjectReference>
</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.

View File

@ -58,10 +58,29 @@ namespace ProjectConverter
}
}
public ProjectPath(Converter converter, string relativeSourcePath, string basePath, string destinationPath)
public string ProjectName
{
get;
private set;
}
public ProjectPath(Converter converter, string relativeSourcePath, string basePath, string destinationPath, string targetExtension)
{
RelativeSourcePath = relativeSourcePath;
FullSourcePath = Path.Combine(basePath, relativeSourcePath);
SetupPath(converter, relativeSourcePath, basePath, destinationPath, targetExtension);
LoadProjectFile();
}
public ProjectPath(Converter converter, string relativeSourcePath, string basePath, string destinationPath, string targetExtension, string documentText)
{
SetupPath(converter, relativeSourcePath, basePath, destinationPath, targetExtension);
ParseProjectFile(documentText);
}
private void SetupPath(Converter converter, string relativeSourcePath, string basePath, string destinationPath, string targetExtension)
{
RelativeSourcePath = relativeSourcePath;
FullSourcePath = Path.Combine(basePath, relativeSourcePath);
ProjectName = Path.GetFileNameWithoutExtension(FullSourcePath);
if (string.IsNullOrEmpty(destinationPath))
{
@ -77,18 +96,15 @@ namespace ProjectConverter
RelativeDestinationPath = Path.Combine(destinationPath, Path.GetFileName(relativeSourcePath));
}
FullDestinationPath = Path.Combine(basePath, RelativeDestinationPath);
//TODO: never ever ignore all exceptions without proper handling
//try
//{
LoadProjectFile();
//}
//catch
//{
//}
}
if (string.IsNullOrEmpty(targetExtension))
{
FullDestinationPath = Path.Combine(basePath, RelativeDestinationPath);
}
else
{
FullDestinationPath = Path.Combine(Path.GetDirectoryName(Path.Combine(basePath, RelativeDestinationPath)), Path.GetFileNameWithoutExtension(RelativeDestinationPath) + targetExtension);
}
}
#region Save
public void Save()
@ -119,12 +135,26 @@ namespace ProjectConverter
#region LoadProjectFile
private void LoadProjectFile()
{
string documentText = File.ReadAllText(FullSourcePath);
Document = XDocument.Parse(documentText);
}
if (File.Exists(FullSourcePath))
{
string documentText = File.ReadAllText(FullSourcePath);
ParseProjectFile(documentText);
}
else
{
throw new FileNotFoundException("couldn't find project file", FullSourcePath);
}
}
#endregion
public override string ToString()
#region ParseProjectFile
private void ParseProjectFile(String documentText)
{
Document = XDocument.Parse(documentText);
}
#endregion
public override string ToString()
{
return "ProjectPath{" + RelativeSourcePath + "}";
}
@ -139,18 +169,18 @@ namespace ProjectConverter
string testRelativeSourcePath = "ANX.Framework.csproj";
var projPath = new ProjectPath(new PsVitaConverter(),
testRelativeSourcePath, testBasePath, string.Empty);
testRelativeSourcePath, testBasePath, string.Empty, string.Empty);
Assert.AreEqual(projPath.RelativeDestinationPath,
"ANX.Framework_PSVita.csproj");
projPath = new ProjectPath(new LinuxConverter(),
"ANX.Framework_IOS.csproj", testBasePath, string.Empty);
"ANX.Framework_IOS.csproj", testBasePath, string.Empty, string.Empty);
Assert.AreEqual(projPath.RelativeDestinationPath,
"ANX.Framework_Linux.csproj");
projPath = new ProjectPath(new MetroConverter(),
"ANX.Framework_IOS_Android_WindowsXNA.csproj", testBasePath, string.Empty);
"ANX.Framework_IOS_Android_WindowsXNA.csproj", testBasePath, string.Empty, string.Empty);
Assert.AreEqual(projPath.RelativeDestinationPath,
"ANX.Framework_WindowsMetro.csproj");
}