ASPNETCOMPILER The Target Directory could not be deleted. Please delete it manually or choose a different target – SubVersion

I’d added some projects to SubVersion today and later on added a CruiseControl.NET build.  I then started getting build failures due to the following:

ASPNETCOMPILER The Target Directory could not be deleted. Please delete it manually, or choose a different target

After a bit of looking around with the SysInternals Process Monitor I couldn’t find anything weird (e.g access denied due to someone locking the folder) and then saw that my output folder from the project (ASP.NET Web Deployment Project) was under SubVersion control (below)

Whoops! – after a swift delete of the folder (also in SubVersion) normality was resumed.  That’s another good reason not to put binaries into source control!

How to extract only changed files from SubVersion for partial deployment using TortoiseSVN

I was really surprised how long it took me to find out how to do this – as it’s quite a simple operation, but if your deployment folder structure matches your SVN repository (e.g. classic ASP site, PHP etc) and you want to do a partial deployment of only files changed in a particular revision (or revisions) then here’s how to get the files (complete with folder structure) using TortoiseSVN:



  1. First you need to work out how you’re going to identify your revision range.  There’s a number of ways to go about this:


    1. Version comments are your friend

    2. You could just note the revision number when you commit.

    3. You could use tags to help identify the range.  I use CruiseControl.NET and so all ‘builds’ are automatically tagged.  If you always release from tags then you can just ‘show log’ on the tag and see the max revision number. 

    4. You could just use a date range.

  2. Once you’ve decided ‘how’ you’re going to identify the revisions (it may be as simple as the ‘last commit’) then either through your working copy, or from Repo Browser ‘show log’ on the root of your ‘deployment’ folder structure.  The files you’re interested in may be within a ‘code’ or ‘source’ folder or similar so you only want to get the files you want to deploy. 

  3. Select the revision/s based on the method you’re using (step 1) and do ‘Compare revisions’.  If you’re just looking at one revision then do ‘Compare with previous revision’.

  4. Review the list of files and select all (assuming the list looks correct) then right-click and ‘Export selection to…’

  5. The file structure will be created at the folder you specify, and you can then zip or do whatever you normally do to deploy.

If you only want the list of files then you can choose ‘Save list of selected files to…’ (text file).


This is all cool and simple, but it’s still quite a manual process.  If you’re certain of the revisions or you automatically keep track of the last deployment revision then it would probably make sense to automate this further with something like NAnt (which is what I’ll attempt to eventually get round to). 


This process also doesn’t cater for deletions (as such), so special care needs to be taken when reviewing the list of files (the action column shows the nature of the changes).

Setting up a Continuous Integration .NET Build Server without Visual Studio

We start with Windows XP SP2 (doesn’t really need to be a ‘server’).  My requirement is to rely on the .NET framework and open source tools – i.e. not requiring a Visual Studio Licence.  We’re using .NET 2.0 so everything will be in reference to that.


I assume here that you’ll be familiar with the actual software below and just want to get a Build Server up and running without having to install Visual Studio.  If you’re not familiar with Continuous Integration then start by looking at Martin Fowler’s Continuous Integration article and then the info on CruiseControl.NET, as that’s the tool that pulls everything together. 


There’s help on each of the sites below for installing and using each of the tools, so I won’t go into detail about each one.  The order of the list isn’t critical, but you’ll probably have some issues unless all are done.



  1. Install IIS from Add/Remove Windows Components (used for CruiseControl.NET) if not already present
  2. Open up a command prompt and run C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -i (to install ASP.NET in IIS)
  3. Install CruiseControl.NET (1.4) from http://confluence.public.thoughtworks.org/display/CCNET/Download.  NOTE:  If you’re using a remote SubVersion repository (as in my case) then you’ll need to run the CruiseControl.NET Service as a domain user that has access to the network location of the repository  rather than LocalSystem.  This is because CruiseControl will be using the SVN client to poll for changes. 
  4. Install Microsoft .NET Framework 2.0 SP1 from http://www.microsoft.com/downloads/details.aspx?familyid=029196ed-04eb-471e-8a99-3c61d19a4c5a&displaylang=en
  5. Install latest SubVersion (1.5) from http://www.collab.net/downloads/subversion/
  6. Install appropriate NUnit from http://nunit.org/index.php?p=download (targeting .NET framework 2.0 – I have 2.4.6)
  7. Install latest FxCop from http://www.microsoft.com/downloads/details.aspx?familyid=3389F7E4-0E55-4A4D-BC74-4AEABB17997B
  8. Install .NET Framework 2.0 SDK from http://www.microsoft.com/downloads/details.aspx?familyid=fe6f2099-b7b4-4f47-a244-c96d69c35dec&displaylang=en (you’ll need this to get around a NAnt bug whereby it can’t resolve an internal property to load the .NET framework)
  9. Download latest NAnt from http://nant.sourceforge.net/
  10. Download latest NAntContrib from http://nantcontrib.sourceforge.net/ (You’ll need this to run MSBuild)
  11. To save getting errors when building Web Projects (and other types) the easiest thing is to copy c:\program files\msbuild from your dev machine to the build server (otherwise you’ll have to alter the path of where the targets are in each project).

