Welcome to MSDN Blogs Sign in | Join | Help

How To: Archive your source files when publishing

A long time ago, when I was trying to look up some piece of information for some blog entry, I stumbled upon a neat site for MSBuild tasks: the MSBuild Community Tasks site. There are several useful build tasks in there, one of which will be the focus of this post: the Zip task. I use this task to package up the source for publication on this blog, and I also use it in the programs I right for entertainment at home.

My archival system for the programs I write in my spare time is pretty simplistic: when I have finished adding a feature and it feels like a good time to use my application, I zip up the sources. Of course, I'll start adding features later, sometimes months or even years later. When I spend so much time away from the program, I'm worried that I'll mess it up so much that I'll just want to revert back to the previous version and start over (that's right: I don't write unit tests at home). Having this zip archive is really handy. Sure, I could use VSS or something fancy, but frankly the programs I write generally don't warrant anything like that. In this entry, I'm going to show how I use the Zip task for archiving.

Since Visual Studio 8 came along, I tend to distribute my applications via ClickOnce. This is a natural time to do the archiving: publishing your app means its a good time to archive the sources. Ah, but when to use the task? Build has both the PreBuild and PostBuild events, which is the old-school way of modifying your build via a command-line command (a .bat file, script, or .exe). The new-school way is to override the BeforeBuild or AfterBuild tasks: I don't know of any good way to do this aside from editing the project file by hand, but I have no qualms about that. Wouldn't it be nice if there was a similar extension point for before or after publishing? Good news: there is.

In Visual Studio, the publish is basically done in 2 phases: there is the build (which in addition to building your binaries, will generate and sign your manifests), and the publish (which pushes all of the appropriate files to the appropriate locations). The first step is all done with MSBuild: it's running msbuild with Target="Publish". The Publish target primarily depends on 2 other targets: Build and PublishOnly:

<PropertyGroup> 
    <PublishDependsOn  Condition="'$(PublishableProject)'=='true'"> 
        SetGenerateManifests; 
        Build; 
        PublishOnly 
    </PublishDependsOn> 
</PropertyGroup>

If you were to take a closer look at what Build depends on, you would see the BeforeBuild and AfterBuild targets, as well as the PreBuildEvent and PostBuildEvent targets. And the PublishOnlyDependsOn property is set to:

<PropertyGroup> 
    <PublishOnlyDependsOn> 
        SetGenerateManifests; 
        PublishBuild; 
        BeforePublish; 
        GenerateManifests; 
        CleanPublishFolder; 
        _CopyFilesToPublishFolder; 
        _DeploymentGenerateBootstrapper; 
        ResolveKeySource; 
        _DeploymentSignClickOnceDeployment; 
        AfterPublish 
    </PublishOnlyDependsOn> 
</PropertyGroup>

Note the BeforePublish and AfterPublish extension points. So it is possible to perform some tasks simply by overriding the AfterPublish target.

Figuring out what to zip is a matter of taste. I make the basic assumption that potentially anything under my project directory is a good zipping candidate. However, there are some directories I want to exclude:

  • obj
  • bin
  • TestResults
  • publish

Similarly, there are several file extensions to avoid, mostly because I only care about the sources:

  • suo: I think this is a file to store user settings for the solution
  • pfx: the signing key for my published application. Definitely don't want to include this just in case I give the zip file to someone else without checking the contents
  • ncb: I think this is intellisense info for VC++ projects
  • user: the user settings for the project file
  • zip: prior archives

So the full information to do the zipping is below:

<Import  Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" /> 
<ItemGroup> 
  <DirectoryToNotZip  Include="obj"> 
    <Visible>False</Visible> 
  </DirectoryToNotZip> 
  <DirectoryToNotZip  Include="bin"> 
    <Visible>False</Visible> 
  </DirectoryToNotZip> 
  <DirectoryToNotZip  Include="TestResults"> 
    <Visible>False</Visible> 
  </DirectoryToNotZip> 
  <DirectoryToNotZip  Include="publish"> 
    <Visible>False</Visible> 
  </DirectoryToNotZip> 
</ItemGroup> 
 
<ItemGroup> 
  <ExtensionToNotZip  Include="suo"> 
    <Visible>False</Visible> 
  </ExtensionToNotZip> 
  <ExtensionToNotZip  Include="pfx"> 
    <Visible>False</Visible> 
  </ExtensionToNotZip> 
  <ExtensionToNotZip  Include="ncb"> 
    <Visible>False</Visible> 
  </ExtensionToNotZip> 
    <ExtensionToNotZip  Include="user"> 
        <Visible>False</Visible> 
    </ExtensionToNotZip> 
    <ExtensionToNotZip  Include="zip"> 
        <Visible>False</Visible> 
    </ExtensionToNotZip> 
</ItemGroup> 
   
<Target  Name="AfterPublish"> 
  <CreateItem  Include="$(ProjectDir)\**\%(DirectoryToNotZip.FileName)\**"> 
    <Output  TaskParameter="Include"  ItemName="FilesToNotZip" /> 
  </CreateItem> 
  <CreateItem  Include="$(ProjectDir)\**\*.%(ExtensionToNotZip.FileName)"> 
    <Output  TaskParameter="Include"  ItemName="FilesToNotZip" /> 
  </CreateItem> 
  <CreateItem  Include="$(ProjectDir)\**\*.*"  Exclude="@(FilesToNotZip)"> 
    <Output  TaskParameter="Include"  ItemName="FilesToZip" /> 
  </CreateItem> 
  <FormatVersion  Version="$(ApplicationVersion)"  Revision="$(ApplicationRevision)"  FormatType="Path"> 
    <Output  TaskParameter="OutputVersion"  PropertyName="PackageVersion" /> 
  </FormatVersion> 
  <Zip  Files="@(FilesToZip)"  ZipFileName="$(ProjectDir)\$(ProjectName)-$(PackageVersion)-src.zip" /> 
</Target>

First, need to import the targets file which contains the Zip task information.

Then, I set the directories and file extensions I don't want to zip in Items. I use items because I build up the list of files to zip by making three calls to CreateItem. The first 2 generate a complete list of files to not zip, and I use that as the list of files to Exclude in the third call. My guess is that I did this in a totally lame way; there's probably some MSBuild stuff I don't know to make the whole process easier, but I'm not entirely sure what it is.

Next, there is a call to the FormatVersion task to figure out what to call my zip file. FormatVersion will take the version of the app that I am publishing (1.0.0.0) and change it into something that may be better for file names (1_0_0_0).

Finally, there is the call to Zip to actually do the archiving. The archive ends up in the project directory.

It would probably be better to zip up my entire solution directory. This would then include the unit tests for my application, and the sources for and class libraries my application is using. I will leave that as an exercise for the reader.

Published Friday, November 30, 2007 6:17 PM by mwade

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Re inventing The Wheel How To Archive your source files when publishing | Quick Diets

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker