 |
|
 |
 |
Thursday, August 16, 2007 |
In my previous post FastCGI in IIS7 I mentioned that I am running WebSVN on this box to give FastCGI a real-world test run. Today, I upgraded to v2.0 of WebSVN. They sure do ship a good-looking template this time around:

The RSS functionality is enabled too in this version (I was running code directly from their repository last time around...). I have to say that WebSVN turned into a must-have tool for anyone using Subversion.
Link to WebSVN on iis7.chrison.net (feel free to play around)
 |
Friday, January 19, 2007 |
I just gave StatSVN a try, which compiles statistics for Subversion repositories. For my trial, I used the 2.1 branch of SharpDevelop - which, because only created a month ago - should create a small and manageable statistic to start out with.
What do you need to get up and running with StatSVN (except, of course, StatSVN itself)? Well, the Subversion command line client (get it here), as well as Java. Working with StatSVN is really easy - simply follow the steps outlined in the readme and you can't go wrong - it even works nicely on Windows Vista.
If you don't want to install StatSVN on your box just to see how a report might look like for a real-world project, I have packaged the report generated for our SharpDevelop 2.1 branch:
DemoReport.zip (1.27 MB)
Before looking at the report, check out the LOC and churn rate I have posted below:

This branch was created from /trunk to only contain bug fixes from Beta 2 to release candidates and RTW. That's why there are spikes of activity, with no activity at other days. Also, not all developers are working on the branch, many are concentrating on developing features for the new version which lives in /trunk.
 |
Thursday, December 28, 2006 |
 |
Tuesday, September 19, 2006 |
Beta 1 of SharpDevelop2 2.1 is available for download. While I was putting together the annoucement for v2.1 yesterday, I realized that for a point release, we really managed to put in a lot of new cool features:
A couple of WOW features (for me, at least): Not only can you compile an application for different versions of .NET, you also get version-specific code completion support. Another cool one is that you can host SharpDevelop in your application, providing your application a "macro editor" (on steroids I might add) with full .NET support. And to pick a third, code analysis rounds out our professional offering in addition to code coverage as well as unit testing.
Two features did not make it for the Beta 1 announcement as they don't yet cover all the scenarios we are hoping for: integrated Subversion support (yeah!) and targetting the Compact Framework for Windows CE devices. Those slipped silently into this release.
As you can see, SharpDevelop is ever growing and the developers working on it can be rightly proud of their achievements!
Finally, a kind of "call to action": let us know what you think! Not only in our forums, but also in your blogs, communities, et cetera. We need your feedback regarding feature set, stability, and much more.
 |
Monday, September 11, 2006 |
Subversion 1.4 is available. The especially good news? Svnserve can now be run as a native Windows service (more).
 |
Monday, June 05, 2006 |
The concept of shelving was made popular by Visual Studio Team System's source control system - it allows you to "shelve" your changes for a couple reasons, like:
- You have to work on a bug fix immediately, but you are in the middle of implementing a new feature. You cannot check in those half-baked changes, only the bug fix. So you shelve your feature work. Once done with the bug fix, you unshelve the feature work and continue.
- Sharing work. Another developer needs the changes you are currently working on, but you are not yet done. So you shelve your changes and the other dev unshelves them and can get productive immediately.
- Code review. Instead of having someone come over to your office (or worse, email the files) to review the changes before checkin, you shelve them and the reviewer can unshelve them.
- Backup. How many times do you leave your workplace with a feature not yet completed? What to do with this build-breaking half-baked work? Shelve it!
Now you get the idea why shelving is pretty neat. Even Subversion does support the concept although it is not explicitly there: the blog posts Shelving in Subversion and Shelving Subversion show how you can make shelving happen with Subversion.
 |
