Lloyd.NET

Programing experiments

Zip files after build

One of the pet project I am working on now is an installer application (in D!). One of the problem I need to solve is automatic archival of my files.

Well it turn out that MSBuild (the underlying build tool used by Visual Studio) is quite extensible. While I haven’t read anything which made me a MSBuild master yet, I found this library (msbuildtask) with plenty of MSBuild goodies (including a zip task).

And also a post on Bell Hall’s blog which explain how to take advantage of this task to zip your project output automatically.

Here, I reproduced it below:

Using MSBuild to create a deployment zip

Monday, September 01, 2008

Automated builds are one of the core fundamental musts for software development. However, your build doesn't just have to build the solution and execute your unit tests. For IronEditor, my build also creates two zip files. One zip is the output from the build for archiving purposes, the second is my deployment zip - the zip which actually gets pushed up to CodePlex containing only the files required by the application. In this post, I will cover how you can get MSBuild to zip your build output.

To use zipping functionality within your build scripts, you need to use the MSBuild Community Tasks which is a great collection of MSBuild extensions and a must if you are using MSBuild.

In order to zip your files, you need to specify which files you want to zip. In the script below, I create an ItemGroup called ZipFiles, this includes all the subdirectories (**) and files (*.*) from my Release directory which is my build output folder. I also specify that this group should not include any other zip files. I then create a Builds directory if it doesn't already exist. Finally, I use the Zip task, passing in my ZipFiles ItemGroup which the task uses to know which files to include.

<Target Name="BuildZip" DependsOnTargets="Test">
  <ItemGroup>
      <!-- All files from build -->
      <ZipFiles Include="$(BuildDir)\Release\**\*.*" Exclude="*.zip" />
  </ItemGroup>
  <MakeDir Directories="$(BuildDir)\Builds" Condition="!Exists('$(BuildDir)\Builds')" />
  <Zip Files="@(ZipFiles)"
       WorkingDirectory="$(BuildDir)\Release\"
       ZipFileName="$(BuildDir)\Builds\IronEditor-Build-$(Version).zip"
       ZipLevel="9" />
</Target>

The most important property is the WorkingDirectory, this is the root directory where all the files you want to exist live. If you don't have this set correctly, you will have the additional directories in your zip file which are navigated in order to get to your actual files and just looks rubbish.

My deployment zip also looks very similar and is executed after the above target. The only different is that I individually specify which files and directories to include. For some directories, such as Config, I still include all sub-directories and files it contains as they will all be relevant and required.

<Target Name="BuildInstallZip" DependsOnTargets="BuildZip">
  <ItemGroup>
      <!-- Selected Files -->
      <InstallFiles Include="$(BuildDir)\Release\Config\**\*.*" />
      <InstallFiles Include="$(BuildDir)\Release\LanguageBinaries\**\*.*" />
      <InstallFiles Include="$(BuildDir)\Release\SyntaxFiles\**\*.*" />
      <InstallFiles Include="$(BuildDir)\Release\Fireball.*.dll" />
      <InstallFiles Include="$(BuildDir)\Release\IronEditor.UI.WinForms.exe" />
      <InstallFiles Include="$(BuildDir)\Release\IronEditor.UI.WinForms.config" />
      <InstallFiles Include="$(BuildDir)\Release\IronEditor.Engine.dll" />
      <InstallFiles Include="$(BuildDir)\Release\Microsoft.Scripting.Core.dll" />
      <InstallFiles Include="$(BuildDir)\Release\Microsoft.Scripting.dll" />
      <InstallFiles Include="$(BuildDir)\Release\System.Core.dll" />
  </ItemGroup>
  <MakeDir Directories="$(BuildDir)\Builds" Condition="!Exists('$(BuildDir)\Builds')" />
  <Zip Files="@(InstallFiles)"
       WorkingDirectory="$(BuildDir)\Release\"
       ZipFileName="$(BuildDir)\Builds\IronEditor-$(Version).zip"
       ZipLevel="9" />
</Target>

One thing which tripped me up was that while my ItemGroup was created within a target, it actually has global scope. As such, you need to call the two groups within the two different targets something different.

Once my script has executed, I have two zip files created - one containing everything, the other ready to be released on CodePlex.

image


Categories: Visual Studio | link
Permalink | Comments (0) | Post RSSRSS comment feed
blog comments powered by Disqus