# Monday, September 03, 2007
Hooray!  I now have both of my LCD's working in Ubuntu, ala "TwinView."  I attemped to use the nVidia confiuration utility, but ended up needing to manually edit my xorg.conf file to get the right settings.  I think the utility would have worked if my secondary LCD was connected using a DVI cable, but unfortunately it only supports VGA so I think the resolutions were not getting auto-detected properly.

For future reference, here's the relevant portions of my xorg.conf file with the dual monitor stuff in bold:

Section "Monitor"
    Identifier     "Acer AL2216W"
    HorizSync       30.0 - 82.0
    VertRefresh     56.0 - 76.0
    ModeLine       "1680x1050" 146.2 1680 1784 1960 2240 1050 1053 1059 1089 +hsync -vsync
    Option         "DPMS"
EndSection

Section "Device"
    Identifier     "nVidia GeForce 8600 GT"
    Driver         "nvidia"
EndSection

Section "Screen"
    Identifier     "Default Screen"
    Device         "nVidia GeForce 8600 GT"
    Monitor        "Acer AL2216W"
    DefaultDepth    16
    Option         "UseFBDev" "true"
    Option         "RenderAccel" "true"
    Option         "TwinView"
    Option         "MetaModes" "1280x1024, 1680x1050; 1024x768, 1280x1024"
    Option         "TwinViewOrientation" "LeftOf"

    SubSection     "Display"
        Depth       16
        Modes      "1680x1050" "1280x1024" "1280x960" "1280x800" "1152x864" "1024x768" "800x600" "640x480"
    EndSubSection
    SubSection     "Display"
        Depth       24
        Modes      "1680x1050" "1280x1024" "1280x960" "1280x800" "1152x864" "1024x768" "800x600" "640x480"
    EndSubSection
EndSection

Monday, September 03, 2007 4:48:35 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, September 02, 2007
I finally got 1680x1050 resolution working on my GeForce 8600 GT and Acer 22" widescreen LCD.  I used the Wubi installer for this which made it super easy to dual boot with Vista, however on the login screen I kept getting an "Out of Range" error using the built in OSS nVidia (nv) drivers.  After some reading I found that I would need the nVidia provided binary drivers to get dual monitors working anway, so I thought I would see if this would allow me to run at the native resolution of my monitor.  Of course I found that my particular video card, GeForce 8600 GT, was not supported by the nVidia binary driver installer.  I ended up doing a manual install of the drivers which actually worked, unlike the untold number of xorg.conf edits I made previously.

  1. Download the NVidia binary drivers from their website.
  2. Change to command line (CTRL ALT F2), and shutdown your display manager: sudo /etc/init.d/gdm stop
  3. Install the dev libc libraries since no precompiled libs exist for my Ubuntu version.  sudo apt-get install libc-dev.
  4. Install the drivers: sudo sh NVIDIA* -k (run this from the location you downloaded the binary drivers too).
  5. Follow the install instructions, when prompted allow the installer to configure your xorg.conf file.

Sunday, September 02, 2007 6:13:19 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, September 01, 2007

I finally figured out why I was having problems specifying sub-folders (other than trunk) in my ccnet.config SVN source control provider trunkUrl element.  After toying around with svn log (which is what CC.NET uses to find changes), I discovered it only worked on some of the folders in our repository.  As it turns out you must specify the folder ensuring you are respecting letter case.

This does not work: svn log http://mysvnserver/svn/gp/trunk/commons

This does work: svn log http://mysvnserver/svn/gp/trunk/Commons

Notice the upper case C on the second line.  I'm sure this is probably documented somewhere in the SVN docs, but I don't remember seeing it.  The other possibility is that Apache is causing the problem.  Perhaps on Monday I'll care enough to look at the docs.

Saturday, September 01, 2007 12:27:03 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, August 31, 2007

For reference, here's how you update your app.config appSettings using MSBuild Community Tasks XmlUpdate.  This example actually batches several app.configs that need changing.

<XmlUpdate

  XmlFileName="%(ConfigFilesToCobrand.FullPath)"

  XPath="//configuration/appSettings/add[@key='MarketSegmentID']/@value"

  Value="$(MarketSegmentId)" />

Friday, August 31, 2007 8:12:56 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

I think most people probably know how to version C# projects by now, but for my own future reference here is how I'm currently doing it. 

In my project's csproj file I append the following VersionProject target to the BuildDependsOn project.  You could override the BeforeBuild target, but appending a dependent target is safer according to Sayed Hashimi.  The following goes directly into each of my csproj files:

<PropertyGroup>

  <SourceDirectory>$(MSBuildProjectDirectory)\..\..\..</SourceDirectory>

  <ProjectDirectory>$(MSBuildProjectDirectory)</ProjectDirectory>

</PropertyGroup>

<Import Project="$(SourceDirectory)\utils\global.targets" />

<PropertyGroup>

  <BuildDependsOn>

    VersionProject;

    $(BuildDependsOn);

  </BuildDependsOn>

</PropertyGroup>

 

The VersionProject target is a custom target in my global.targets MSBuild project file which gets included into my csproj file.  This target is using the MSBuild community tasks' AssemblyInfo task.

<Target Name="VersionProject">

  <Message Text="Generating AssemblyInfo.cs Version: $(BuildVersion)"/>

  <MakeDir

    Directories="$(ProjectDirectory)\Properties"

    Condition="!Exists('$(ProjectDirectory)\Properties')" />

  <AssemblyInfo CodeLanguage="CS"

    OutputFile="$(ProjectDirectory)\Properties\AssemblyInfo.cs"

    AssemblyCompany="$(CompanyName)"

    AssemblyProduct="$(ProductName)"

    AssemblyCopyright="$(Copyright)"

    AssemblyVersion="$(BuildVersion)"

    AssemblyFileVersion="$(BuildVersion)"

    AssemblyTitle="$(ProductName)"

    AssemblyDescription="$(ProductName)"/>

</Target>

 

The great thing about this, I can reuse this target over and over again for each of my projects.  Some properties like the BuildVersion are set when running under CC.NET, others like CompanyName, Copyright are set once in the global.targets file as these don't change between projects.  By default my global.targets file will default the ProductName to the MSBuild project file name (minus the file extension), this of course can be overridden in any number of ways - including from CC.NET. 

The nice thing is, this will work when building from the command line with MSBuild.exe or from within Visual Studio.  This last point is important because we don't ever checkin the AssemblyInfo.cs source files to SVN (we set SVN ignore on these since they are autogenerated on every build) and most developers would like to checkout, open the solution, and finally CTRL SHIFT B.  Some OSS projects I've worked on require you to build from the command line first (to generate the AssemblyInfo.cs files) before you can build from Visual Studio; I believe this tends to confuse most .NET developers since most are so IDE dependant.

Another thing to note is that if a developer wanted to build a specifically versioned project from within Visual Studio all they would need to do would be to set an environment variable before starting Visual Studio, specifically: BUILDVERSION=1.0.0.1503.

Friday, August 31, 2007 7:07:50 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, August 30, 2007

Something I noticed today while cleaning up an MSBuild script is that there seems to be a direct correlation between the load time of bootstrapping MSBuild and your ItemGroups.  I noticed this because I have an ItemGroup that has an exclude to ignore any .svn folders on disk that I set at the parent folder level which contains a lot of files.

<ItemGroup>

  <System32Files

    Include="$(ProjectDirectory)\Libs\SdDriver\**\*.*"

    Exclude="$(ProjectDirectory)\**\$(SvnFolder)\**"/>

</ItemGroup

 

WHen I changed the above Exclude to $(ProjectDirectory)\Libs\**\$(SvnFolder)\** my build script load time was noticeably faster.  The interesting thing is, MSBuild doesn't count the loading of ItemGroups in its calculation of "Time Elapsed," running with either exclude setting produced identical Time Elapsed results - even though there was an obvious difference in run times.

Thursday, August 30, 2007 4:19:50 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, August 22, 2007

I have multiple projects checked into my Subversion repository, but CC.NET out of the box will build all of them when any source file get checked into any part of the repository under trunk.  The desired behavior is to have only a build get kicked off when a source file gets checked in under its project folder.  I was able to do this when using Perforce with CC.NET by creating multiple views, but in SVN I haven't found a way to do this yet.

Unfortunately there doesn't seem to be a built in way to specify a URL filter in CruiseControl.NET for when a build gets kicked off in Subversion (I'm using CC.NET 1.3).  The current SVN source control provider in CC.NET only takes a trunk URL, and doesn't like it when you specify a subdirectory.    For now I've just hacked the Svn class in CC.NET to apply a filter using a new TrunkWatchUrl element.  In the following example, a build will only be kicked off when a change happens under http://svnserver/svn/gp/trunk/MyProject.

