Background: StyleCop is complaining that an auto-generated file has poor formatting, leading to many warnings when I try to build my project. The auto-generated file is in the obj/ directory of my project, and I want to create an MSBuild task that prepends // <auto-generated/> to this file before compilation (but after it is generated) so that StyleCop doesn't complain.
Problem: I have the following MSBuild code
<!-- StyleCop complains about a file that's auto-generated by the designer, so we need to prepend 'auto-generated' to it beforehand. --> <Target Name="BeforeCompile" DependsOnTargets="MarkGeneratedFiles" /> <Target Name="MarkGeneratedFiles"> <PropertyGroup> <GeneratedFilePath>$(MSBuildThisFileDirectory)obj\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).Program.cs</GeneratedFilePath> </PropertyGroup> <InsertIntoFile FilePath="$(GeneratedFilePath)" LineNumber="1" Text="// <auto-generated/>" /> </Target> <!-- Code taken from http://stackoverflow.com/a/21500030/4077294 --> <UsingTask TaskName="InsertIntoFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <FilePath ParameterType="System.String" Required="true" /> <LineNumber ParameterType="System.Int32" Required="true" /> <Text ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Using Namespace="System" /> <Using Namespace="System.IO" /> <Code Type="Fragment" Language="cs"> <![CDATA[ // By tradition, text file line numbering is 1-based var lines = File.Exists(FilePath) ? File.ReadAllLines(FilePath).ToList() : new List<String>(1); lines.Insert(Math.Min(LineNumber - 1, lines.Count), Text); File.WriteAllLines(FilePath, lines); return true; ]]> </Code> </Task> </UsingTask> The file that I want to modify has the filename obj/Debug/netcoreapp1.0/BasicCompiler.Tests.Program.cs. In the above snippet, I have a BeforeCompile target that depends on MarkGeneratedFiles, which goes ahead and tries to insert // <auto-generated/> before the first line of that file.
I have tested, and this seems to work fine if the generated file is already present. However, if I remove the obj/ directory or I build from another machine, I get this error:
"C:\cygwin64\home\james\Code\cs\BasicCompiler\src\BasicCompiler.Tests\BasicCompiler.Tests.csproj" (default target) (1) -> (MarkGeneratedFiles target) -> C:\cygwin64\home\james\Code\cs\BasicCompiler\src\BasicCompiler.Tests\BasicCompiler.Tests.csproj(68,5): error MSB4018: The "InsertIntoFile" task failed unexpectedly.\r C:\cygwin64\home\james\Code\cs\BasicCompiler\src\BasicCompiler.Tests\BasicCompiler.Tests.csproj(68,5): error MSB4018: System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\cygwin64\home\james\Code\cs\BasicCompiler\src\BasicCompiler.Tests\obj\Debug\netcoreapp1.0\BasicCompiler.Tests.Program.cs'.\r Basically it seems like the target is getting run before the file is getting generated, so there's nothing to prepend the text to. Is there a way to run it after this file gets generated, but before compilation?
Additional notes: So far, I have looked through all of the special target names here and tried using both BeforeBuild and BeforeCompile.
Also, since I am using the "new" StyleCop, I cannot put <ExcludeFromStyleCop> in my project file. See https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1145
AfterTargets="<TargetGeneratingFile>"to your MarkGeneratedFiles target (no need for BeforeCompile etc anymore0GenerateProgramFile) and putAfterTargets="GenerateProgramFile"in my target. Everything works as expected now.