msbuild fileupdate setup project - msbuild

I'm looking to use the fileUpdate task from msbuildtasks.tigris.org to modify image src's as part of our web setup project so that they will point to a static img sub domain (or later a CDN)
I can run a task within a given project with:
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="AfterBuild">
<FileUpdate
Files="basic.css"
Regex="/images/([^\)]*)"
ReplacementText="http://img.domain.com/images/$1" />
</Target>
However, I dont want to overwrite the original css source file, but want to run this as part of our deployment project that produces an msi.
This is done using a web setup project (.vdproj) which also uses a custom actions project which is just a standard .csproj
My questions are:
How can I run this task in the setup project so that I replace content in the files that go into the .msi?
Is there a way to use wildcards for the files - ideally I want to say do this for ALL .css files?

In order to achieve this you need to use an item group to create the list for you
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="AfterBuild">
<ItemGroup>
<CssFiles Include='$(SolutionRoot)\**\*.css' />
</ItemGroup>
<FileUpdate
Files="#(CssFiles)"
Regex="/images/([^\)]*)"
ReplacementText="http://img.domain.com/images/$1" />
</Target>

Related

Apply a web.config transform within a Teamcity Build Step

I am trying to run a MSBuild task on team city that also transforms a web.casper.config file.
I have tried various switches but can;t get this right. Which most likely means there is a different way to achieve my desired result (like publish).
I have tried:-
/t:TransformWebConfig
/p:TransformWebConfig=true
Basically I want to
- BUILD website.csproj into a custom dir
- THEN apply a web.config transform on web.casper.config
Can anyone help?
One thing that seems to work (not sure if its the best way) is to add a before/after build event on the csproj file for the website e.g.
<Target Name="BeforeBuild">
<Copy SourceFiles="Web.config" DestinationFiles="Web.temp.config"
OverwriteReadOnlyFiles="True" />
<TransformXml Source="Web.temp.config" Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
<Target Name="AfterBuild">
<Copy SourceFiles="Web.temp.config" DestinationFiles="Web.config"
OverwriteReadOnlyFiles="True" />
<Delete Files="Web.temp.config" />
</Target>
This basically copies web.config to web.temp.config then uses the casper config to transform.
Source from SO

How to generate files during build using msbuild

Does anyone know how to modify a csproj file in a way to generate code files during build without actually referencing the files?
A process like :
create file,
dynamically reference temporary file during build
compiled assembly has additional members, depending on the files created during build
The purpose of this is to create a way of generating code files using roslyn instead of using t4 templates, which are very awkward to use once you're trying to do something depending on attributes.
Hence i am planning on providing a way to use a special csharp file (for full syntax support) to generate files programatically based on the contents of that special file.
I've spent a couple of weeks looking into resources on the internet (with the topic msbuild), but until now it seems i didn't use the right keywords.
This one has been the most insightful one to me yet:
https://www.simple-talk.com/dotnet/.net-tools/extending-msbuild/
My guess is, that the correct build target for my purpose should be "BeforeCompile" in order to somehow populate the build process with custom code files.
Does anyone have experience with my issue, or is aware of any particular resources which deal with the task?
Solution i got it working with:
<UsingTask TaskName="DynamicCodeGenerator.DynamicFileGeneratorTask" AssemblyFile="..\DynamicCodeGenerator\bin\Debug\DynamicCodeGenerator.dll" />
<Target Name="DynamicCodeGeneratorTarget" BeforeTargets="BeforeBuild;BeforeRebuild">
<DynamicFileGeneratorTask>
<Output ItemName="Generated" TaskParameter="GeneratedFilePaths" />
</DynamicFileGeneratorTask>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" />
<!-- For clean to work properly -->
</ItemGroup>
</Target>
Unfortunately i did not get it to work with a propertygroup override as suggested
Update: This link is interesting too: https://github.com/firstfloorsoftware/xcc/blob/master/FirstFloor.Xcc/Targets/Xcc.targets
Generating the code file can be achieved by msbuild task or msbuild inline task. It is up to you to generate the proper code. One thing that you must care of is creating output item parameter in order to append it to the #(Compile) item. You can use $(IntDir) location to locate your newly generated file, and add them to the #(FileWrites) item group in order for Clean target work properly.
When you finish writing your task, you must use it in your project like this:
<UsingTask TaskName="TaskTypeFullName" AssemblyFile="YourAssembly.dll"/>
<PropertyGroup>
<!-- Here you need to experiment with [Build/Compile/SomeOther]DependsOn property -->
<BuildDependsOn>
MyCodeGenerator;
$(BuildDependsOn)
</BuildDependsOn>
</PropertyGroup>
<Target Name="MyCodeGenerator">
<YourTaskName>
<Output ItemName="Generated" TaskParameter="GeneratedFiles" />
</YourTaskName>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" /> <!-- For clean to work properly -->
</ItemGroup>
</Target>
I wanted to use a bash script to generate code for a project using dotnet core on Linux. Here is what worked for me. And thanks #stukselbax, I built this off of your answer.
<Target Name="GenerateProtocolBuffers" BeforeTargets="BeforeBuild;BeforeRebuild">
<Exec Command="./generatecode.sh" Outputs="proto/*.cs">
<Output ItemName="Generated" TaskParameter="Outputs" />
</Exec>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" />
</ItemGroup>
</Target>
Note that the script I'm using to generate the code is called generatecode.sh. Replace this with your own.

