msbuildmsbuild-4.0

How do I stop MSBuild from replacing backslashes with forward slashes?


MSBuild normally replaces backslashes in your build file (usually found in paths) with forward slashes, which helps when working on a cross-platform project. But I have one task where I don't want MSBuild to touch my backslashes: there's a custom task in our build that takes a regular expression and a replacement task, and updates a file. (I'm using it to update version numbers in AssemblyInfo.cs files, getting the version number from git describe. There's a TeamCity build feature that would work if only I could control when it runs, but that's a different story -- suffice it to say that doing this in my MSBuild file looks like the best approach for now).

My problem is that MSBuild is "helping" me by replacing backslashes with forward slashes in the attributes I pass to our custom task, wreaking havoc on my regular expression. What I wrote:

<FileUpdate File="$(RootDir)/GlobalAssemblyInfo.cs"
            Regex='AssemblyFileVersion\("[^"]+"\)'
            ReplacementText='AssemblyFileVersion("$(VersionNumber)")' />

And what I got in the build log:

error : Did not manage to replace 'AssemblyFileVersion/("[^"]+"/)' with 
        'AssemblyFileVersion/("1.1.0.92"/)'

Notice how the backslashes in my regex have become forward slashes? Yeah, that's not going to match anything in my AssemblyInfo.cs file.

I've been able to work around this by avoiding the use of backslashes entirely in my regular expression, like so:

<FileUpdate File="$(RootDir)/GlobalAssemblyInfo.cs"
            Regex='AssemblyFileVersion[(]"[^"]+"[)]'
            ReplacementText='AssemblyFileVersion("$(VersionNumber)")' />

But this won't work in every case. Sooner or later I'm going to need a regular expression with \ in it, or some other backslash expression, and then I'll be sunk. Before that happens, I'd really like to figure out how to tell MSBuild "Stop helping me! I said backslash, and I really meant BACKslash, not forward slash, in this ONE attribute. You can "help" me with other attributes all you like, but leave this one alone!" Any ideas?


Solution

  • You can create your own Replace Text Task and have control over wrongly replaced characters by simply changing / to \ or use other more unique marker.

    <UsingTask TaskName="ReplaceFileText" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
        <InputFilename ParameterType="System.String" Required="true" />
        <MatchExpression ParameterType="System.String" Required="true" />
        <ReplacementText ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
        <Reference Include="System.Core" />
        <Using Namespace="System" />
        <Using Namespace="System.IO" />
        <Using Namespace="System.Text.RegularExpressions" />
        <Code Type="Fragment" Language="cs">
            <![CDATA[
                File.WriteAllText(
                    InputFilename,
                    Regex.Replace(File.ReadAllText(InputFilename), MatchExpression.Replace('/', '\\'), ReplacementText)
                );
              ]]>
        </Code>
    </Task>