<sourcecontrol type='svn'>

  <trunkUrl>http://svnserver/svn/gp/trunk</trunkUrl>

  <trunkWatchUrl>http://svnserver/svn/gp/trunk/MyProject</trunkWatchUrl>

  <tagBaseUrl>http://svnserver/svn/gp/tags</tagBaseUrl>

  <workingDirectory>c:\autobuild\src\server</workingDirectory>

  <executable>C:\Program Files\Subversion\bin\svn.exe</executable>

  <username>domain\svcautobuild</username>

  <password>pass</password>

  <autoGetSource>true</autoGetSource>

  <tagOnSuccess>true</tagOnSuccess>

</sourcecontrol>

 

The associated code changes to Svn.cs:

[ReflectorProperty("trunkWatchUrl", Required = false)]

public string TrunkWatchUrl;

 

public override Modification[] GetModifications(IIntegrationResult from, IIntegrationResult to)

{

    ProcessResult result = Execute(NewHistoryProcessInfo(from, to));

    Modification[] modifications = ParseModifications(result, from.StartTime, to.StartTime);

 

    if (!string.IsNullOrEmpty(TrunkWatchUrl))

    {

        string trunkPath = TrunkWatchUrl.ToLower();

        modifications = Array.FindAll(modifications, delegate(Modification mod)

        {

            string[] folderParts = mod.FolderName.Split('/');

            if (folderParts.Length < 2)

                return false;

 

            string modFirstPathPart = folderParts[1];

            int trunkStartIdx = trunkPath.IndexOf(modFirstPathPart);

 

            if (trunkStartIdx < 0)

                return false;

 

            string localTrunkPathPart = trunkPath.Substring(trunkStartIdx).ToLower();

            return mod.FolderName.ToLower().Contains(localTrunkPathPart);

        });

    }

 

    if (UrlBuilder != null)

    {

        UrlBuilder.SetupModification(modifications);

    }

 

    return modifications;

}

 

Wednesday, August 22, 2007 10:59:51 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [4]  | 
# Sunday, August 19, 2007

Project structure is probably one of the most important things to get right.  If things are not setup in a consistent manner you will have a hard time managing your software builds.  I find convention over configuration to be of great help especially when creating new builds.  We want the project structure to be organized and easy to use, which means it should be easy for new developers to figure out where things are and where new files should go.  For this series I will be using the fictitious FoodBankTracker application.

I like to use multiple solution files at the root of my source control repository, this allows me to share projects between different solutions as project references are so much easier to deal with than file based assembly references.

The root of the source control repository

In the SharedLibs folder I have all my 3rd party file based assembly references which are used during the build process, things like: NUnit, Castle, NHibernate, RhinoMocks etc.  Other than these 3rd party assemblies, all of my references are project based.

In the Tools folder I keep build tools checked in such as NUnit, Doxygen, and MSBuildCommunityTasks.  The Tools folder differs from the SharedLibs folder in one key aspect, the SharedLibs folder contains assemblies that may be deployed with the built application, where the executables and assemblies in the Tools folder are only used during the build process.   Tools are checked into source control for several reasons:

  • New workstations don't require so many 3rd party tool installs.
  • Upgrades across the team are as easy as svn update.
  • Relative tool paths are fixed, which makes automating builds that much easier.

Tools directory

I also keep a generic global.targets MSBuild file in the Tools folder which gets included in all my MSBuild project files.  Global.targets keeps shared settings and targets that are common to all projects; this saves me time when configuring a new project, but it also allows me to change a tool path or target without touching every single build file in source control.  The global.targets also includes the MSBuildCommunityTasks which contains additional targets that will be used; by including it in global.targets its just one less thing I have to include in each build file.  Most importantly this target file keeps all the paths to the different tools used during the build process, remember we want to keep things consistent across projects.  This target build script also sets some build properties like version, company name, and sets some paths used during the build process.

Before global.targets gets included, the parent build script needs to set the $(SourceDirectory) property which should point to the root of the source control repository.  This path is used to find where things are in the source control repository relative to the trunk.  The parent build file may also want to set a friendly product name property, but this is purely optional.

 

<!-- The SourceDirectory property must be set prior to including this file -->

<!-- The ProductName property should be set prior to including this file -->

 

<PropertyGroup>

  <BuildVersion>$(CCNetLabel)</BuildVersion>

  <BuildVersion Condition="'$(BuildVersion)' == ''">0.0.0.0</BuildVersion>

  <CompanyName>Sneal</CompanyName>

  <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>

  <ProductName Condition="'$(ProductName)' == ''">$(MSBuildProjectName)</ProductName>

</PropertyGroup>

 

