Scott Hanselman

Example: How to contribute a patch to an Open Source Project like DasBlog

August 02, 2006 Comment on this post [15] Posted in ASP.NET | DasBlog | Programming
Sponsored By

Lots of discussion going on around the death of NDoc and Open Source as a viable option for .NET projects. A lot of this harkens back to some of the things discussed in "Is Open Source a Crap Idea" from a a few months back.

  • I said Open Source is free like a Puppy. It requires care, feeding, and in the words of Pete Seale, if you beat it it will run away.
  • Phil says Open Source is free like a Flower. "I think of Open Source software as being like a nice set of flowers in a common space such as a courtyard. Nobody that lives around the common space owns the flowers, yet they all enjoy the presence of the flowers."
  • Jeff says Open Source is free as in Free. "The highest compliment you can pay any piece of open source software is to simply use it, because it's worth using."

From my point of view, just USING Open Source software doesn't fix bugs. Volunteers fix bugs, whether they are a member of the project or not. (Assuming you haven't got an Open Source Sugar Daddy or a company that supports your work.)

All that is required for Evil to succeed is that Good Men [and Women] do nothing.

If you have the power to fix a bug (or at least get the fix started), especially in software you're using, why not make THAT your contribution?

Jeff says:

Fine. Create a new blog entry. Walk us through, step by step, the process for contributing a fix to DasBlog. List EVERY step, starting with finding a bug.

If it's that easy, prove it.
Jeff Atwood on August 2, 2006 09:40 AM

Kind of a sassy tone that, Jeff ;) but here you go.

Note, the bug might be one line, a single char, or quite involved. It all depends. The point is, any help you can give an Open Source dev, no matter how little is a good thing. If you can give them a line number and an idea, that's contributing. Here's an ideal (and real) bug report that stops just short of including the fix. We'll fix it and submit the patch.

How to fix a bug in an Open Source Project
(Or at least one that uses Subversion or CVS and is hosted at SourceForge)

Get the Project

Install TortoiseSVN and/or TortoiseCVS, depending on which source control system the Open Source Project is using. They both work about the same, integrating into Explorer.

Make a new folder, right-click, select Checkout.

Opensource1

Enter the URL of the Source Repository and click OK. In this example, the project at Source Forge is called "dasblogce" and we are getting the "trunk" so the URL is https://svn.sourceforge.net/svnroot/dasblogce/trunk. This is how folks are getting the very latest "bleeding edge" versions of DasBlog, since we haven't released in a while.

Opensource2

Build the Project

Every project is a little different, but most have a build file, readme or some detail that says how to get started.

Assuming you have IIS installed, to build DasBlog, run the CreateDasBlogVdir.vbs file in the tools folder to make the IIS Virtual Directory for your local copy.

Open up DasBlog All.sln in Visual Studio 2003 and build. Your virtual directory is mapped to <projectdir>\newtelligence.DasBlog.Web and your binaries - since this is a web application - are in the <projectdir>\newtelligence.DasBlog.Web\bin folder.

Example: Find a Bug

So perhaps you've found a bug. Maybe you got the Yellow Screen of Death. You likely have a stack trace or a strange bit of behavior.

Most projects at SourceForge have a home page like http://sourceforge.net/projects/dasblogce. Visit ours and click the Bugs menu item. Pick one, or see if the bug you've found has already been reported.

For example, George V. Reilly reports in Bug 1397557 that our "content filter" feature for making words link as Google Searches doesn't work well. He writes:

[The Content Filter] $g(multiple words) should produce
<a href="
http://www.google.com/search?q=multiple+words">
multiple words</a>. In other words, the spaces should
be URL encoded as pluses in the URL.

I spent some time looking into a fix. It doesn't seem
to be possible with a regex. See the thread I started at
http://regexadvice.com/forums/14513/ShowPost.aspx

My suggested fix.
$g(expr) ->
<a href="
http://www.google.com/search?q=$h(${expr})">
${expr}</a>
where $h is a new kind of content filter, one that uses
a builtin function to URL encode the string.

Here he is kind enough to suggest the desired behavior. As you may have found the bug or undesirable behavior, you may have an opinion as to how to fix it.

Example: Fixing the Bug