StyleCop MS Build magic? Who is calling the StyleCop target?

In our project files we are using StyleCop and are running it during the build process. We've modified our project files to include the StyleCop targets like so:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
<Import Project="..\..\Tools\Microsoft\StyleCop\v4.3\Microsoft.StyleCop.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
The question is why does this work? Who is calling the StyleCop target defined in the Microsoft.StyleCop.targets file?
As far as I can tell, the only target being run when you start the build, is the "Build" target. I can't find any references to the "StyleCop" target anywhere outside the Microsoft.StyleCop.targets file. So again, why is it being called?
The reason I want to know is because it would be cool if we could do something similar for our own custom tasks. So instead of editing all of our 78 csproj files, we could just import our own general target like:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
<Import Project="Common.targets" />
And then just import StyleCop in that file instead, along with all our other tasks that need to be done on a per project basis.
Please help me understand.
Eureka!
The secret sauce is the following lines in the StyleCop targets file:
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);StyleCop</BuildDependsOn>
<RebuildDependsOn>StyleCopForceFullAnalysis;$(RebuildDependsOn)</RebuildDependsOn>
</PropertyGroup>
The "Build" target in Microsoft.Common.targets is declared like so:
<Target Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="$(BuildDependsOn)"
Outputs="$(TargetPath)" />
This means that any target listed in the "BuildDependsOn" property will get called during the build. Isn't that nice? :)

MSBuild and _PublishedWebsites

After MSbuild has built my solution (with an asp.net website), and the webdeployment project has built and put the website in the directory _PublishedWebsites:
c:\mybuilds\buildName\Daily_20090519.3\Release_PublishedWebsites\MyWebsite.
How do I copy this to the fixed directory where IIS points to for the test website?
I have found loads of code snippets, but I cannot seem to find one that will take into account the fact that this directory name changes.
This is pretty easy. You can edit the project and insert something similar to the following.
<PropertyGroup>
<OutputDest>$(MSBuildProjectDirectory)\..\OutputCopy\</OutputDest>
</PropertyGroup>
<Target Name="AfterBuild">
<!-- Create an item with all the output files -->
<ItemGroup>
<_OutputFiles Include="$(OutputPath)**\*" Exclude="$(OutputPath)obj\**\*" />
</ItemGroup>
<!-- You probably don't want to include the files in the obj folder so exclude them. -->
<Message Text="OutputDest : $(OutputDest)" />
<Copy SourceFiles="#(_OutputFiles)"
DestinationFiles="#(_OutputFiles->'$(OutputDest)%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
Is this what you are looking for?
My Book: Inside the Microsoft Build Engine : Using MSBuild and Team Foundation Build
I'm using different technique.
<PropertyGroup>
<BinariesRoot>c:\BinariesForIis\</BinariesRoot>
</PropertyGroup>
The c:\BinariesForIis\ will be used for direct output compiled binaries (before copy to ...\Daily_20090519.3\Release_ ...).

MSBuild ITaskItem array is out of date

I'm creating a custom ITask for MSBuild which uploads the output files of my build. I'm using a web deployment project to publish my app and hooking in to the AfterBuild target to do my custom work.
If I add a file to my web application, the first time I do a build, my custom task is not recognizing the recently added file. In order for that file to show up in my array of ITaskItems, I have to first do a build with my 'AfterBuild' target removed and then start the build again with my 'AfterBuild' target in place.
Here is what my build file looks like:
<ItemGroup>
<PublishContent Include="$(OutputPath)\**" />
</ItemGroup>
<Target Name="AfterBuild">
<UploadTask FilesToPublish="#(PublishContent)" />
</Target>
The list in #(PublishContent) seems to be initialized at the beginning of the build instead of reflecting any changes that might have taken place by the build process itself.
Any ideas?
Thanks
Your ItemGroup is going to get evaluated when the project file first loads (when you first open Visual Studio or you 'unload' and 'reload' the project in Solution Explorer).
What you probably need is to create an ItemGroup as a task in your 'AfterBuild' target. Example:
<CreateItem Include="$(OutputPath)\**">
<Output TaskParameter="Include" ItemName="OutputFiles"/>
</CreateItem>
followed by:
<Target Name="AfterBuild">
<UploadTask FilesToPublish="#(OutputFiles)" />
</Target>