in

CodePrairie .NET

South Dakota .NET User Group

chrisortman

  • How do you manage your open source software

    I have several projects all using a combination of open source software.

    Castle

    NHibernate

    Rhino

    MbUnit

    log4net

    Are the first ones that come to mind.

    In some of these cases I am always running off the trunk which means I am building everything myself. This can get pretty complex to manage, especially when the code changes frequently. I'd like to hear from you how you are dealing with some of these issues.

    How do you handle updates?

    How do you manage your own changes?

    How do you integrate it with your build process.

  • ReSharper 4 nightly builds coming soon!

    So excited am I, here's the announcement from Ilya Ryzhenkov. The full thread is here

     

    Hi,
    Here is updated information about ReSharper 4 public availability.
    1. Nightly builds are planned to start publishing tomorrow (in about 24 hours),
    when it will be February 15 evening here. Our apologizes to those who live
    ahead of our time :)
    It may very well happen that we delay public builds if we find critical problem
    in our product. We hope you understand. We won't delay it "just in case".
    2. No stable EAP builds in near future. We have to do a lot before we begin
    stabilization phase. However, we use current development builds all the time,
    so any critical problem will most likely be fixed within a day or two. After
    all, we are going to open public builds because YOU asked for it :)
    3. If you are going to download nightly builds, it is HIGHLY recommended
    to register in our JIRA issue tracker. We will ask for additional information
    for exceptions and problems reported, so we want to talk to someone other
    than Mr. Anonymous. Actually, we usually just ignore anonymous exceptions,
    if they are not plain obvious, because it is almost impossible to reproduce
    them without additional information. When you complete your registration
    in JIRA, please include your credentials in ReSharper exception submission
    dialog.
    You can read more about our issue tracking policy here: http://www.jetbrains.net/confluence/display/ReSharper/ReSharper+Issue+Tracker
    4. Information about what to look for in ReSharper 4 and what features are
    ready or not will be available simultaneously with first public build.
    Thank you for your interest in ReSharper 4!
    Sincerely,
    Ilya Ryzhenkov
    JetBrains, Inc
    http://www.jetbrains.com
    "Develop with pleasure!"

  • Why frequent commits are important

    Something I have noticed has changed about the way I work now that I use git instead of subversion is that I make a lot more commits.

    Let's say that in order to add feature X I need to make the following changes

    Add migration
    Add ActiveRecord model Foo
    Add PersistanceTests for model
    Write Tests for feature X
    Rename an existing class
    Change the way some other model class works
    implement some behavior in Foo
    Ensure that tests pass

    In a lot of code I've seen all these changes would be grouped into a single SVN commit

    svn commit -m "Implemented feature X"

    But when that is the case a lot of information gets lost about how feature X got implemented.

    I think that each of those changes should be their own commit with their own explanation. Centralized version control doesn't help this though because I would get impatient with making 3 minutes worth of changes and waiting 30 seconds to make the commit. I also think that pushing each change out to everyone else before the whole feature is ready would be a bad thing.

    Using a DVCS (such as git) it is painless to do this. The commits are fast, and I just because I commit doesn't mean I need to share. I also have the freedom to go back and rewrite history if I realize while I'm implementing some behavior in Foo that I forgot a column that should have been part of my initial migration.

  • Why I <3 git rebase

    I recently started adding a new feature to one of my projects. The first thing I typically do in this scenario:

    git checkout -b name-of-feature current-version (replacing name-of-feature and current-version appropriately)

    Now as I'm working on this I may bump into something that if I were to refactor would make this new feature a lot a lot simpler to implement.

    If I were using only subversion and I started on this refactoring I would have a source history that looks something like:

    Added migration for table x

    Created new models + tests for feature X

    Renamed class foo to bar

    Refactored some service into separate services

    next change for feature x

    fixed bug 370 reported by QA

    another change for feature X

     

    Which isn't bad persay, but it would be better if things were in their proper order. I also don't like that I would have to commit some incomplete implementation of feature X just to fix a bug. If I had a little better foresight and planning I might have fixed the bug first, then done that refactoring that will make feature X simpler then actually implemented feature X. Fortunately git makes this pretty easy to do.

    Here's what my output of git branch might be:
    v1.2
    add-feature-x
    refactor-some-service
    fix-bug-370

    v1.2
           |
            -------add-feature-x
                                          |
                                           ---------refactor-some-service-----
                                                                                         |
                                                                                          ----fix-bug-370

    In my graph here a - represents a commit and | a branch point
    What this says is that I started adding feature x, did some refactoring, stopped to fix a bug and continued my refactoring after.

    Just because things happened in this order is no reason that history must say they did. I guess I like the Back to the Future theory of time travel better than Terminator.

    Since I haven't shared these changes yet, I can fix up my history.

    git co fix-bug-370
    git rebase v1.2

    I now have

     

    v1.2
           |
            -------add-feature-x
           |                             |
           |                              ---------refactor-some-service-----
           |------fix-bug-370

     

    And a couple more times:

    git co refactor-some-service
    git rebase fix-bug-370
    git co add-feature-x
    git rebase refactor-some-service

    So that I now have                                                                           

     

    v1.2
           |
            -------fix-bug-370
                                      |
                                       ---------refactor-some-service-----
                                                                                          |
                                                                                          ---- add-feature-x

    Which when I eventually do

    git co v1.2
    git merge add-feature-x

    Will produce a nice linear history in the order things should have happened.

    Posted Feb 14 2008, 07:27 AM by chrisortman with no comments
    Filed under:
  • How to execute a VIM macro over a line range

    Macros in VIM are extremely useful for making lots of changes.

    One thing that has always bothered me though is that I couldn't run the macro over a movement or line range and had to run it manually for each line.

    The secret sauce is the :norm command.

    Say you have recorded a macro in the q register.

    To apply it to lines 3 - 6 use:

    :3,6norm! @q

    If you like VIM and want to learn more, I suggest you check out Aaron's screencasts.

  • Creating Subversion patches with git

    Adam expressed his frustration with creating tortoise compatible patches using git.

    He mentions a script that will do the job, which I have not yet tried. However if you are using git on windows you most likely have cygwin installed which you can use to install the patch.exe program.

    But first you need a patch file.

    This is pretty simple

    In my example I'm going to be creating a patch to fix FACILITIES-97 in castle project.

    First I need my local git repo ready

    git co -b bugs/facilities-97 castle-svn/trunk

    Now edit / test

    When you're all done prepare your index and commit

    git add .
    git commit -m "fixes (FACILITIES-97)"

    Now create your patch

    git format-patch castle-svn/trunk

    That last command will create a patch file for every commit that is in bugs/facilities-97 but not in castle-svn/trunk
    In this case I have a single commit so it creates 0001-fixes-FACILITIES-97.patch

    Now that you've got your patches they can be applied to svn like this

    patch -p1 -i 0001-fixes-FACILITIES-97.patch

    Now here's the gotcha. patch.exe can either read stdin or take a named file. My patches would always fail if I used stdin, so using -i to specify the filename is important.
    The -p1 switch tells patch to strip the first part of the path in the patch file because git generates file paths like
    /a/InversionOfControl/MicroKernel.....

    That's it, you're all done.

  • Which for Windows

    One thing I love about *nix is the which command which will tell me where a certain file is located if it is in my path.

    Say I have patch.exe in my path somewhere, but I don't know where, here's a quick powershell script to find out:

     

    foreach($p in $env:path.split(";")) { gci $p/patch.*}
  • Catching up with Castle trunk 4710

    I've just got done updating one of my projects from castle trunk 4044 to trunk 4710 and given the amount of changes thought I would share.

    First things first, fix up those compiler errors. I had quite a few, but they were easy and pretty much the same few things:

    • Rename IRailsEngineContext to IEngineContext
    • Change Filter methods to accept IController and IControllerContext instead of just Controller.
    • No more Context.Url, now it is Context.Request.Url
    • SetController method on helpers has changed to take IController and IControllerContext instead of Controller.
    • Since helpers now use IController instead of Controller there may be several missing methods or properties so just cast it to an instance of Controller.

     

    I'm so glad I have unit tests. When I first ran them I had many failures, but it was one fix:

    Error:

    Inner Exception
    NHibernate.HibernateException
    Message: Could not instantiate dialect class
    Source: NHibernate

    Problem:

    The key names for NHibernate configuration have changed

    Solution:

    Change your ActiveRecord configuration entries from this

    <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />

    to

    <add key="connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />

     

    Then to get my site up and running:

    Error:

    Configuration Error

    Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
    Parser Error Message: Could not load type 'Castle.MonoRail.Framework.EngineContextModule'

    Problem:

    There is no more EngineContextModule

    Solution:

    Remove this from web.config <add name="monorail" type="Castle.MonoRail.Framework.EngineContextModule, Castle.MonoRail.Framework" />

     

    Error:

    Configuration Error

    Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
    Parser Error Message: An error occurred creating the configuration section handler for Brail: Could not load file or assembly 'Boo.Lang.Extensions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67' or one of its dependencies. The system cannot find the file specified.

    Problem:

    A new boo assembly has been added

    Solution:

    Add a reference to Boo.Lang.Extensions to your web project.

     

    Error:

    CommonScripts\Extensions.brail(7,9): BCE0044: Boo.Lang.Compiler.CompilerError: expecting "end", found 'except'. ---> CommonScripts\Extensions.brail:7:9: expecting "end", found 'except'

    Problem:

    I had defined an extension method in one of my brail common scripts that looked like

    [Boo.Lang.ExtensionAttribute]
    static def IsEmpty(val as duck) as bool:
    	try:
    		return true if val is null
    		return val.GetEnumerator().MoveNext() == false
    	end
    	except e as System.MissingMethodException:
    		return true
    	end
    end

    Solution:

    [Boo.Lang.ExtensionAttribute]
    static def IsEmpty(val as duck) as bool:
    	try:
    		return true if val is null
    		return val.GetEnumerator().MoveNext() == false
    	except e as System.MissingMethodException:
    		return true
    	end
    end

     

    Of note:

    Because of the new way MonoRail resolves its service container you can remove the useWindsorIntegration flag from your configuration. I think this will also mean you don't need to register a custom logging service as well.

  • Limitations of svn branching

    I generally run all my projects that use castle off the trunk. However it has been several months since I've taken any updates, mostly due to lack of time on my part.

    As I'm upgrading there are many many changes which require me to update my code. Most due to the introduction of IController and changes from IRailsEngineContext.

     

    One such instance is IResponse.BinaryWrite which seems to no longer be available.

    As I dig through svn to try to find if there is a replacement method or why it was removed etc I am hit right in the face with how poorly svn handles branching and merging. The only log message in the trunk is that all these changes were merged back in in one giant commit. If you want to go see what those changes were you need to go look through the branch that was merged, but even then there's no way of knowing exactly which changes were pulled ( I just assume all.)

    With git I would be able to see these sort of things and save myself a lot of time.

  • Linux boot hangs at /etc/rc.local

    Last night I changed my display settings on my laptop for our user group meeting.

    However, the settings I had chosen started causing me problems the next time I rebooted.

    For the record I'm running Linux Mint Daryna 021 Beta

    During the boot the system would stop at "running scripts in /etc/rc.local" From there if I hit enter I would be greeted with a login prompt.

    At this point I didn't even think to try startx which would have quickly told me the problem. But I figured it must have something to do with my display since that was what i had last been messing with.

    Fortunately I had my MintCD handy so I popped that in and booted up. I then loaded up meld and started doing diffs between the live cd /etc directory and my own.

    Sure enough there were my changes in /etc/X11/xorg.conf

    I replaced the copy on disk with the copy from the live cd;reboot and viola I'm back in business.

  • Testing Helpers in MonoRail

    I have a helper that generates some links and wanted to be able to test that functionality. The difficult thing is that the helper delgates to UrlHelper which Delegates to Controller and to UrlBuilder.

    Thanks to the new testing functionality in MonoRail this was quite easy

    Heres's part of my test fixture.

     

    [TestFixture]
    public class NavigationHelperFixtures : Castle.MonoRail.TestSupport.BaseControllerTest {
    	private NavigationHelper helper;
    	private TestController controller;
    	[SetUp]
    	public void Setup() {			
    		helper = new NavigationHelper();
    		controller = new TestController();
    		PrepareController(controller, "test", "index");
    		helper.SetController(controller);
    	}
    }
     

    This will let me call my helper methods that call UrlHelper without problems.

     

     

    Technorati tags: ,
  • Can your VCS do this?

    Here's an interesting scenario I just ran into that makes me glad I am using git.

    I'm in the middle of working on a project which uses the same database for testing as development (not my idea) and I wanted to change the way that navigation on one of the pages works. This involves changes to the code as well as to a stored procedure. So I begin work like this

    git checkout -b experiments/new-navigation main

    Which will create a new branch for me to do my work in. Once the work is done I notify my testers to see what they think of the proposed change.

    While they are reviewing I want to be able to work on another feature, so I start:

    git checkout -b work/add-update-support main

    Which creates a new branch based on the main (which doesn't have any of the navigation changes I just did).

    The problem I'm going to have is that the database is using a version of the stored procedure I changed, but the change is incompatible with version of the code I have.

    What would you do? I'm not sure what I would do with subversion, probably copy and paste some hacks and leave TODO: markers by them. I'm using git though so I have a better way.

    Conceptually what I want is to go back in time and pretend I had made all the changes for update but started with navigation instead of main. Git has just the thing to do this and it is called rebase.

    git rebase --onto experiments/new-navigation main work/add-update-support

    So what happened after I ran this command?

    Here's a helpful graphic (excuse my poor image editing skills)

    The first diagram in my image shows what my working copy looked like before the rebase, and the second picture shows it after. As you can see I've gone back in time and made git think that my work/add-update-support started from a different base.

    Now I can continue to work on the update feature in the work/add-update-support branch. When I'm all done I have 2 options. If people like the navigation I can merge the work/add-update-support branch back into main, or if they don't I can rebase again and transplant the branch back onto main ala:

    git rebase --onto main experiments/new-navigation work/add-update-support 

     

    Technorati tags:
  • Getting started with the Castle git repo

    Before we dive into commands I feel the need for a little rationale. I'm not going to explain all the virtues of GIT as google will happily do that for you, I am however going to explain why I need to use it.

    I have 5 separate projects that all use something from Castle. Keeping track of which project uses which build can be very difficult espcially since I always run from castle trunk. Subversion would have me create a separate vendor branch in each project and stick mirror the castle repo there. That is all well and good until I start fixing bugs or making enhancements. As soon as that happens things get hairy.

    My solution is to have a git repository that mirrors the castle svn but contains separate branches for each product that is using it.

    On my system git branch -a will list something like

    castle-svn/trunk

    castle-svn/branches

    castle-svn/tags

    Product1/current

    Product2/current

    MyPatches/MR-XXX

    MR-Restsupport

    .....

    Now when I need to jump between projects and dig into castle source it is as simple as

    git checkout Product1/current

    I can also freely move patches around and stay up to date with the latest and greatest being produced by the castle community.

    Setting up the git mirror can be a time consuming process. You do have the option of only pulling history up to the last N revisions, but I like full history so I can visualize how things have changed. Pulling the full history takes a while and puts an increased load on Hammett's servers.

    That is why I did the full import and published the mirror to http://repo.or.cz which provides public git hosting.

    Now the good stuff. To get started you want to install cygwin + git. Git is a cygwin package so this is easy. I believe there is a MinGW port in progress, but I already had cygwin so this was easy for me.

    Now to clone the repo simply do

    git clone -n --origin castle-svn git://repo.or.cz/castle.git

    These are not the standard options, so let me explain.

    -n tells git to not checkout anything after it copies. I like this because a master branch isn't very meaningful to me in this context.

     --origin castle-svn tells git to place branches in from the remote repository into /refs/remotes/castle-svn instead of /refs/remotes/origin (the default). This again is just for simplicity on my part. I like doing git checkout trunk castle-svn/trunk better than git checkout trunk origin/trunk

    What you have at this point is a git repo that has all the SVN history. On my machine this actually takes up less space than the svn checkout

    That is all well and good but you only have the snapshot of the trunk as of when I created the git repo.

    At some point I will setup up an automated pull to keep history up to date, if you want to be able send a commit to the castle server you will need svn metadata anyway. To do that we use:

    git svn init https://svn.castleproject.org/svn/castle -T trunk -t tags -b branches

    This will create a new .git/svn folder and add some options to your .git/config file.

    Because we're doing things a little custom from the default behaviour of git-svn we need to edit this .git/config file to tell it where our subversion revisions go.

    Open up .git/config in your favorite text editor and make the svn-remote section look like this

     

    [svn-remote "svn"]
        url = https://svn.castleproject.org/svn/castle
        fetch = trunk:refs/remotes/castle-svn/trunk
        branches = branches/*:refs/remotes/castle-svn/branches/*
        tags = tags/*:refs/remotes/castle-svn/tags/*

    The stuff to the right of the equals sign is called a refspec and it tells git-svn that heads from svn under trunk goto refs/remotes/castle-svn/trunk (not the wildcard for branches and tags). This is creating remote-tracking branches in git.

    With this in place you can now do git svn fetch and git will check your history against all the castle revisions. This does take a minute or so, but it is much faster than having to pull all the svn file data.

    So now you want to work with RC3?

    git checkout -b RC3 castle-svn/tags/1.0.x-RC3

    What about the trunk?

    git checkout -b trunk castle-svn/trunk

    Maybe you need RC2

    git checkout -b RC2 castle-svn/tags/1.0.x-RC2

    Try switching between RC2 and RC3 and see how it compares to the paultry svn-switch.

    In our next installment we'll look at fixing a bug and creating the patch.

    Cheers

    PS: Trouble committing? Check here
    PPS: My list of git resources so far http://del.icio.us/chrisortman/git http://del.icio.us/chrisortman/git-svn

  • Refactoring in practice

    I've recently inherited some code that needs a bit of polish.

    Here's an example of one method I didn't like:

     

    /********************************************************
     *Sunday == 1 and Saturday == 7
     * In C#, Sunday == 0 and Saturday == 6
     * *****************************************************/
    public DateTime GetWeekEndDayDate(DateTime date, int WeekEndDay) {
    			
    	int temp = 0;
    	DateTime retval = DateTime.Now;
    	int Day = (int)date.DayOfWeek;
    	WeekEndDay--;//decrease by 1 so it lines up with C# enumeration of days
    
    	//get the difference in days
    	if (WeekEndDay > Day)
    		temp = WeekEndDay - Day;
    	else if (Day > WeekEndDay)
    		temp = WeekEndDay - Day + 7;
    	else
    		temp = 0;//currently on WeekEndDay
    
    	retval = date.AddDays((double)temp);
    	return retval;
    
    }

    So, how to fix?

    I need to verify that after my refactoring I still get the correct result. Since this class lacks a constructor that I can use without going through some other non-related initialization I've added my own constructor for the time being:

    public Tables(bool skipInitialization) {}
     

    I will use this in my test case that will check the existing behavior.

     

    [RowTest]
    [Row("10/15/2007",1)]		
    [Row("10/15/2007",2)]
    [Row("10/15/2007",3)]
    [Row("10/16/2007",4)]
    [Row("10/15/2007",5)]
    [Row("10/15/2007",6)]
    [Row("10/15/2007",7)]
    public void TestInputs_WithExpectedValuesFromOldAlgorithm(string startDate, int dayOfWeekIntValue) {
    
    	bool skipInitialization = true;
    	Tables t = new Tables(skipInitialization);
    	DateTime start = DateTime.Parse(startDate);
    	DateTime converted = t.GetWeekEndDayDate(start, dayOfWeekIntValue);
    	System.Diagnostics.Debug.WriteLine(converted);
    }

    All I want to do here is pass in some input and record the output. Once I have the output I change the test method and give it some values to check against.

     

    [RowTest]
    [Row("10/15/2007",1,"10/21/2007")]		
    [Row("10/15/2007",2,"10/15/2007")]
    [Row("10/15/2007",3,"10/16/2007")]
    [Row("10/16/2007",4,"10/17/2007")]
    [Row("10/15/2007",5,"10/18/2007")]
    [Row("10/15/2007",6,"10/19/2007")]
    [Row("10/15/2007",7,"10/20/2007")]
    public void TestInputs_WithExpectedValuesFromOldAlgorithm(string startDate, int dayOfWeekIntValue,string expected) {
    	bool skipInitialization = true;
    	Tables t = new Tables(skipInitialization);
    	DateTime start = DateTime.Parse(startDate);
    	DateTime converted = t.GetWeekEndDayDate(start, dayOfWeekIntValue);
    	Assert.AreEqual(DateTime.Parse(expected),converted);
    }

    This test should of course pass, but now I can do some real work. Since the bulk of this is just a generic date manipulation and not the primary responsibility of this class I want to extract that into a helper method. For now I'm must putting it into a Util class that has a bunch of static methods.

     

    public class Util {
    	public static DateTime GetWeekEndDayDate(DateTime date, int WeekEndDay) {
    		int temp = 0;
    		DateTime retval = DateTime.Now;
    		int Day = (int)date.DayOfWeek;
    		WeekEndDay--;//decrease by 1 so it lines up with C# enumeration of days
    
    		//get the difference in days
    		if (WeekEndDay > Day)
    			temp = WeekEndDay - Day;
    		else if (Day > WeekEndDay)
    			temp = WeekEndDay - Day + 7;
    		else
    			temp = 0;//currently on WeekEndDay
    
    		retval = date.AddDays((double)temp);
    		return retval;
    	}
    }

    The goal of this method should just be to advance the input date to the next DayOfWeek passed as the second argument. So I'm going to rename the method to MoveToNext and change the second argument to take a DayOfWeek enumeration value. This means it will be the respibility of the calling code to do that WeekEndDay-- before calling my method.

    I've now got this Util method

     

    public static DateTime MoveToNext(DateTime date, DayOfWeek day) {
    	int temp = 0;
    	DateTime retval = DateTime.Now;
    	int Day = (int)date.DayOfWeek;
    	int dayToMoveTo = (int) day;
    
    	//get the difference in days
    	if (dayToMoveTo > Day)
    		temp = dayToMoveTo - Day;
    	else if (Day > dayToMoveTo)
    		temp = dayToMoveTo - Day + 7;
    	else
    		temp = 0;//currently on WeekEndDay
    
    	retval = date.AddDays((double)temp);
    	return retval;
    }

    And this in my Tables class

     

    public DateTime GetWeekEndDayDate(DateTime date, int WeekEndDay) {
    	DayOfWeek dayValue = (DayOfWeek) WeekEndDay - 1;
    	return Util.MoveToNext(date, dayValue);
    
    }

    At this point my tests all still pass so now it's time to simplify that move to next method. I find it helps to think of this in terms of looking at a calendar and needing to get to the next Saturday or Monday or whatever. So that's what the code should do. I should be able to remove the conditionals and just walk the calendar until I get to the correct day. Rewritten with this in mind my method becomes

     

    public static DateTime MoveToNext(DateTime date, DayOfWeek day) {
    		
    	DateTime retval = date;
    	while(retval.DayOfWeek != day) {
    		retval = retval.AddDays(1);
    	}
    
    	return retval;
    }

    IMO this is much simpler to read, and since my tests still pass I haven't changed any functionality. I really wish I could use extension methods in this project because this is just screaming at me for a good case for them. No matter though, I can at least be prepared.I think we can improve this just a bit by renaming the method and changing the order of the parameters.

     

    public static class DateTimeExtensions {
    
    	public static DateTime MoveToNext(DateTime date, DayOfWeek day) {
    		DateTime retval = date;
    		while (retval.DayOfWeek != day) {
    			retval = retval.AddDays(1);
    		}
    
    	        return retval;
    	}
    }

    And, since my tests still pass I am all done.

    Posted Oct 16 2007, 07:09 AM by chrisortman with no comments
    Filed under:
  • UriTemplate and extensions

    The UriTemplate is a new class in the .NET Framework 3.5

    It provides a nice convenient way to parse variables from Uri's such that

     

    UriTemplate temp = new UriTemplate("account/{accountid}");
    Uri requestUri = temp.BindByPosition(baseUri, id.ToString());

    Will give you http://localhost/account/100 Nice!

     

    However, should your template contain a file extension it will give you an exception saying that there are no variables in your template, NOT Nice!

    Posted Sep 07 2007, 09:01 AM by chrisortman with no comments
    Filed under:
More Posts « Previous page - Next page »
Powered by Community Server (Commercial Edition), by Telligent Systems