Once you’ve got all of these set up then you’ll be able to add some builds to your ccnet.config file ( most likely c:\program files\CruiseControl.NET\server\ccnet.config)


Test CruiseControl’s happy by going to http://localhost/ccnet It should come up OK but basically show ‘no projects’.


I’m not going to go into detail about setting up the builds here but may cover that in a follow up article, as it requires some more setup with SVN and a ‘standard’ project structure (to get benefit from reuse of build scripts).  If you’re still with me then I’ll share one last thing which might help… 


Some people choose to have NAnt in a standard place and just reference it from the PATH, but I now use the power of svn:externals to drag in NAnt, NUnit and other common external dependencies like MS Enterprise Library from a shared SVN location to each project.  This means you just get latest of a project and it has ‘everything’ needed to build – no installations or assumptions about locations of tools.

Upgrading SubVersion Server and Repositories to 1.5

After upgrading TortoiseSVN and AnkhSVN to SubVersion 1.5, I set about upgrading the server this morning.  The main reason for this is that I wanted to merge a branch back into the trunk using the integrated merge option, and this simply doesn’t work with a 1.4x server and repository.  Everything needs to be 1.5 for that to work. 


We’re currently on 1.4.5 ish, from a previous 1-click Windows/Apache setup with some mods for groups authentication


I just downloaded the 1.50 server Windows binary and it actually now does a nice thing of asking whether you want to use SvnServe or Apache. 


I had some issues originally running Apache 2.2 with 1.4, and ended up with Apache 2.0.x but gave the new 1.5 install a go.  The following is how I upgraded my install from 1.4x using the same httpd.conf settings from the previous installation (link above).


Upgrading the Server



  1. Stop existing services (Apache etc)

  2. Back up your httpd.conf (my original install was apache 2.0 and went into a different folder) – but you’ll need the settings in any case

  3. Back up mod_auth_sspi.so from your existing Apache installation (/modules folder).  If you were using Apache 2.0 then don’t bother ‘cos it won’t work with 2.2.

  4. NOTE: If you want to upgrade your repository (required to use new 1.5 merging functionality) you need to first dump out the existing repository using the ‘old’ installation


    1. Backup the existing repository

    2. Run svnadmin /repos/path > dumpfile.txt

    3. You do the rest once you’ve upgraded the server

  5. Install 1.50 server (choosing Apache and whatever port / repository location you previously had.  You’ll replace the repository location later, but make sure your port’s right to save confusion and updates to httpd.conf).

  6. Edit the new httpd.conf replacing all ‘<Location>‘ sections at the bottom with that from your saved config.

  7. Paste the following line at the bottom of the LoadModule section
    LoadModule sspi_auth_module modules/mod_auth_sspi.so

  8. Copy an Apache 2.2-compatible mod_auth_sspi.so into the /modules folder.  As noted above if you take mod_auth_sspi.so that was compiled against Apache 2.0 you’ll get a message along the lines of:
     
    httpd: Syntax error on line 117 of C:/Program Files/CollabNet Subversion Server/httpd/conf/httpd.conf: API module structure ‘sspi_auth_module’ in file C:/Program Files/CollabNet Subversion Server/httpd/modules/mod_auth_sspi.so is garbled – expected signature 41503232 but saw 41503230 – perhaps this is not an Apache module DSO, or was compiled for a different Apache version?
     
    If you go to the home of mod_auth_sspi you’ll only find a module compiled against 2.0 so after hunting around a bit I found a copy compiled against 2.2.  Just copy the .so file into your modules folder)

  9. Start her up, and hopefully hey presto, you’ll have 1.50 server.  You can verify this easily by loading up the repository url in your browser and the footer should say something like… Powered by Subversion version 1.5.0 (r31699).

Upgrading the repository



  1. With the new version (1.5) binaries run:


    1. svnadmin create /temp/repos/path

    2. svnadmin load /temp/repos/path < dumpfile.txt

  2. Swap the old and new repository folders (useful to keep the backup)

  3. You’re all up to date.

Upgrading TortoiseSVN, Subversion 1.5 and AnkhSVN.

I thought I’d upgrade to v1.5 of TortoiseSVN this morning (leaving the server on V1.4.x) – of course completely forgetting that I use AnkhSVN in Visual Studio. 


New versions of TortoiseSVN and Subversion tend to upgrade the format for Working Copies.  This means AnkhSVN (1.02) was no longer compatible with my ‘new’ Working Copy and I got the following error…


This client is too old to work with Working copy ‘xxx’. Please get a newer Subversion client.


Thankfully AnkhSVN 2.0 is on the way and I downloaded a nightly build (2.0.4523.91) and installed (without uninstalling 1.0.2).  I usually do this to ‘test’ whether people write good installers.  Most people do the right thing with AutoUpgrade and 1.0.2 dutifully disappeared.


I loaded up Visual Studio with the same solution and – ‘Where’s my AnkhSVN menus gone?’.  As V2.0 is not even Alpha yet there’s not much in the way of obvious help on the Collabnet site.  The community area may have more, but I luckily didn’t need it.


I noticed in the application folder that there’s now an Ankh.Scc.dll.  Well blow me if they haven’t gone and made it a ‘standard’ Visual Studio SCC Provider!  Tools –> Options –> Source Control –> Plug-in Selection.  There it is.


Once you’ve got over that, then you might find a few little errors here and there, but the main difference is that instead of an ANKH menu on Tools and in the Solution Explorer context menu – you get a Subversion context menu. 


I’m liking it so far.  I think it’s probably stable enough to put your faith in and make the jump to SVN 1.5.


Update (08/07/2008) 
I submitted a bug report yesterday on an error I encountered (from the nice ‘send error details’ link) and got a reply saying ‘fixed in latest build’ the next day.  This bodes well!!!  Reasons to pay money for VisualSVN now disappearing fast…


Update (23/07/2008)


AnkhSVN v2.0 now officially out (that was a quick alpha/beta phase!)

Using RSS.NET to re-write an existing feed XML file

Don’t know what happened to RSS.NET.  Looks like it’s trying to go commercial, but still very quiet.  Code examples are few and far between (with some simple ones on the site).  Also on InformIT.


I’m writing a quick RSS console app (as I lost the last one I wrote!) that I can use to write an RSS feed from a SubVersion hook.  Most people use a pre-existing tool for Python (can’t remember the name), but I thought I’d give RSS.NET another go just for kicks.


The example above works fine assuming you’re maintaining state somewhere other than the feed xml file itself.  The example also assumes you’re serving this up to the web.  You can override the RssFeed.Write() method to take a filename.


If run the same code again (assuming you’ve written to a file) it will simply overwrite it with one item (not add to it).  This isn’t what I wanted so…


You need to



  1. Read the file back in if it’s there – otherwise create
  2. Add your item to the existing channel if it’s there – otherwise create
  3. Fix the date behaviour as RSS.NET always assumes UTC dates and appends ‘GMT’.  The problem here is that if you’re in Australia (like me) reading and rewriting the same items will effectively add several hours on to existing items every time, because you write the date you read back in for existing items (read and parse into region-specific date, then write back as is).  There’s two ways to fix this:

    1. Before you add your new item – loop through all items and change the item.PubDate to item.PubDate.ToUniversalTime().  This effectively sets it back to the ‘correct’ date.
    2. Change the RSSWriter class in RSS.NET to convert ToUniversalTime for the Item.PubDate, Channel.PubDate etc.  This seems like a better option, but it has potentially more knock on effects in RSS.NET.  I’m here to achieve a result, not change the behaviour (possibly adversely) of RSS.NET so I chose option 1

So here’s the code.  Not finished yet and rough around the edges, but works as I need.  The intention is to avoid the need for config files and configuring up of feeds specifically.  I just want a library function that’s called by a console app.  The web serving will simply be based on the location of the file and pointing to some folder in IIS.


        private static void WriteFeed(string feedFileName, string feedName, string feedDescription, 
        string feedURL, string itemTitle, string itemDescription, 
        DateTime itemPublishDate, 
string itemURL)
        {
            
bool newFeed = false;
            
//Try and first open the feed (to see if it’s existing)
            
RssFeed feed = null;
            try
            
{
                feed 
RssFeed.Read(feedFileName);
            
}
            
catch (FileNotFoundException ex)
            {
                feed 
= new RssFeed();
                
newFeed = true;
            
}
            
catch (Exception ex)
            {
                WriteError(ex)
;
                return;
            
}

            RssChannel channel 
= null;

            
//Loop through all channels and if we’ve got the same title reuse
            
for (int 0i < feed.Channels.Counti++)
            {
                
if (feed.Channels[i].Title == feedName)
                {
                    channel 
feed.Channels[i];
                    break;
                
}
            }

            
if (channel == null)
            {
                channel 
= new RssChannel();
                
feed.Channels.Add(channel)//might blow up if already there?
            
}

            RssItem item 
= new RssItem();

            
item.Title itemTitle;
            
item.Description itemDescription;
            
item.PubDate itemPublishDate.ToUniversalTime();
            
item.Link = new Uri(itemURL);

            
//To ensure we don’t screw up existing dates – convert to UTC
            
foreach (RssItem existingItem in channel.Items)
            {
                existingItem.PubDate 
existingItem.PubDate.ToUniversalTime();
            
}

            
//Now add our new item
            
channel.Items.Add(item);

            
channel.Title feedName;
            
channel.Description feedDescription;
            
//channel.LastBuildDate = channel.Items.LatestPubDate();
            
channel.PubDate DateTime.UtcNow;
            
channel.Link = new Uri(feedURL);

            
feed.Write(feedFileName);
        
}



Colorized by: CarlosAg.CodeColorizer

 


 

Setting up SubVersion with Apache and Windows Group authentication

I found many links tell ing me how to do ‘most’ of this, but like lots of others, just couldn’t put together all the pieces.


My requirements were:



  1. Set up SubVersion to run with a remote repository (on a network drive that’s backed up)
  2. Run with Windows Authentication for all clients (tortoise, browser etc) and hook into the domain
  3. limit access to Windows Groups (not specific users) – to allow a single change to control everything (adding a user to a group that has access to the network resource).

Fact #1.  SubVersion only supports Windows Authentication through Apache.  There may be some hoops you can jump through to get that going with svnserve, but don’t go there.


Fact #2.  SubVersion does not support any Windows AD ‘group’ authentication through its config files, and so you have to do this through Apache.  It supports ‘custom’ groups that you can add domain users to.


The process.


Right, we now know you need to install SubVersion, Apache, and some other bits and pieces to allow Windows Authentication.


1. Install the main components (Follow all instructions on Trumpi’s blog).  This will set up SubVersion, Apache and the necessary modules to do Windows Authentication.


2. Change the ‘Location’ section at the bottom of the Apache httpd.conf to reflect your setup:  I’ve left in some commented lines to show some of the alternatives:


<Location /svn>
DAV svn
#SVNParentPath d:\LocalApp
#SVNPath D:\LocalApp\SVN
SVNPath //myserver/myshare$/SVN #NOTE the // rather than \\ in the UNC path name – you don’t have to use a mapped drive!!!


#User Authentication Policy
AuthName “Subversion”
AuthType SSPI
SSPIAuth On
SSPIAuthoritative On
SSPIDomain mydomain
SSPIOfferBasic On #Essential for TortoiseSVN to access the repository as it doesn’t support Windows integrated authentication
SSPIUsernameCase lower #allows you to type your username in lower case
SSPIOmitDomain On #allows you to just type your username without the domain\ qualifier


# our access control policy enforced by mod_authz_svn
#AuthzSVNAccessFile “D:\LocalApp\SVN\svnaccess.conf” #you shouldn’t need this


#SSLRequireSSL #Look at http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-serversetup.html#tsvn-serversetup-apache-5 if you need it
#require valid-user #User this line if you don’t need to limit to a group – i.e. any domain user

require group mydomain\mydomaingroup #here’s the magic for your group authorisation.  This limits access to the virtual directory
</Location>


3. Run the Apache2 service as a ‘generic’ domain user that is in your windows group (above).  This should also be part of the local administrators group on the web server (you can probably tweak this I was a bit lazy).  Access to the repository is then through the Apache user’s credentials, and each user will simply be authorised based on their group membership at the Apache level.