Those that know me hear me say often that “I hate computers.” The first time someone hears me say that, their comment is usually “But, you make your living with computers!” I have to politely tell that it doesn’t mean I have to like them.
I was recently working on an issue discovered by our QA tester. We have a feature that allows access to dBase database files. As most programs that provide this access, we utilize the Microsoft Jet Database Engine to perform the heavy lifting. (I know, Jet is on it’s way out, but for now it still works.)
During my development, I tested this feature many times without any problems. Now, our QA tester opens a problem ticket stating that he cannot see any of the database’s columns. I attempt to duplicate it but cannot on my development machine, so I turn to one of my test machines.
Using a few different machines, I find that the issue is not the test file or the version of the operating system. What is strange is that I can get it to work on one machine but cannot on another with the same operating system. What’s worse, is that the error is not throwing an exception so my utility is not displaying anything to the user.
I do manage to finally get the application to throw an exception. What’s strange is that the exception message is “Microsoft jet database engine could not find object ‘xyz.dbf’”. SAY WHAT??? Not possible, the file is RIGHT THERE!!
Next I turn to my favorite tool, the web search. A bit of searching turned up the following interesting text:
3011 – Microsoft jet database engine could not find object ‘xyz.dbf’… Notice the dbf file extension. A dbf file name needs to be in 8.3 DOS name format. It is quite possible that some machines can open the file with a longer file name and others it must be in 8.3 DOS name format.
Now, isn’t that interesting? Long file names have been in existence since Windows 95, but yet the jet database engine doesn’t support them after almost 15 years!
By renaming the file to a DOS 8.3 format name resulted in a successful test on all systems. (Yes, the internal “short” name, the one with the ‘~’, also worked.) What is interesting is that one machine worked just fine with the long file name, but the rest didn’t. If anyone has any input in to why long names work on some systems and not others, I’d appreciate the input.
Recently I was tasked with implementing an automatic build and versioning system for our .NET development project. As part of that process, I needed to come up with a versioning mechanism to place into the process.
The system had to be automatic so that any member of the team could implement it as part of a regular build cycle. Other projects within the company integrate with this project, so distribution builds are a weekly occurrence.
The build environment has been kept simple: Visual Studio 2008 and Subversion. Integration between the two was accomplished by using the ankhsvn Visual Studio plugin. To enable Subversion maintenance from outside of Visual Studio, the TortoiseSVN Explorer shell extension is used.
Due to the numerous builds that occur, it is necessary to integrate a build number into the application version information. The AssemblyVersion and AssemblyFileVersion attributes allow for a four level versioning system. Having four levels would allow us to simply add the build number to the end of our existing standard three-level version system (Major.Minor.ServicePack).
The only issue was how to come up with a build number that would be meaningful. Visual Studio has an option to replace the third and fourth levels with values that are hacks of the date and time of the build. However, this option resulted in the removal of the Service Pack number from our version number, which was not acceptable.
Back in Visual Basic 6, there was a build option that auto-incremented the last value in the version each time the output was built. That feature was not available in the C/C++ versions of Visual Studio and was not brought forward to the .NET versions. Although an auto-incrementing value allows for determining which build is newer, it provides for not much else.
During my research, I came across a blog post where the author was utilizing the latest subversion revision as the build number. This allowed for a build to be directly connected to point in the subversion repository. However, this author’s instructions were utilizing MSBuild, which we were not.
The plan was to implement the following versioning scheme: Major.Minor.ServicePack.Build. The major, minor and service pack values would be specified manually and the build value would be generated automatically as part of the build process.
Coming up with the versioning scheme was only half of the work. The other half, and arguably the hardest half, was to come up with the actual implementation. The challenge was to determmine what tools would be needed to accomplish the task. The tools would have to be lightweight and easy to use.
I decided to utilize Windows PowerShell to accomplish the task. Not only could it be used for automating the build process, but it could also be used to perform automated tests on our .NET classes. PowerShell utilizes the .NET framework classes, so any task that we can accomplish in a .NET application could be accomplished in a PowerShell script.
To allow access to the Subversion repository, a command-line SVN client would be needed. I chose the SlikSVN client available from the Subversion client page. It comes with a Microsoft MSI installation package and was easily distributed to other team members.
Before diving into the PowerShell script, some work had to be done to make the job easier and more efficient. Each project has its own AssemblyInfo.cs file. Since our procedure would only update the build number, this would mean that each AssemblyInfo.cs file would have to be updated with the major, minor and service pack numbers. As the number of projects grows, this task becomes more prone to error.
To solve this issue, the AssemblyInfo.cs file would be split into two files. The first file, AssemblyVersionInfo.cs, would contain the company, product, copyright and version information. The second, AssemblyInfo.cs, would contain the remaining attributes. AssemblyVersionInfo.cs would be a single file that would be shared by all projects, whereas AssemblyInfo.cs would be located in each project’s directory.
By placing all version information into a single file, this reduces the modifications needed by the development team when a version changes. It also allows the PowerShell script to simply modify a single file rather than having to search through each project directory.
The first step in the process is to obtain the value of the latest Subversion revision. Alejandro Espinoza wrote a little PowerShell script that accomplished this task. With a bit of simplification for my use, here’s the result:
| powershell | | copy code | | ? |
| 01 | function GetLatestRevisionNumber() |
| 02 | {
|
| 03 | $revLinePattern = "(.*?)(Revision: )(\d+\.?\d*)(.*?)"; |
| 04 | |
| 05 | $result = svn info . |
| 06 | |
| 07 | $revision = 0; |
| 08 | |
| 09 | if([regex]::Match($result, $revLinePattern)) {
|
| 10 | $matches = [regex]::Split($result,$revLinePattern); |
| 11 | $revision = $matches[3]; |
| 12 | } |
| 13 | |
| 14 | return [int]$revision; |
| 15 | } |
This PowerShell function calls ‘svn info’ to get the Subversion repository information for the current directory. Then it locates the line with ‘Revision’, pulls out the value and returns it to the caller.
Now that the latest revision value is obtained, we need to take that value and update the AssemblyVersionInfo.cs file. However, there are two issues that need to be addressed when doing so:
To address issue #1, the script will need to compare the updated value with the value that exists in the file. The file will only be updated if the value has changed.
To address issue #2, the revision level obtained above will be incremented before writing it to the file. Otherwise, the file will be updated each time the script is run. By incrementing the value, the value written to the file will match the level when the file is copied back into the respository after the update.
The PowerShell script to perform the update is quite simple:
| powershell | | copy code | | ? |
| 01 | function UpdateAssemblyVersion() |
| 02 | {
|
| 03 | $currRevision = GetLatestRevisionNumber; |
| 04 | $nextRevision = [int]$currRevision + 1; |
| 05 | $versionPattern = '(?<major>\d+)\.(?<minor>\d+)\.(?<sp>\d+)\.\d+'; |
| 06 | $hasChanged = 0; |
| 07 | |
| 08 | $assemblyFileData = Get-Content Common\AssemblyVersionInfo.cs; |
| 09 | |
| 10 | for($line=0; $line -lt $assemblyFileData.Length; $line++) |
| 11 | {
|
| 12 | $newLine = [regex]::Replace($assemblyFileData[$line], |
| 13 | $versionPattern, |
| 14 | "`${major}.`${minor}.`${sp}." +
|
| 15 | $currRevision); |
| 16 | if($newLine.CompareTo($assemblyFileData[$line]) -ne 0) |
| 17 | {
|
| 18 | $hasChanged = 1; |
| 19 | $newLine = [regex]::Replace($assemblyFileData[$line], |
| 20 | $versionPattern, |
| 21 | "`${major}.`${minor}.`${sp}." +
|
| 22 | $nextRevision); |
| 23 | $currRevision = $nextRevision; |
| 24 | $assemblyFileData[$line] = $newLine; |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | if($hasChanged -eq 1) |
| 29 | {
|
| 30 | write-host "Updating AssemblyVersionInfo.cs to version " $nextRevision "."; |
| 31 | Set-Content Common\AssemblyVersionInfo.cs $assemblyFileData; |
| 32 | svn commit Common -m `"Version change for build.`" |
| 33 | } |
| 34 | } |
These PowerShell functions are simply two steps in the entire build automation process. When placed between a Subversion update and a Visual Studio compile, they provide an automated method for integrating meaningful build numbers into your .NET assemblies.

Categories
Tag Cloud
Blog RSS
Comments RSS
Last 50 Posts
Back
Void « Default
Life
Earth
Wind
Water
Fire
Light 