NAnt and ASP.NET on Mono

Most of my personal projects are built on top of ASP.NET, Mono and Lighttpd. One of the benefits of keeping them all running on the same stack (as opposed to mixing Python, Mono and PHP together) is that I don't need to maintain different infrastructure bits to keep them all up and running. Two key pieces that keep it easy to dive back into the the side-project whenever I have some (spurious) free time are my NAnt scripts and my push scripts.

NAnt
I use my NAnt script for a bit more than just building my web projects, more often than not I use it to build, deploy and test everything related to the site. My projects are typically laid out like:

  • bin/ Built DLLs, not in Subversion
  • configs/ Web.config files per-development machine
  • libraries/ External libraries, such as Memcached.Client.dll, etc.
  • schemas/ Files containing the SQL for rebuilding my database
  • site/ Fully built web project, including Web.config and .aspx files
  • sources/ Actual code, .aspx.cs and web folder (htdocs/ containing styles, javascript, etc)

Executing "nant run" will build the entire project and construct the full version of the web application in the site/ and finally fire up xsp2 on localhost for testing. The following NAnt file is what I've been carrying from project to project.

  1. <?xml version="1.0"?>
  2. <project name="MyProject" default="library" basedir=".">
  3. <property name="debug" value="true" overwrite="false" />
  4. <property name="project.name" value="MyProject"/>
  5. <property name="project.version" value="1.0.0"/>
  6. <property name="library" value="MyProject.dll"/>
  7. <tstamp property="build.date" pattern="yyyyMMdd" verbose="true" />
  8.  
  9. <!-- These are being definde for posterity's sake, as they may change in the future -->
  10. <property name="bin_dir" value="bin"/>
  11. <property name="src_dir" value="sources"/>
  12. <property name="lib_dir" value="libraries"/>
  13. <property name="site_dir" value="site"/>
  14. <property name="deps_dir" value="deps/"/>
  15. <property name="contrib_dir" value="contrib/"/>
  16.  
  17. <!-- xsp specific properties -->
  18. <property name="xsp_port" value="8088"/>
  19. <property name="xsp_root" value="${site_dir}"/>
  20. <property name="xsp_apps" value="/:../${bin_dir}"/>
  21. <!--// End properties -->
  22.  
  23. <target name="library" description="Basic MyProject build task" >
  24. <echo message="Building ${project.name}-${project.version}"/>
  25. <csc target="library" output="${bin_dir}/${library}">
  26. <sources>
  27. <include name="${src_dir}/**.cs"/>
  28. </sources>
  29. <references>
  30. <include name="Npgsql.dll"/>
  31. </references>
  32. </csc>
  33. </target>
  34. <target name="clean" description="Clean up MyProject">
  35. <echo message="Cleaning ${project.name}"/>
  36. <delete>
  37. <fileset>
  38. <include name="${bin_dir}/**.dll"/>
  39. <include name="${site_dir}/**.dll"/>
  40. <include name="${site_dir}/**.aspx"/>
  41. </fileset>
  42. </delete>
  43. </target>
  44. <target name="site" description="Populate the site/ directory">
  45. <copy todir="${site_dir}">
  46. <fileset basedir="${src_dir}/htdocs">
  47. <include name="**"/>
  48. </fileset>
  49. </copy>
  50. <copy todir="${site_dir}/contrib">
  51. <fileset basedir="${contrib_dir}">
  52. <include name="**"/>
  53. </fileset>
  54. </copy>
  55. <copy todir="${bin_dir}">
  56. <fileset basedir="${lib_dir}">
  57. <include name="*"/>
  58. </fileset>
  59. </copy>
  60. <!-- Copying bin/ into the site/ directory sucks, but xsp2 is buggy
  61.   with the applications parameter
  62.   -->
  63. <copy todir="${site_dir}">
  64. <fileset>
  65. <include name="bin/*.dll"/>
  66. </fileset>
  67. </copy>
  68. </target>
  69. <target name="run" description="Runs the xsp2 web server on the port cited above" depends="library, site">
  70. <echo message="Starting the xsp2 web server running on port ${xsp_port}"/>
  71. <exec program="xsp2" failonerror="true" commandline="--port ${xsp_port} --root ${xsp_root}"/>
  72. </target>
  73. </project>

The Push Script
Since I usually build and deploy on the same machine, I use a simple script called "push.sh" to handle rsyncing data from the development part of my machine into the live directories.

  1. #!/bin/bash
  2. ###############################
  3. ## Push script variables
  4. export NANT='/usr/bin/nant'
  5. export STAGE=`hostname`
  6. export SOURCE='site/'
  7. export LIVE_TARGET='/serv/www/domains/myproject.com/htdocs/'
  8. export BETA_TARGET='/serv/www/domains/beta.myproject.com/htdocs/'
  9. export TARGET=$BETA_TARGET
  10. ###############################
  11.  
  12. ###############################
  13. ## Internal functions
  14. function output {
  15. echo "===> $1"
  16. }
  17. function build {
  18. ${NANT}|> && ${NANT}|> site
  19. }
  20. ###############################
  21.  
  22. ###############################
  23. ## Build the site first
  24. output "Building the site..."
  25. build
  26. if [ $? -ne 0 ]; then
  27. output "Looks like there was an error building! abort!"
  28. exit 1
  29. fi
  30.  
  31. ###############################
  32. ## Start actual pushing
  33. if [ "${1}" = 'live' ]; then
  34. output " ** PUSHING THE LIVE SITE ***"
  35. export TARGET=$LIVE_TARGET
  36. else
  37. output "Pushing the beta site"
  38. fi
  39.  
  40. output "Using Web.config-${STAGE}"
  41. output "Pushing to: ${TARGET}"
  42.  
  43. cp config/Web.config-${STAGE}|> site/Web.config
  44. rsync --exclude *.swp --exclude .svn/ -av ${SOURCE}|> ${TARGET}|>

Depending on the complexity of the web application I might change the scripts up on a case-by-case basis, but for the most part I have about 5-6 projects out "in the ether" that are built and deployed with a derivative of the NAnt script and push.sh listed above. In general though, they provide a good starting point for the tedious bits of non-Visual Studio-based web development (especially if you're in an entirely Linux-based environment).

Hope you find them helpful :)