So since this bug involves DasBlog's content filter feature, I'll search the project for "ContentFilter" using Ctrl-Shift-F (Find in Files).

Opensource4

Looking at my search, "ApplyContentFilters" looks promising in Utilities line 645.

As George points out in the bug report, we want to UrlEncoded the result, but we don't want to UrlEncode all results. Just some.

He also helpfully points me to a post on a RegularExpressions forum where he tried to get the bug fixed using pure Regex. It doesn't appear possible with just RegEx, so we'll use a System.Text.RegularExpressions.MatchEvalulator like the post suggested. He also recommends a new kind of Content Filter that would UrlEncode. In this case, it'll be necessary because we want to do this:

$g(The Quick Brown Fox)

into

<a href="http://www.google.com/search?q=The+Quick+Brown+Fox">The Quick Brown Fox</a>

Note that if we did a blanket UrlEncode on the first string, we'd get + signs in our linked text.

So, we'll take his suggestion. Here's the code for a new ApplyContentFilters function with our changes in red.

Remember, we will be submitting our changes as a DIFF file for the developers/commmiters/admins to check in, as we're assuming we don't have source 'commit' access.

private static string CustomUrlEncodingRegexReplacer(Match m)

{

    // Remove the $<char>() from around the string and encode the result.

    if (m.Value.Length < 4) throw new ArgumentOutOfRangeException("Match",m.Value,"UrlEncoded Content Filters should be in the format $u() where 'u' is any single character. Match strings must be at least 4 characters long.");

    string trimmed = m.Value.Substring(3,m.Value.Length-4);

    return HttpUtility.UrlEncode(trimmed);

}

 

public static string ApplyContentFilters( SiteConfig siteConfig, string content )

{

    if ( content == null ){return String.Empty;}

 

    foreach ( ContentFilter filter in siteConfig.ContentFilters )

    {

        if ( filter.IsRegEx )

        {

            try

            {

                if(filter.UrlEncode)

                {

                    content = Regex.Replace(content, filter.Expression, new MatchEvaluator(CustomUrlEncodingRegexReplacer), RegexOptions.Singleline);

                }

                content = Regex.Replace(content, filter.Expression,filter.MapTo,RegexOptions.Singleline);

            }

            catch

            {

            }

        }

        else

        {

            content = content.Replace( filter.Expression, filter.MapTo );

        }

    }

    return content;

}

And we'll add our new Content Filter as George suggested to the XML settings file. (Note: we don't need to edit the XML directly, we'll change the editor page in a moment)

Again, changes in red.

  <ContentFilters>
    <ContentFilter find="\$g\((?&lt;expr&gt;[\w\s\d]+)\)" replace="&lt;a href=&quot;http://www.google.com/search?q=$u(${expr})&quot;&gt;${expr}&lt;/a&gt;" isregex="true"/>
    <ContentFilter find="\$u\((?&lt;expr&gt;[\w\s\d]+)\)" replace="${expr}" isregex="true" urlencode="true"/>
...snip other filters...
  </ContentFilters>

So now after our Google filter (or dictionary filter, or any of the dozens of filters that folks use) runs, we'll be able to UrlEncode arbitrary parts of the result.

Now we'll add UrlEncode as an option to the ContentFilters object. We'll make false the default so we don't break our public interface as we don't want to break existing code or change existing behavior.

Opensource4

Content Filters don't have to be edited in the XML file directly, they are managed by a rich UI. We'll want to extend the UI quickly.

On the EditContentFilters page, I'll add a new column to allow us to edit this new option in "EditContentFilters" by copy-pasting from another column.

Opensource5

I also do copy paste of the code to update the config file by using the existing "IsRegEx" example. It's a true/false checkbox-style option, just like the new one we're adding.

Here's a test of the results. Note the + in the URL in the Status Bar.

Opensource6

Making the Patch

Now that we think the bug is fixed, we want to make a patch/diff file that will allow the developer(s) to apply easily so they can consider our patch for committing to the project. We don't want to email them a zip of our project directory. That would mean they'd have to manually diff each file and that's a hassle. Remember the goal here is easy on everyone's part. We don't want to bust our asses sending in the patch and we don't want to stress them out by sending 4 megs of code when we only changed 10 lines.

Now I'll right click in the main folder of my project in Explorer and click Create Patch.

