views:

2119

answers:

3

When I do a ReadLinesFromFile on a file in MSBUILD and go to output that file again, I get all the text on one line. All the Carriage returns and LineFeeds are stripped out.

<Project DefaultTargets = "Deploy"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<Import  Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

<ItemGroup>
    <MyTextFile Include="$(ReleaseNotesDir)$(NewBuildNumber).txt"/>
</ItemGroup>

<Target Name="ReadReleaseNotes">
    <ReadLinesFromFile
        File="@(MyTextFile)" >
        <Output
            TaskParameter="Lines"
            ItemName="ReleaseNoteItems"/>
    </ReadLinesFromFile>
</Target>

<Target Name="MailUsers" DependsOnTargets="ReadReleaseNotes" >
 <Mail SmtpServer="$(MailServer)"
  To="$(MyEMail)"
  From="$(MyEMail)"
  Subject="Test Mail Task"
  Body="@(ReleaseNoteItems)" />
</Target>
<Target Name="Deploy">
 <CallTarget Targets="MailUsers" />
</Target>

</Project>

I get the text from the file which normally looks like this

- New Deployment Tool for BLAH

- Random other stuff()""

Coming out like this

- New Deployment Tool for BLAH;- Random other stuff()""

I know that the code for ReadLinesFromFile will pull the data in one line at a time and strip out the carriage returns.

Is there a way to put them back in? So my e-mail looks all nicely formatted?

Thanks

+11  A: 

The problem here is you are using the ReadLinesFromFile task in a manner it wasn't intended.

ReadLinesFromFile Task
Reads a list of items from a text file.

So it's not just reading all the text from a file, it's reading individual items from a file and returning an item group of ITaskItems. Whenever you output a list of items using the @() syntax you will get a separated list, the default of which is a semicolon. This example illustrates this behavior:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build"    xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

    <ItemGroup>
     <Color Include="Red" />
     <Color Include="Blue" />
     <Color Include="Green" />
</ItemGroup>

<Target Name="Build">
     <Message Text="ItemGroup Color: @(Color)" />
</Target>

</Project>

And the output looks like this:

  ItemGroup Color: Red;Blue;Green

So while the best solution to your problem is to write an MSBuild task that reads a file into a property as a string an not a list of items, that's really not what you asked for. You asked if there was a way to put them back, and there is using MSBuild Transforms.

Transforms are used to create one list from another and also have the ability to transform using a custom separator. So the answer is to transform your list read in using ReadItemsFromFile into another list with newlines. Here is an example that does just that:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

    <ItemGroup>
     <File Include="$(MSBuildProjectDirectory)\Test.txt" />
    </ItemGroup>

    <Target Name="Build">
     <ReadLinesFromFile File="@(File)">
      <Output TaskParameter="Lines" ItemName="FileContents" />
     </ReadLinesFromFile>

     <Message Text="FileContents: @(FileContents)" />
     <Message Text="FileContents Transformed: @(FileContents->'%(Identity)', '%0a%0d')" />
    </Target>

</Project>

Test.text looks like:

Red
Green
Blue

And the output looks like this:

[C:\temp]:: msbuild test.proj
Microsoft (R) Build Engine Version 3.5.21022.8
[Microsoft .NET Framework, Version 2.0.50727.1433]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 11/8/2008 8:16:59 AM.
Project "C:\temp\test.proj" on node 0 (default targets).
  FileContents: Red;Green;Blue
  FileContents Transformed: Red
Green
Blue
Done Building Project "C:\temp\test.proj" (default targets).


Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

What's going on here is two things.

@(FileContents->'%(Identity)', '%0a%0d')
  • We are transforming the list from one type to another using the same values (Identity) but a custom separator '%0a%0d'
  • We are using MSBuild Escaping to escape the line feed (%0a) and carriage return (%0d)

Sorry for the long answer. Hope this helps.

Todd
That is exactly what I was looking for thank dude!!I knew I could do it writing a custom task, but I would rather not have a bunch of Custom tasks about the place if I can do it with the syntax at hand.Thanks again!! :-)
evilhomer
+1  A: 

Instead of @(FileContents->'%(Identity)', '%0a%0d') I believe you can do @(FileContents, '%0a%0d')

A: 

Yeah, but it looks like white spaces and other formatting characters are removed as well. So it's not just CR and LF characters that are lost. How would you make sure they stay where they're supposed to?

Roman