Friday, October 14, 2005 |
Remember my call to action in Web applications and SMTP proxies don't mix well (it seems)? I mentioned that I am guilty as well - not only for Web applications as it turned out, but also for other server-based software, such as the Subversion post-commit hook I wrote.
You can already guess the contents of the change log (the last public version was 1.7):
- SMTP authentication & SMTP server port options added
If you are running the hook today, all you need to do is copy the new post-commit.exe over your existing one (assuming you use 1.7), and add the following four lines to your post-commit.exe.config's <appSettings> section: <add key="SMTPAuthentication" value="" /> <add key="SMTPServerPort" value="25" /> <add key="SMTPUsername" value="username" /> <add key="SMTPPassword" value="password" />
Those values default post-commit.exe to the 1.7 behavior. To use authentication, set SMTPAuthentication to BASIC, and provide username and password. Most of the time, you will not need to play with the server port.
Finally, here is the usual binary & source code archive:
SvnPostCommitHook1.8.0.51014.zip (424.24 KB)
 |
Tuesday, August 23, 2005 |
I admit that I am not the sort of person who likes to go through long and winded installation instructions. However, I am willing to go to great lengths when it comes to security - still with certain limits though. And I hit such a brick wall today: trying to secure Subversion. From the documentation, I knew that the recommended path was SSH, so I set out to find out how to get this up and running on my Windows box.
Owning the black sock in Google fu, I came up with various articles, the most helpful being SVN+SSH+public key authentication on Windows Box as server. Most helpful because after reading the aforementioned recipe plus Subversion / TortoiseSVN SSH HowTo, I decided to scratch my efforts. Why?
For starters, I am not a big fan of Cygwin. That's just personal mischief of a Windows guy, I can swallow my pride when the tools that depend on it provide merit. What's more of a problem for me is installing a service for adding security to another service - especially if I need that new service just for the "security purpose", and not the other bells and whistles it can provide (plus the security issues that might be hidden in those unused parts). Call me paranoid, but I simply like to reduce "moving parts" in my setups, because: What's worse than malicious traffic? Right, encrypted malicious traffic.
Secondly, do you think - honestly - that developers love to jump through hoops to get access to the repository? (I am referring to the client side of things on Windows) Not really. From the top of my head, I fall short of naming a single developer I personally know that would love to follow those steps. But every single one of them would be more than willing to just replace svn:// for svns:// when accessing a repository.
Conclusion: yes, I am whining about the usability of an open source project. As I am participating on one myself, you very well can spare me the "usual" arguments of do-it-yourself-because-the-sourcecode-is-available-anyways. This is a rant. I want to be unreasonable. But it sure would be nice if security was in the box. Especially nowadays.
 |
Wednesday, August 10, 2005 |
This was a longer-planned upgrade to our Subversion server that happened today: moving from the 1.1 series to 1.2.1. It went smoothly, especially because I played it safe by doing a dump / load cycle (more details to be found in Migrating a Repository) with all repositories. Safety wasn't the only concern: as detailed in the release notes, I also wanted to move the repositories to a FSFS back end, and take advantage of xdelta compression. I was mostly after server-side features, I don't see many of our devs use the optional locking...
 |
Monday, August 08, 2005 |
I finally got around to make a new version of SvnPostCommitHook. For one, it was about time to include Ben's changes, and secondly I wanted to roll a new version onto our Subversion box - it was still running on v1.3. So much for dogfooding...
With that, here is the change log. Note that the last public version was 1.5:
8/8/2005 - 1.7, Changes by Christoph Wille
- LookInfo getter logs when _lookinfo is null
- MailTextOnly & AppendDiffToMail properties added to .config file (text-only currently does not send diffs anyways)
- UU case added to svnlook parser
- Change SvnLookOutputParser.SkipBlanks method to return bool if StringCollection hasMoreLines
5/14/2005 - 1.6, Changes by Ben Lowery, ben AT blowery DOT org
- <pre> blocks for code#
- Updates CSS for new HTML
- Logic for finding CSS updated
- More logging
And here is the usual binary & source code archive: SvnPostCommitHook1.7.zip (420.75 KB)
 |