Opensource7

From the Create Patch window I will select the files I changed:

Opensource8

In this example, it was only four files. I'll save the unified diff/patch as "contentfilterchange.patch"

Opensource9

If I look inside the patch file with Notepad2 (with it's lovely diff/patch syntax highlighting) I'll see just my few changes with deletes and adds highlighted.

Opensource10

Now, we'll log back into SourceForge and upload and attach our patch to the bug.

Opensource11

Conclusion

We've just downloaded source to an Open Source application, built it, found a bug, fixed the bug, and submitted a patch to an Open Source Project that we were not committing members of. 

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service
August 03, 2006 0:48
Well, you still have to have programming knowledge and I agree with Jeff on that part. Just by using it and telling your friends about it, you're helping too
August 03, 2006 1:15
Very nice tutorial Scott! And now where can we donate $5 to you?
August 03, 2006 1:18
This post itself already qualifies as helping the cause. Most of the Open Source software I use is for software development, so a large part of their user base can is are potential candidates for the above type of help. Even if you don't have programming skills there are tasks like documentation and site administration that could use some help too.
August 03, 2006 1:43
Simply Excellent !!

I´ll be linking to this post in the "How to help in the Development" link of my project. There is a lot of people that helps to fix bugs or add functionality but them send all the project back and now thanks to you I can said them how to send the changes.

Perfect step by step guide, THANKS A LOT !!!
August 03, 2006 1:44
Excellent post. This whole NDoc fiasco has really motivated me to start looking for existing open source projects I use and can contribute to.

BTW, I notice you're using Notepad2. I used that for a long time before I found Notepad++, which is like 900 million times cooler than Notepad2. Not only does is it just as fast as Notepad2, it contains a bunch of filetypes (and an editor to define your own, including keywords, folding keywords, etc), has plugins (cool ones like HTMLTidy integration), and a macro recorder. Oh. And a tabbed interface.

And it's open source. ;-)
August 03, 2006 1:44
Great work!

> Kind of a sassy tone that, Jeff ;)

Well that is where he derives all that sex appeal. Rowr!
August 03, 2006 1:45
Oh yeah...Notepad++...I suppose you could google it, but I could also make it really easy for you to find the thing:

http://notepad-plus.sourceforge.net/uk/site.htm
August 03, 2006 1:51
Thank you for show how easy is to contribute to an Open Source Project. Most of the time we are only a bunch of good desires but not always have the real initiative to share a bit (or a bunch) of our time.
August 03, 2006 3:15
"If it's that easy, prove it"

I think you may have just done that ;-)

nice job!
Ian
August 03, 2006 4:08
Great post. I really think more open source projects should post (or link to) this type of information. Coupled with a "Developer's Guide" document that covers the project "philosophy", code standards, testing strategy, etc, it really lowers the barrier to entry for contributions.

It was your original post on this topic (http://www.hanselman.com/blog/UsingAWindowsVersionOfGNUPatchexeWithCVSAndDiffFiles.aspx) that helped me get over my unwarranted fear of CVS and inspired me to start contributing to DasBlog.
August 03, 2006 19:03
Very nice, Scott. This is a great intro into the mechanics of the process. But, but ... does svn.sourceforge.net support the notion of contributors creating branches? If so, might it be better for contributors to commit the bug fix on "task" branch instead? This allows the project owners to simply do an "svn merge" into the trunk to accept the changes. While patch files are elegant, it is not very subversion-y.
August 03, 2006 19:59
Great post man, and the perfect response!
August 03, 2006 22:45
Notepad++ is the bomb.

Hey, does anybody but me ever wonder when friendly antagonism between Scott and Jeff is going to escalate an all-out brawl?

I got $20 on Scott. The small, scrappy guys are dangerous. :)
August 07, 2006 3:48
Great article! This is just what I needed! Thanks.
August 27, 2006 16:13
Hi Scott,

When grabbing the source and opening the project, I came across one of my old Visual Studio favourites "Unable to retrieve folder information for the project".

I think it would be worth adding a note about this (and the need for the ASP.NET hack which does not install by default with TortoiseSVN) as it may frustrate all these eager DasBlog beavers!

Thanks for the post.

Ben
Ben

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.