Posted by: boggin | July 30, 2009

MSBuildCommunityTasks and Versioning

Auto-versioning our assemblies in TeamCity using MSBuild was more fiddly than I expected but ultimately a very clean implementation.

I’m using TeamCity for continuous integration and MSBuild to run our project’s solution file (.sln) as the build script. I wanted each of our builds to have a version number on the assembly (.exe) so that testers would know what they were dealing with. The format for the version number is the familiar dotted quad of Major.Minor.Build.Revision where the Build would be the build number from TeamCity and the Revision would be our version control system (VCS) revision number (our VCS is Perforce).

I use Scrum for Agile software construction, in an OpenUP project management process, so I’ve decided our Major number is the number of the release to the customer and the Minor is the iteration (Sprint) that produced the build. For example, my first build with this system was 0.8.282.11066 which means: we’ve yet to make a release to the customer (0); the build was from the eighth two-week Sprint (8); TeamCity has completed 282 builds; and Perforce is up to revision 11066.

MSBuildCommunityTasks includes an AssemblyInfo task. These are the steps I used to get this working:
(1) added MSBuildCommunityTasks to our “ExternalTools” folder in Perforce and submitted the MSBuild.Community.Tasks.dll and MSBuild.Community.Tasks.Targets files.
(2) integrated the MSBuildCommunityTasks items from step 1 into the solution’s “tools” folder.
(3) updated the MSBuild.Community.Tasks.Targets file to the correct path to the MSBuildCommunityTasksLib (in our “tools” folder from step 2).
(4) imported the Targets file from step 3 into the project file (.csproj).

<MSBuildCommunityTasksTargets>..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets</MSBuildCommunityTasksTargets>
<Import Project="$(MSBuildCommunityTasksTargets)" />

(5) created the properties for the parts of the version number so it is easy to update for releases and works both on the developer’s machine, where the Build number and Revision number are set to 0, and on TeamCity which provides environment variables for the TeamCity build number and the VCS revision number.

  <PropertyGroup>
    <!-- Release -->
    <Major>0</Major>
    <!-- Iteration -->
    <Minor>9</Minor>
    <Build>0</Build>
    <Build Condition="'$(BUILD_NUMBER)' != ''">$(BUILD_NUMBER)</Build>
    <Revision>0</Revision>
    <Revision Condition="'$(BUILD_VCS_NUMBER)' != ''">$(BUILD_VCS_NUMBER)</Revision>
    <Version>$(Major).$(Minor).$(Build).$(Revision)</Version>
  </PropertyGroup>

(6) deleted the current AssemblyInfo.cs from the source and the VCS.
(6) add the AssemblyInfo task that will autogenerate the AssemblyInfo.cs for each build

  <Target Name="BeforeBuild">
     <AssemblyInfo CodeLanguage="CS" 
                OutputFile="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs"
                AssemblyTitle="MyProduct"
                AssemblyDescription="My Product"
                AssemblyConfiguration=""
                AssemblyCompany="MyCompany Ltd"
                AssemblyProduct="MyProduct"
                AssemblyCopyright="Copyright © MyCompany Ltd 2009"
                AssemblyTrademark=""
                ComVisible="false"
                CLSCompliant="true"
                Guid="884276aa-6859-4318-8bb9-073f68a66057"
                AssemblyVersion="$(Version)" />
  </Target>

Now I need to create a WiX project to build a release version and expose it as an artifact in TeamCity so our testers can easily pick up a build themselves.

Technorati Tags:

Posted by: boggin | July 28, 2009

When is a Task ‘Complete’?

In Agile you have to define when a task may be considered ‘Complete’.

‘Complete’ is when:

  • the unit tests are all passing
  • the automated acceptance tests are all passing
  • the task’s user acceptance test is passed
  • all supporting chores are completed, i.e. updating user guides, design documentation, etc..

If all the tasks are complete the workitem may be marked ‘Done’. The Product Owner should be marking ‘Accepted’ any workitem marked ‘Done’. He should be reviewing workitems daily if possible. If it cannot be accepted then he can throw it back into the iteration’s backlog.

Posted by: boggin | July 28, 2009

Development Impediments

The environment at the place I’m currently working is structured to impede development. This can be divided into certain types:

(1) Quality of tools.