Wednesday, July 27, 2005 |
This post is again motivated by last week's Community Bootcamp on ASP.NET 2.0, the CBC05. I presented "Under the Covers - Exploring Internals, Page Lifecycle and the Compilation Mode" from TechEd, using the samples that Simon Calvert provided me with (special thanks fly out to Simon, Ben Miller and Rich Ersek @MS for providing us with material - I know I can be a royal pain in the posterior... sometimes at least).
The talk included a demo of a database-backed virtual path provider (files don't come from the file system but a database, dynamically). Somehow we started talking about how cool it would be if you could test your Web sites without checking them out from source control in the first place - by simply writing a virtual path provider that goes to the repository on demand. I wrote that idea down.
Actually, I didn't think I'd get around to doing that. But yesterday I decided to pester one of my devs on the #develop project, namely Daniel Grunwald. He has implemented the Subversion addin for our 2.0 version, so he had experience with NSvn, the managed API for talking to Subversion. I sent a stripped down version of the vpath provider to him, and asked him to replace database code with NSvn code where appropriate.
It didn't take long, and I had a command-line verified version back, and all I had to do was make sure that it works with ASP.NET 2.0. There were a few problems I ran into (like Subversion is case-sensitive and I didn't want that for the Web scenario). Some of the issues arose simply because client and Web developers have different backgrounds. Talk about path separators. Or directories where you have to drop assemblies.
Now, let's stop talking, let's take a look at the provider in action:
SvnVPathProvider.wmv (3.76 MB)
Want to get your hands on that DemoSiteSvn directory with the current rendition of the SubversionVirtualPathProvider? No problem, just a couple of notes up front on what you should be aware of:
- Only file names are currently treated specially for casing. Ie directories still do react in a case sensitive way.
- The file name cracking code needs to be reviewed. Currently, this is a quick hack.
- appSettings need to be placed in a separate .config file. Reason is that web.config cannot be obtained via a VirtualPathProvider, and thus this file has to be checked out separately. And I don't want to get in the way of automating this by requiring entries in web.config.
- Package it as an assembly, so only the \bin folder needs to be copied to get up and running.
- The VirtualPathProvider requires (at the very least) anonymous access to the repository. Passing security tokens is not implemented.
With those notes out of the way, thanks fly out to the ASP.NET team for providing me with the sample of their virtual path provider in the first place. It has been a tremendous help to get this thing off the ground. And maybe in turn this sample will help others to get started:
SvnVppDemo.zip (972.37 KB)
Installation note: the two DLLs in the system32 folder need to be dropped in the respective folder of your system. Do not place them into \bin. Unless you want to get into trouble, that is.
What is left to say? Oh, the source code, of course! I thought you might be interested in reading it online instead of having to download an almost 1MB-size file first. Here it is (App_Code\SubversionVirtualPathProvider.cs):
using System; using System.IO; using System.Collections; using System.Globalization; using System.Configuration; using System.Text; using System.Web; using System.Web.Util; using System.Web.Hosting; using System.Web.Caching; using NSvn.Core; using NSvn.Common;
namespace ICSharpCode.Web.Providers { public class SubversionVirtualPathProvider : VirtualPathProvider { #region class HashCodeCombiner internal sealed class HashCodeCombiner { // Start with a seed private long _combinedHash = 5381; internal void AddLong(long l) { _combinedHash = ((_combinedHash << 5) + _combinedHash) ^ l; } internal string CombinedHashString { get { return _combinedHash.ToString("x", CultureInfo.InvariantCulture); } } } #endregion
#region class SubversionVirtualFile internal class SubversionVirtualFile : VirtualFile { string fullPath; DirectoryEntry entry; public SubversionVirtualFile(string virtualPath, string fullPath, DirectoryEntry entry) : base(virtualPath) { this.fullPath = fullPath; this.entry = entry; } public override bool IsDirectory { get { return entry.NodeKind == NodeKind.Directory; } } public override Stream concat() { Client client = new Client(); MemoryStream ms = new MemoryStream(); client.Cat(ms, fullPath, Revision.Head);
// .Cat closes the stream, so we have to copy it MemoryStream ms2 = new MemoryStream(ms.GetBuffer()); ms2.Position = 0; return ms2; } } #endregion
public static void AppInitialize() { SubversionVirtualPathProvider provider = new SubversionVirtualPathProvider(); HostingEnvironment.RegisterVirtualPathProvider(provider); } string GetSvnFullpath(string virtualPath) { if (bool.Parse(ConfigurationManager.AppSettings["svnvppStripVdir"])) { // this will break root Webs, StripVdir should be the default however int pos = virtualPath.IndexOf('/', 1); virtualPath = virtualPath.Substring(pos, virtualPath.Length - pos); }
return ConfigurationManager.AppSettings["svnvppRepositoryUrl"] + virtualPath; }
string GetSvnFullpath(string virtualPath, string fileName) { return FixupSvnFullpath(GetSvnFullpath(virtualPath), fileName); }
// Subversion is case sensitive, this we switch the filename here string FixupSvnFullpath(string svnPath, string fileName) { int pos = svnPath.LastIndexOf('/'); string parentDirectory = svnPath.Substring(0, pos + 1); return parentDirectory + fileName; } DirectoryEntry GetEntry(string virtualPath) { Client svnClient = new Client(); string fullPath = GetSvnFullpath(virtualPath); int pos = fullPath.LastIndexOf('/'); string parentDirectory = fullPath.Substring(0, pos); string entryName = fullPath.Substring(pos + 1);
try { DirectoryEntry[] entries = svnClient.List(parentDirectory, Revision.Head, false); foreach (DirectoryEntry entry in entries) { if (0 == String.Compare(entry.Path, entryName, true)) return entry; }
return null; } catch (SvnClientException ex) { if (ex.ErrorCode == 160013) // parent directory not found return null;
throw; } } public override bool FileExists(string virtualPath) { DirectoryEntry e = GetEntry(virtualPath); if (e != null) return e.NodeKind == NodeKind.File;
return Previous.FileExists(virtualPath); } public override bool DirectoryExists(string virtualDir) { DirectoryEntry e = GetEntry(virtualDir); if (e != null) return e.NodeKind == NodeKind.Directory; return Previous.FileExists(virtualDir); } // Obtain the file. This will only be called if the hash that we return is // different than that the runtime holds on to as a cached indicator. public override VirtualFile GetFile(string virtualPath) { DirectoryEntry e = GetEntry(virtualPath); if (e != null) return new SubversionVirtualFile(virtualPath, GetSvnFullpath(virtualPath, e.Path), e); // Default to the previous implementation return Previous.GetFile(virtualPath); } /// /////////////////////////////////////////////////////////////// /// Return a hash value indicating a key to test this file and dependencies have not been /// modified public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) { HashCodeCombiner hashCodeCombiner = new HashCodeCombiner(); ArrayList unrecognizedDependencies = new ArrayList(); foreach (string virtualDependency in virtualPathDependencies) { DirectoryEntry e = GetEntry(virtualDependency); if (e != null) { hashCodeCombiner.AddLong(e.Size); hashCodeCombiner.AddLong(e.CreatedRevision); } else { unrecognizedDependencies.Add(unrecognizedDependencies); } } string result = hashCodeCombiner.CombinedHashString; if (unrecognizedDependencies.Count > 0) { result += Previous.GetFileHash(virtualPath, unrecognizedDependencies); } return result; } /// /////////////////////////////////////////////////////////////// /// The cache dependency is a specialized object that means that the runtime /// can perform file monitoring and change notifications directly   |