views:

896

answers:

3

I'm rewriting our NAnt build scripts to make them cleaner and simpler, as well as more general purpose.

One of the steps in our build process is to package certain files into a zip file. Before we had created a fileset with lots of included file types, trying to catch everything that might be in the project. This occasionally caused problems when we wanted to include a non-standard file type with the project.

I was hoping that I could find a way to create a fileset based on the files (and, also, a subset of the files) listed in the Visual Studio project file (.csproj). I could then use this fileset in a zip task. I haven't found anything that does this automatically (though the now-deprecated SLiNgshoT task in NAntContrib looked a little promising).

I started down the path of trying to do this manually, but have gotten stuck. I have a target that gets the project from the solution (using regex), then tries to get each Content file in the project using xmlpeek (with the XPath query /n:Project/n:ItemGroup/n:Content/@Include). The problem here is that xmlpeek doesn't return every value, just the first. And, even if it did return every value, I'm not sure how I'd get it into a fileset from here.

Is there any way to salvage this track of thinking? Can I accomplish what I want with a custom NAnt task (I'd prefer not to have every project dependent on a custom task)? Is there some built-in way to do this that I'm not finding?

Please feel free to ask questions in the comments if something about my goal or method isn't clear.

Thanks!


UPDATE: To clarify, my point in all of this is to make the whole process much more seamless. While I can easily add all .xml files to a package, this often gets .xml files that live in the same folder but aren't really part of the project. When I already have a list of the files that the project uses (separated out between Content and other types, even), it seems a shame not to use that information. Ultimately, no one should have to touch the build file to change what gets included in a package. It doesn't seem like too much of a pipe dream to me...

+1  A: 

See this related question. The microsoft.build.buildengine interface should let you get much better access to the information you need, but unfortunately I think you would have to build a custom task.

But I think that parsing a project file to generate a fileset that is used elsewhere is ... a bit much to put all inside your build script. And since you seem to want to re-use this, I don't think that depending on a custom task is any worse than any other form of re-use (even if you can do it all in existing Nant tasks, you'd still need to have every project inherit that process somehow).

Zac Thompson
That code sample from the other question should be helpful to build out this custom task. I definitely would have gone down the regular expression and XML parsing path, otherwise.
bdukes
+1  A: 

As far as reading your project files. I've done something like this before. I ended up just writing a program that read the project files and built a custom project by project build file.

However I was trying to compile my code base. Looks like you are trying to just zip it.

Considering that the Zip task would allow you to run multiple filesets into it you could create some generic filesets and then just update for your specific ones rather easily.

So you could have something like this:

<fileset id="project.source.objects">
  <include name="**/*.cs"/>
  <include name="**/*.xml"/>
  <include name="**/*.resx"/>
</fileset>

<fileset id="project.misc.sources">
  <include name="MyFile1.someext"/>
</fileset>

Then in your zip target just put:

<zip zipfile="myzip.zip">
  <fileset refid="project.source.objects"/>
  <fileset refid="project.misc.sources"/>
</zip>

Now if you wanted project specifics. There is one other thing you could do. If you are using VS2005 or greater search on T4. It's a template framework for creating plugins that allow you have extra files generated when you do something. Kind of like when you do a class diagram or have a XSD (and it gets it's code behind file, it's done this way).

In most projects that I've worked on we maintain a build file for each project and just keep it up to date. Since we have the generic filesets that's a start so we only really need to update the file for the obscure stuff.

Hope that helps. If you could provide a little more detail I might be able to help further.

Joshua Cauble
That's a good idea to use named filesets to keep the unchanging, generic stuff in one place.
bdukes
A: 

I like the first part of Josh's idea.

Write a small console app to pull the files from the .csproj (since it's just XML in there) and write the list out to a file.

Instead of NAnt's zip task, I would use 7-zip to create the archive with the list you generated in the previous step:

(I'm creating a self extracting archive here)

<target name="ZipBuild">
  <exec program="${SevenZip}" workingdir="${SolutionPath}/Installation/Build.Staging">
    <arg value="a" />
    <arg value="-sfx" />
    <arg value="ReferenceBuild-${build.number}.exe" />
    <arg value="@mycustomfilelist.txt" />
  </exec>
</target>

Hope that helps,

-jason

Jason Slocomb