The workstations that the developers have are poorly specified for user interface development tasks. The machines are underpowered, resulting in frequent, long timeouts.

The machines cannot be easily upgraded as it is their CPUs that are too long in the tooth. A cost needs to be defined for upgrading machines and when there is the finance available this should be budgeted for. Unfortunately, the company are not big on setting budgets.

It is also difficult to obtain the necessary licences for software.

(2) Control of environment.

The lack of Local Admin rights on the developers’ machines significantly slows the uptake of new technology and the crippled web access severely limits access to information.

The workstation is the developer’s tool of the trade. Restricting the developers’ access to their toolboxes is preventing them from working well. Policies that have been made to prevent abuse of the company’s assets should be enforced through instructions and disciplinary action against offenders; there is no need to treat everyone as if they can’t be trusted to use a computer.

I cannot understate how important this issue is. A software engineer is an expert computer user and there’s no excuse for treating them as anything else.

(3) Specification of projects.

The current projects have no specifications. This means no realistic estimates can be made of when a project will be completed and how much effort will be required. A lot of effort is wasted as the work is developed ad hoc and often requires rework.

Requirements change is to be expected. Indeed, where it provides for a system better aligned with users needs they are to be welcomed. Management, however, must understand and accept the extra costs involved in rework or extra work.

(4) Distrust of developers.

There have been failings from the developers that have resulted, in the past, in misuse of company assets and timewasting. More recently there have been delays in project completion.

To help alleviate this mistrust the developers would like management to be regularly updated on progress. Attention will be drawn to project burndowns and management will be provided with regular demonstrations of the applications.

A company handbook would be useful to state the company’s policies.

Posted by: boggin | February 5, 2009

Installing Aptana Studio 1.2 on Ubuntu 8.10 x86

I’m using Aptana Studio for some PHP/RoR/Python web development and I have Win XP x64 on a Rock xtreme64 D900K but my Sony Vaio TX3 uses Ubuntu (Compiz Fusion is irresistible). To keep the development environments the same I’ve created an Ubuntu guest virtual machine (VM) for PHP work on the Win XP host machine. Aptana is easy to install under Windows but it’s less easy under Linux so it’s worth documenting how this can be done with the current releases.

VirtualBox VM with Windows XP x64 Host and Ubuntu 8.10 Desktop x86 Guest (procedure should work for any Ubuntu 8.10 install).

  1. download and unarchive Aptana Studio Standalone for Linux (v.1.2)
  2. place the aptana folder under /usr/local/aptana

    sudo mv ./aptana/ /usr/local/

  3. install Java v.1.6

    sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-fonts

  4. install xulrunner 1.8.* with the Synaptic Package Manager
  5. save the following script as /usr/local/aptana/runAptana.sh

    #!/bin/bash
    export MOZILLA_FIVE_HOME=/usr/lib/xulrunner
    /usr/local/aptana/AptanaStudio

  6. Make your script executable

    chmod +x runAptana.sh

  7. download and unarchive the Aptana icons: http://support.aptana.com/asap/secure/attachment/10398/aptana_icons.zip
  8. move the aptana_icons folder to under the aptana folder
  9. create a desktop and/or panel launcher

    name: Aptana Studio
    command: browse to /usr/local/aptana/runAptana.sh
    icon: use aptana48×48.png for the desktop launcher
    comment: web development

  10. click on launcher :)

Note: I didn’t need to install Firefox v.2. The current version of FF is 3.0.5.

Technorati Tags: ,

Posted by: boggin | January 30, 2009

Geocode accuracy with UK postcodes and Google APIs

Using the Google APIs is entirely painless so if I need a map in a web app that’s where I’ll start.

I had a list of hotels I wanted to display and instead of looking up the latitude and longitude of each of them by hand I thought I’d use the google.maps.ClientGeocoder functionality. A bit of quick, scruffy code later and it’s looking them all up and putting the markers on the map but not where I expected.

I discovered that the postcodes are being truncated in the search, cutting off the last two letters. This seriously degrades the accuracy of each marker’s placement and many of the markers ended up on top of each other. The reason is probably the cost to Google of licensing the data from the Post Office. Fair enough but I was most of the way to my solution. There’s a simple workaround, however, do your lookup through the Google Search API’s LocalSearch class and pull the lat and lng from that. Bonzer.