<PropertyGroup>

  <NUnitPath>$(SourceDirectory)\Tools\NUnit\bin\nunit-console.exe</NUnitPath>

  <DevEnvPath>&quot;$(VS80COMNTOOLS)..\ide\devenv.com&quot;</DevEnvPath>

  <DoxygenPath>$(SourceDirectory)\Tools\Doxygen\doxygen.exe</DoxygenPath>

  <MSBuildCommunityTasksPath>

    $(SourceDirectory)\Tools\MSBuildCommunityTasks

  </MSBuildCommunityTasksPath>

</PropertyGroup>

 

<Import Project=

"$(SourceDirectory)\Tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

 

<PropertyGroup>

  <ArtifactDirectory>$(CCNetArtifactDirectory)</ArtifactDirectory>

  <ArtifactDirectory Condition="'$(ArtifactDirectory)' == ''">

    $(SourceDirectory)\artifacts\$(ProductName)

  </ArtifactDirectory>

  <PublishDirectory Condition="'$(PublishDirectory)' == ''">

    \\buildserver\builds\$(ProductName)\$(BuildVersion)

  </PublishDirectory>

  <TempZipDirectory Condition="'$(TempZipDirectory)' == ''">

    $(ArtifactDirectory)\ZipImage

  </TempZipDirectory>

</PropertyGroup>

 

Notice that this reusable targets file tends to be passive, i.e. it doesn't overwrite any properties if they've already been set.  One thing to note is that non-official CC.NET builds will be built using version 0.0.0.0, which would be used if a developer did a local build.  When CC.NET runs a build script it will set some additional properties, one of which would be build version.  Global.targets include some other paths and reusable targets that are not shown, but we won't talk about the reusable targets just yet.

Besides setting paths to build tools we also set properties for build directories, specifically: $(ArtifactDirectory), $(PublishDirectory), and $(TempZipDirectory).  The ArtifactDirectory property should point to where all build artifacts get spit out to.  Artifacts are things like XML result files from NUnit, MSBuild, and Doxyen output.  If running under CC.NET this will be the CC.NET artifact directory.  The TempZipDirectory property points to where all build output gets copied to, to build up a disk image in the proper layout for the zip file which will contain our ready for deployment build.  Everything in the temp zip directory gets zipped and then copied to the publish directory which is usually a network accessible location on the build server, here it would be \\buildserver\builds\FoodBankTracker\0.0.0.0

The commons folder contains a reusable library that I use between most, if not all, of my solutions.  This contains the actual library and another unit test project.  This project is built in the same fashion as the FoodBankTracker application, but will focus just on the one application.

FoodBankTracker application folder Now for the FoodBankTracker folder, without the FoodBankTracker application there would be no need for everything else we've talked about up to this point.  As you can see in the image, the application is broken out into four main logical areas: core, data, presentation, and web.  You will also notice that the main application and unit test projects are all at the same folder level and the database folder which contains the database scripts used to build the application's database.  There is generally a 1:1 ratio of unit test projects versus normal projects, but the important thing to note is that the test code is in a separate folder and project from the application code. 

All of the projects are class library projects except for the web project and the database project.  The web project is a normal web application project that only contains very thin display logic, while the database is a (.dbp) database project where we keep our SQL scripts. Solution explorer view of FoodBankTracker Inside the solution the different project types are logically organized between the core application and the Tests solution folder.  Separating out projects logically inside the solution instead of on disk allows me to easily move things around in the future without adversely effecting the build scripts.  Also since I've positioned my solution file at the root, I can easily add project references to my Commons library and unit test project.  This also allows me to add new shared "common" features that much quicker, because its just as easy to add it to the Commons project as it is to add it to one of the FoodBankTracker projects.

Sunday, August 19, 2007 4:34:01 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, August 09, 2007

I was browsing through our production web servers application event logs today and noticed a bunch of errors from .NET 2.0 Runtime Error Reporting about w3wp.exe crashing.  This naturally bothered me being a former systems administrator; it also bothered me because I was afraid that our asp.net application was the source.  After a couple hours of pair troubleshooting, we found that every time our app pool got recycled it was crashing, thus causing a nasty application event log message.  This was caused by the fact we were running our web server as Windows Server 2003 domain controllers.  The fix was to set the proper permissions (Query Value, Set Value, Create Subkey, Enumerate Subkeys, Notify and Read Control) on the following registry key for the Network Service account:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ASP.NET_2.0.50727\Names

For more info see this article: http://channel9.msdn.com/ShowPost.aspx?PostID=215428

Wednesday, August 08, 2007 11:19:12 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  |