Optional project output copying using MSBuild
Different people have different approaches for structuring their projects. This is quite evident when working with open source software such as that found in the Sitecore shared source library where the project is normally setup with the preferences of the maintainer of the project.
There are 2 major approaches to project structure. The first keeps the code under the webroot of your solution and the other keeps it separated from the webroot. Both have advantages and disadvantages and a lot of the time it comes down to personal preference which structure you go with.
My preference is to keep the code out of the webroot so I don’t have any
proj files muddying up my website. I use MSBuild and the
AfterBuild target to copy the output and resource files from my solution into the correct locations.
Recently when I was updating EviBlog I ran into a situation where Mark Van Aalst had setup the module project structure to be developed under a Sitecore webroot. Now it would be extremely arrogant of me to update the project structure to match my preferences especially as I’m not the owner of the module. Luckily I was able to come up with an approach that would satisfy Mark’s preference for code under the webroot and my preference for code outside the webroot.
Mark doesn’t require any
AfterBuild tasks performed while I require some tasks to run to copy the files to the Sitecore instance I’m using. MSBuild contains conditional operators for checking the existence of files and folders. You can use this to determine if a particular task should be run. I could leverage this to conditionally copy the files if a particular file exists.
One of the things I wanted to do with this configuration was to make it as simple as possible for other developers to easily redirect the output based on their own preferences. I didn’t want them to have to go changing MSBuild parameters. If they needed to update the
AfterBuild target that would require them to update the project file and when they checked in their preferences would overwrite what others may have in place.
Another task MSBuild contains out-of-the-box is the
ReadLinesFromFile task. This task allows reading text from a text file. So I could simply have the developer enter the desired target path in a file and MSBuild would take care of the rest.
To do this I created the following target in the project file. This target finds all the config patch files, binary files, layouts, sublayouts, sitecore modules files (such as the WCF SVC file, various CSS files, etc) and excludes all subversion control files and copies them to the path specified in the
deploy.txt file which exists in the same location as the project file.
<Target Name="DeployToWeb"> <ReadLinesFromFile File="deploy.txt"> <Output PropertyName="DeployPath" TaskParameter="Lines" /> </ReadLinesFromFile> <CreateItem Include="App_Config\**\*.*; bin\*.dll;layouts\**\*.aspx; layouts\**\*.ascx;sitecore modules\**\*.*" Exclude="**\.svn\**\*.*"> <Output ItemName="DeployFiles" TaskParameter="Include" /> </CreateItem> <Copy SourceFiles="@(DeployFiles)" DestinationFiles="@(DeployFiles->'$(DeployPath)\%(RelativeDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" /> </Target>
I conditionally invoke this target from the
AfterBuild target if the
deploy.txt file exists.
<Target Name="AfterBuild"> <CallTarget Targets="DeployToWeb" Condition="Exists('deploy.txt')" /> </Target>
And that’s it. So if someone wants to check out the source code to under their webroot, they can do that. If someone wants to check out the source code outside the webroot, all they have to do to have the project files deployed to your Sitecore solution is to create a text file called
deploy.txt in the same location as the project (csproj) file and fill in the path to their Sitecore installation on a single line.