In the code below look for the reference to localSearch in the newMarker function.

<html>
<head>
    <script src=”http://www.google.com/jsapi?key=<<INSERT API KEY HERE>>”></script>
    <script type=”text/javascript”>
    google.load(”maps”, “2″,{”other_params”:”sensor=false”});
    google.load(”search”, “1″);
    </script>
    <script type=”text/javascript”>
    var map;
    function loadMap() {
      if (google.maps.BrowserIsCompatible()) {
        map = new google.maps.Map2(document.getElementById(”map”));
        var house = new google.maps.LatLng(52.742844, -0.406194);
        map.setCenter(house, 10);
        var marker = new google.maps.Marker(house, { title: “Venue” });
        map.addOverlay(marker);
        map.addControl(new google.maps.SmallMapControl());
        addBeds();
      }
    }
    function addBeds() {
        var ch = [ 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U' ];
        var name = [ 'The George Hotel', 'Bridge House', 'Dormy House', 'Mill House', 'Maycroft Cottage', 'The Wishing Well Inn', 'Willoughby Arms', 'The Royal Oak Inn', 'The Baskervilles Hotel', 'Lady Annes Hotel', 'The Garden House Hotel', 'The Crown Hotel', 'The Bull and Swan', 'The Griffin Inn', 'The Oak Inn', 'Rock Lodge', 'The Royal Oak Inn', 'Travelodge Hotel', 'The Dolphin Guest House', 'Lindsey Cottage' ];
        var address = [ 'PE9 2LB', 'PE10 0JT', 'PE10 9EZ', 'PE10 9BU', 'PE10 0RB', 'PE10 0AF', 'NG33 4RA', 'NG33', 'Baston', 'PE9 2LJ', 'PE9 2LP', 'PE9 2AG', 'Stamford', 'NG33 4JG', 'pe9 3pa', 'PE9 2RH', 'Duddington, Stamford', 'NG33 5JR', 'PE9 1QD', 'Uffington, Stamford' ];
        var base = “http://www.google.com/mapfiles/marker”;
        for (var i = 0; i < ch.length; ++i) {
            var icon = new google.maps.Icon(G_DEFAULT_ICON);
            icon.image = base + ch[i] + “.png”;
            newMarker(address[i], name[i], icon);
        }
    }
    function newMarker(address, name, icon) {
        // ref: http://www.tomanthony.co.uk/blog/geocoding-uk-postcodes-with-google-map-api/
        var localSearch = new GlocalSearch();
       
        localSearch.setSearchCompleteCallback(null, function() {   
            if (localSearch.results[0]) {
                var lat = localSearch.results[0].lat;
                var lng = localSearch.results[0].lng;
                console.info( address + ” = ” + lat + “, ” + lng );
                var point = new google.maps.LatLng( lat, lng );
                var marker = new google.maps.Marker(point, { icon: icon, title: name });
                map.addOverlay(marker);
            } else {
                console.warn( address + ” not found” );
            }
        });
       
        localSearch.execute( address + “, UK” );
    }
    google.setOnLoadCallback(loadMap);
    </script>
</head>
<body onunload=”google.maps.Unload()”>
    <div id=”map” style=”width:300px; height:420px;”>Loading…</div>
</body>
</html>

Technorati Tags:

Posted by: boggin | September 9, 2008

VoIP on Orange Nokia N82

Orange have disabled the Internet Telephone menu on the Nokia N82 to prevent their subscribers setting up VoIP accounts using the built in SIP stack. You can still use Fring but you can’t use Truphone, Gizmo, etc.. Also, Orange customer support are clueless as are Nokia customer support. I’m being generous here, my opinion is they were directly lying to me. Only Carphone Warehouse were honest about the problem.

To get a working phone you have to debrand it. I managed this with the Nemesis Service Suite (NSS), the EURO 1 product code, the Nokia Software Updater (NSU) and a hard reset.

With NSS (Beta 1.0.38.14) I did the following:
1. Installed choosing Virtual USB device.
2. Started in PC Suite mode (N82 set to PC Suite mode throughout).
3. Clicked on the magnifying glass.
4. Phone Info > Scan
5. Product Code > Enable > Read
6. Entered the EURO 1 product code (0549174)
7. Write
8. Tools > Full Factory > Reset

I restarted my phone just to make sure this hadn’t bricked the device.

With NSU I had to set up Comodo Firewall just so as NSU uses some odd ports, amongst other, less than sensible, programming decisions by Nokia. I was then able to reflash the firmware (v.20.0.062).

Next you have to reset the device so it uses the new firmware. I tried the reset using * + 3 + “Call button” simultaneously while turning on (aka Vulcan nerve pinch) but that didn’t seem to help so I used Ezra’s instructions for a hard reset. Now all the menu options are enabled!

I restored just my contacts list from PC Suite and nothing else. Now I have Truphone and Gizmo working no problem at all and I’ll try to set up Sipgate next.

Here are some other folks experiences: Nokia N82 Debrand & Update, Eric’s Corner.

Posted by: boggin | September 8, 2008

USB drive portable apps

My 1GB USB thumb drive (or flash drive) is over two years old and it’s seen a lot of action. In fact, too much, as it’s cooked. I mean this quite literally – it runs very hot and misreports itself, completely dropping off the other day. It’s being a bit quirky now but I have a replacement, a SanDisk Cruzer Micro Skin 8GB. This seems like a good time to record how it’s set up as it’s had a lot of tweaks over the last couple of years. I ran with a 256MB thumb drive before that so there’s been quite a bit of expansion in how I use my usb stick. The main thing that’s changed is that it now has exclusively free software on it.

I’ve created three top-level folders: Data, Downloads and Program Files. The only files at the root are a ReturnIfLost.txt, a launch.bat and an AutoRun.inf. As the drive sits on my keyring the ReturnIfLost file has anonymous details in it (and the offer of a small reward)!

xxx@yahoo.co.uk
+44xxxxxxxxxx
20UKP reward for safe return!

The launch.bat is:

@echo off
REM Launch portable apps
cd "Program Files\PStart"
start PStart.exe

The AutoRun.inf is:

[AutoRun]
open=Launch.bat
action=Launch

Obviously, some app called PStart is required. This an extremely useful utility from Pegtop Software that puts a panel into your system tray from which you can launch any of the programs you’ve set up on your thumb drive. Within this panel I’ve created four top-level folders: Development; Internet; OpenOffice and Utilities (which could do with some sub-folders as it runs to over thirty apps now). Where these have ‘Portable’ in their names I’ve removed it as that gets tired, quick.

Development

CassiniWebServer
CSVed
GIMP
Notepad++
NVU
QueryExpress
SQLiteSpy
UPX executable packer

Internet

AM-DeadLink
FileZilla
Firefox
GoogleEarth
Pidgin
ProxyGet
Skype
Tor
utorrent
WinSCP

OpenOffice

(no need to list these, it’s the whole sheebang)

Utilities

7-Zip
Audacity
BonkEnc
CCleaner
DeepBurner
ClamWin
CloneSpy
Driver Magician
Floola
Foxit Reader
FSViewer
GnuCash
KeePass
Launchy
MagicDVDRipper
MD5 check sums
PhotoRec
ProduKey
RemoveDrive
Restoration
ShellMenuView
Stellarium
SyncToy
TestDisk
TightVNC
TrueCrypt
VirtuaWin
VirtualDub
VLC Media Player
WinDirStat
WipeDisk

Also SDelete and PsTools which I just use from the command line. That’s some 600MB of software! The only one of these which isn’t a straight download is Skype where I took the skype.exe from the desktop install, ran it through the UPX executable packer, and dumped it on the thumb drive. It’s 12MB and it’s version 3.0.0.198 but it works fine. It requires the following command line parameters:

/datapath:"Data" /removable

so that folder needs setting up …

All of the above programs are installed to the Program Files directory.

The Data folder has a few sub-folders: Backup; KeePass; misc; music; avatars; pictures; scripts; and work. It also has a .tc TrueCrypt file of approximately 128MB. The TrueCrypt file has a folder structure below it that, once mounted as another drive, can hold anything that should be encrypted. You can also have a Program Files directory here for any programs that may have a lot of write cycles to the flash memory, the advantage being that they will be run exclusively from memory once the TrueCrypt drive is mounted. As it works as a drive you could even have an SVN repository here. In theory I could put everything into a TrueCrypt file but then I’d always need admin rights on a machine before I could use my thumb drive and I’d have to enter that really long, complicated passphrase every time I plugged it in.

The music, pictures and work folders are usually empty, only being used for occasional transport duties. Backup is used almost exclusvely for my FEBE backups to transport Firefox extensions from one machine to another. Downloads tends to have just a couple of small utilities that I want on any machine, like GNotify, and otherwise works as another temporary transport folder.

Posted by: boggin | September 8, 2008

Multiple partitions on a USB key drive

I’m creating multiple partitions on a USB Key (or Flash or Thumb) Drive. Data is shared between partitions and I’ll be able to boot any partition from the drive.

The drive in question is a SanDisk Cruzer Micro Skin 8GB. SanDisk don’t have a utility for flipping the removable bit on the drive and without that XP will not allow the drive to be partitioned. After much reading (the following threads were extremely useful: 911cd.net, msfn.org) and experimenting I’ve finally managed using the Hitachi Microdrive Filter (xpfildrvr1224_320) and adding the correct registry entry to the cfadisk.inf (USBSTOR\Disk&Ven_SanDisk&Prod_Cruzer&Rev_7.01). I then updated the driver (Device Manager > Disk Drives > “USB Drive” > Update Driver) and was able to use Disk Management to create four FAT32 primary partitions.

I used UNetbootin, the Universal Netboot Installer, to install Puppy Linux, UBCD, and Xubuntu. The Portable Apps are described in another blog post. I need to get WinGrub working and then I’ll update this post.

In case you’ve not come across it there’s an extremely useful command line utility in the Visual Studio tools, the XML Schema Definition Tool xsd.exe. It’s particularly important in separating the ‘what’, the system requirements, and the ‘how’, the system architecture.

An example of using it would be defining your application’s FooStatus XSD using Altova’s XMLSpy and then generating your FooStatus class. The class can be generated with the following command line:
C:\>xsd FooStatus.xsd /classes.

This is a painless way of quickly getting a usable business object. The best part of using xsd? The process is completely reversible. If you want to start by generating your class and then create a schema from it you can. Take a look at what else xsd can do for you when you’ve a spare moment – it’ll save you a lot of effort!

Posted by: boggin | July 4, 2008

Robocopy

If you’ve a large piece of un-branched code you’re working on but you can’t check in to source control then you’ll be worried about losing your changes. You need a backup. Here’s a way of mirroring your working copy.
Robocopy came as part of the Windows Server 2003 Resource Kit Tools. Robocopy can perform mirrors of any directory tree and can monitor that tree for changes, mirroring only the changed files. I’ve set up mine as a scheduled task (Run: robocopy /JOB:SVNBACKUP) (cf: Managed File Transfer, RoboCopy, Sheduled Tasks). A useful Microsoft Robocopy GUI for learning the Robocopy switches is available. When you first create the destination directory with robocopy use the /CREATE switch (see the Robocopy Help file) to minimise directory fragmentation.

The following is my current job file:
::
:: Source Directory :
::
/SD:C:\svn\ :: Source Directory.
::
:: Destination Directory :
::
/DD:G:\svn\ :: Destination Directory.
::
:: Exclude These Directories :
::
/XD :: eXclude Directories matching these names
.svn
bin
obj
::
:: Copy options :
::
/S :: copy Subdirectories, but not empty ones.
/E :: copy subdirectories, including Empty ones.
/MON:1 :: MONitor source; run again when more than n changes seen.
/MOT:5 :: MOnitor source; run again in m minutes Time, if changed.
/PURGE :: delete dest files/dirs that no longer exist in source.
/MIR :: MIRror a directory tree (equivalent to /E plus /PURGE).
::
:: Retry Options :
::
/R:10 :: number of Retries on failed copies: default 1 million.
/W:30 :: Wait time between retries: default is 30 seconds.
::
:: Logging Options :
::
/V :: produce Verbose output, showing skipped files.
/NDL :: No Directory List - don't log directory names.
/NFL :: No File List - don't log file names.
/NP :: No Progress - don't display % copied.
/LOG+:C:\Documents and Settings\Placeholder\Application Data\Microsoft Robocopy GUI\Logs\robocopy.log :: output status to LOG file (append to existing log).
/TEE :: output to console window, as well as the log file.

Older Posts »

Categories