I am trying to transform a T4 template from command line using TextTransform.exe with the following command line:
"%ProgramFiles(x86)%\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe"
-out .\MyProj\MyT4.cs
-I "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes"
-a !NamespaceHint!MyNameSpace
-dp T4VSHost!Microsoft.Data.Entity.Design.VisualStudio.Directives.FallbackT4VSHostProcessor!"%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Microsoft.Data.Entity.Design.dll"
.\MyProj\MyT4.tt
Results:
The problem is point 4. This may be expected, since the .csproj isn't a part of the above command line, however, I can't find any parameters which can accept it.
What am I doing wrong or what should I be doing instead?
P.S. When I use the button in Visual Studio the process works as excepted (new files are added to project).
Solved using the following method:
Added these parameters to command line:
-a !!ProjPath!.\MyProj\MyProj.csproj -a !!T4Path!.\MyProj\MyT4.tt
Changed the include directory parameter to a local path:
-I ".\Dependencies"
Copied EF.Utility.CS.ttinclude to that path and made the following changes:
3.1. Replaced:
public static EntityFrameworkTemplateFileManager Create(object textTransformation)
{
DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
IDynamicHost host = transformation.Host;
#if !PREPROCESSED_TEMPLATE
if (host.AsIServiceProvider() != null)
{
return new VsEntityFrameworkTemplateFileManager(transformation);
}
#endif
return new EntityFrameworkTemplateFileManager(transformation);
}
with
public static EntityFrameworkTemplateFileManager Create(object textTransformation)
{
DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
IDynamicHost host = transformation.Host;
#if !PREPROCESSED_TEMPLATE
if (host.AsIServiceProvider() != null)
{
return new VsEntityFrameworkTemplateFileManager(transformation);
}
#endif
return new EFTemplateFileManagerPlus(transformation);
}
(Last return has the change)
Add added this class to the file:
private sealed class EFTemplateFileManagerPlus : EntityFrameworkTemplateFileManager
{
private Action<IEnumerable<string>> projectSyncAction;
private readonly string _projPath;
private readonly string _t4Name;
public EFTemplateFileManagerPlus(object textTemplating)
: base(textTemplating)
{
var projPath = _textTransformation.Host.ResolveParameterValue("", "", "ProjPath");
var t4Path = _textTransformation.Host.ResolveParameterValue("", "", "T4Path");
_projPath = System.IO.Path.GetFullPath(projPath);
_t4Name = System.IO.Path.GetFileName(t4Path);
projectSyncAction = files => SyncCsProjFile(_projPath, _t4Name, files);
}
public static void SyncCsProjFile(string csProjFilePath, string t4FileName, IEnumerable<string> files)
{
files = files.Select(f => System.IO.Path.GetFileName(f)).Distinct().ToList();
var csProjDocument = new XmlDocument();
csProjDocument.Load(csProjFilePath);
var root = csProjDocument.DocumentElement;
XmlElement itemGroup = root.ChildNodes.OfType<XmlElement>()
.Where(n => n.Name == "ItemGroup")
.SelectMany(n => n.ChildNodes.OfType<XmlNode>()
.Where(c => c.Name == "Compile")
)
.Select(c => c.ParentNode)
.FirstOrDefault() as XmlElement;
if (itemGroup == null)
{
itemGroup = csProjDocument.CreateNode(XmlNodeType.Element, "ItemGroup", null) as XmlElement;
root.AppendChild(itemGroup);
}
var codeFiles = itemGroup.ChildNodes.OfType<XmlElement>()
.Where(c =>
c.Name == "Compile"
&& c.HasAttribute("Include") && !String.IsNullOrEmpty(c.GetAttribute("Include")))
.ToList();
var dependantFiles = codeFiles
.Where(f =>
f.ChildNodes.OfType<XmlElement>().Any(c =>
c.Name == "DependentUpon"
&& c.InnerText == t4FileName)
).ToList();
// Remove redundant files
foreach (var node in dependantFiles)
{
if (!files.Contains(node.GetAttribute("Include")))
itemGroup.RemoveChild(node);
}
// Add missing files
foreach (var name in files)
{
if (!dependantFiles.Any(node => node.GetAttribute("Include") == name))
{
var node = csProjDocument.CreateNode(XmlNodeType.Element, "Compile", null) as XmlElement;
node.SetAttribute("Include", name);
itemGroup.AppendChild(node);
var node2 = csProjDocument.CreateNode(XmlNodeType.Element, "DependentUpon", null) as XmlElement;
node2.InnerText = t4FileName;
node.AppendChild(node2);
}
}
SaveClean(csProjDocument, csProjFilePath);
}
static private void SaveClean(XmlDocument doc, string path)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = " ";
settings.NewLineChars = "\r\n";
settings.NewLineHandling = NewLineHandling.Replace;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
using (XmlWriter writer = XmlWriter.Create(sb, settings))
{
doc.Save(writer);
}
var newXml = sb.ToString().Replace("encoding=\"utf-16\"", "encoding=\"utf-8\"").Replace(" xmlns=\"\"", string.Empty);
System.IO.File.WriteAllText(path, newXml, Encoding.UTF8);
}
public override IEnumerable<string> Process(bool split)
{
var generatedFileNames = base.Process(split);
projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
return generatedFileNames;
}
}
Now the project file sync works using TextTransform.exe too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With