从命令行转换T4不会将生成的文件添加到csproj

时间:2013-09-23 19:17:23

标签: visual-studio-2010 visual-studio code-generation build-automation t4

我正在尝试使用以下命令行使用TextTransform.exe从命令行转换T4模板:

"%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

结果:

  1. 没有错误消息
  2. %ERRORLEVEL%在完成时为0。
  3. 生成文件
  4. .csproj不会更改
  5. 问题是第4点。这可能是预期的,因为.csproj不是上述命令行的一部分,但是,我找不到任何可以接受它的参数。

    我做错了什么或者我该做什么呢?

    P.S。当我在Visual Studio中使用该按钮时,该过程将作为例外工作(将新文件添加到项目中)。

2 个答案:

答案 0 :(得分:2)

使用以下方法解决:

  1. 将这些参数添加到命令行:

    -a !!ProjPath!.\MyProj\MyProj.csproj -a !!T4Path!.\MyProj\MyT4.tt

  2. 将include目录参数更改为本地路径:

    -I ".\Dependencies"

  3. EF.Utility.CS.ttinclude复制到该路径并进行了以下更改:

  4. 3.1。取代:

        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);
        }
    

        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);
        }
    

    (上次回报有变化)

    将此类添加到文件中:

    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;
            }
        }
    

    现在,项目文件同步也可以使用TextTransform.exe

答案 1 :(得分:0)

我相信命令行主机无法更改.csproj。只有VS主机才能通过访问DTE对象来实现。