Search code examples
delphidelphi-2007static-code-analysislines-of-code

Windows diff tool to extract lines of code written and time spend


Is there a tool for Windows that can read the Delphi history files.
and extract the lines-of-code written per session along with the timestamps of the sessions.

What info do I want

session_id   date+time             filename      lines_of_code changed
1            1-1-2011 - 13:14:36   unit1.pas     100
....

What info do I have to extract this from
I'm using Delphi 2007.
And every change a in source file gets written to a subdir called history that looks like:

name                date_changed    type     size
project1.dpr.~1~    date-time       ~1~      1  kb
project1.dpr.~2~    date-time       ~2~      1  kb
unit1.pas.~1~       date-time       ~1~      83 kb
...

Every history file includes the full source code, not just the differences.
(so if you would like to revert back to a source file you can just code that file over the old)

Not subversion
For the future I'm going to use a subversion program to keep track of this stuff, but for the past stuff I want to have some record as well.
So unless a subversion clone can index the old source file backups in the history folder I'm not looking for that now.


Solution

  • Virtually any Diff tool that generates so-called "diff compatible" diff files or "patches" can be used for the job. For example, I'm sure you can use this: http://gnuwin32.sourceforge.net/packages/diffutils.htm

    Simply invoke the command line tool giving as parameters the new and the old versions of the file and Annalise it's output: You basically care about lines that start with a single - or +. This would give you a rough estimate of number of lines changed. If you want to get fancy you'll need to modify your algorithm to properly detect changed blocks, but that's a lot more difficult, because diff's job is to generate output that's used to transform the "old" file into a "new" files, not count changes. Line edits are usually shown as a deletion followed by an addition.

    Here are the problems you'll face using diff:

    • Moved lines are shown as both DELETIONS and ADDITIONS and will likely be counted twice, even those all the programmer did was restructure the code a bit.
    • Edited lines might be counted more then once.

    Since you don't care about the actual diff, and you want a rough estimate of changed lines of code, here's an other very simple idea that provides you with a number. Not very accurate, but then again LOC counting is not exactly an accurate measure of programmer performance any way! This code looks at both OLD and NEW files and gives the number of lines found in OLD but not found in NEW plus the number of lines found in NEW but not found in OLD

    function CountLineChanges(const OldFile, NewFile:string):Integer;
    var OldL: TStringList;
        NewL: TStringList;
        i: Integer;
    
      procedure FillListWithStringsFromFile(const FileName: string; const L:TStringList);
      var F: TStringList;
          i,n: Integer;
          s: string;
      begin
        F := TStringList.Create;
        try
          F.LoadFromFile(FileName);
          for i:=0 to F.Count-1 do
          begin
            s := F[i];
            if L.IndexOf(s) = -1 then
              L.Add(s)
            else
              begin
                // Seeing this line again!
                n := 1;
                while L.IndexOf(s + '#' + IntToStr(n)) <> -1 do
                  Inc(n);
                L.Add(s + '#' + IntToStr(n));
              end;
          end;
        finally F.Free;
        end;
      end;
    
    begin
      OldL := TStringList.Create;
      try
        OldL.Sorted := True;
        NewL := TStringList.Create;
        try
          NewL.Sorted := True;
    
          FillListWithStringsFromFile(OldFile, OldL);
          FillListWithStringsFromFile(NewFile, NewL);
    
          Result := 0;
          for i:=0 to OldL.Count-1 do
            if NewL.IndexOf(OldL[i]) = -1 then
              Inc(Result);
          for i:=0 to NewL.Count-1 do
            if OldL.IndexOf(NewL[i]) = -1 then
              Inc(Result);
    
        finally NewL.Free;
        end;
      finally OldL.Free;
      end;
    end;
    

    Issues with this code:

    • Blocks of code moved from one place to the other give 0 as a result.
    • All edited lines are counted precisely twice.