msbuild

MSbuild : read files with line feeds


Using MSBuild, how to read a text file with carriage return/line feed and get each line content in a property? The file goes like

Prod;2.13
Pre-Prod;2.14
Test;2.15

And I would like to get

<PropertyGroup>
    <_ProdVersion>2.13</_ProdVersion>
    <_PreProdVersion>2.14</_PreProdVersion>
    <_TestVersion>2.15</_TestVersion>
</PropertyGroup>

So far, i got this but it don't get where i can implement that line-feed splitting step and MSBuild Online Documentation is pretty light:

<ReadLinesFromFile Condition="'$(Configuration)' == 'Debug'" File="$(MSBuildThisFileDirectory)/Resources/Others/MyFiles.txt">
    <Output TaskParameter="Lines" ItemName="MyItem" />
</ReadLinesFromFile>
<ItemGroup>
    <Lines Include="@(MyItem)">
        <Line_test>$([System.String]::Copy('%(MyItem.Identity)'))</Line_test>
    </Lines>
</ItemGroup>
<PropertyGroup>
    <_test>%(Lines.Line_test)</_test>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">           
    <_TestLine1>$(_test.Split(';')[0])</_TestLine1>
    <_TestLine2>$(_test.Split(';')[1])</_TestLine2>         
</PropertyGroup>

Solution

  • Here's an easy solution using response files. It's easy, it's fairly standard and it's builtin so no manual processing required. It does require exact names (so not _Prod but _ProdVersion), but to be honest it seems a better choice to have the same name in your configuration file.

    test.proj:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="12.0" DefaultTargets="ShowVersions">
      <Target Name="ShowVersions">
        <Message Text="_ProdVersion = $(_ProdVersion)"/>
        <Message Text="_PreProdVersion = $(_PreProdVersion)"/>
        <Message Text="_TestVersion = $(_TestVersion)"/>
      </Target>
    </Project>
    

    test.rsp:

    /p:_ProdVersion=2.13
    /p:_PreProdVersion=2.14
    /p:_TestVersion=2.15
    

    Called like msbuild test.proj @test.rsp, output:

    FromResponseFile:
      _ProdVersion = 2.13
      _PreProdVersion = 2.14
      _TestVersion = 2.15
    

    Or if you want the file to be used as you show, you could still transform it into a .rsp file using basic regex replacement. Well, and getting rid of the '-'. Powershell:

    ((Get-Content in.txt) -replace '(.+);(.+)', '/p:_$1Version=$2').Replace('-', '') | Out-File test.rsp
    

    Now for the msbuild-only approach as you tried, add to test.proj:

    <Target Name="ParseVersions">
      <ReadLinesFromFile File="$(MSBuildThisFileDirectory)/in.txt">
        <Output TaskParameter="Lines" ItemName="Versions"/>
      </ReadLinesFromFile>
      <!--Value is part after the ';', name is the part before it,
          but surrounded '_<name>Version' and without dashes in the name-->
      <CreateProperty Value="$([System.String]::Copy('%(Versions.Identity)').Split(';')[1])">
        <Output TaskParameter="Value" PropertyName="_$([System.String]::Copy('%(Versions.Identity)').Split(';')[0].Replace('-', ''))Version"/>
      </CreateProperty>
    </Target>
    

    And call msbuild test.proj /t:ParseVersions;ShowVersions. As you can see this isn't quite as readable as the other options. It could be split by first creating an item group, but that still would need the string manipulation logic.