Bug 73531

Summary: [meta] Make prepare-ChangeLog a Perl module
Product: WebKit Reporter: Kentaro Hara <haraken>
Component: Tools / TestsAssignee: Kentaro Hara <haraken>
Status: RESOLVED FIXED    
Severity: Normal CC: abarth, aroben, darin, dbates, ddkilzer, eric, mjs
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 73208, 73788, 74172, 74173, 74175, 74257, 74266, 74389, 74485, 74497, 74681, 74698, 74808, 74836, 74992, 74994, 75081, 75191, 75195, 75197, 75201, 75202, 75524, 75531, 75836, 75943    
Bug Blocks:    
Attachments:
Description Flags
Patch ddkilzer: review-

Description Kentaro Hara 2011-11-30 23:45:47 PST
In order to write unit tests for prepare-ChangeLog, the unit tests need to load prepare-ChangeLog as a Perl module.
Comment 1 Kentaro Hara 2011-12-01 00:39:27 PST
Created attachment 117371 [details]
Patch
Comment 2 David Kilzer (:ddkilzer) 2011-12-03 20:53:01 PST
Comment on attachment 117371 [details]
Patch

This patch tries to do too much at once.  If we're going to refactor prepare-ChangeLog, we should do it in smaller steps (with unit tests written for each smaller patch).

It would also be acceptable to change prepare-ChangeLog just enough to make it possible to load the file as a module for unit testing (like run-leaks).  The way you do this is (likely) to refactor away the use of the problematic global variables.
Comment 3 Kentaro Hara 2011-12-04 16:21:06 PST
(In reply to comment #2)
> (From update of attachment 117371 [details])
> This patch tries to do too much at once.  If we're going to refactor prepare-ChangeLog, we should do it in smaller steps (with unit tests written for each smaller patch).
> 
> It would also be acceptable to change prepare-ChangeLog just enough to make it possible to load the file as a module for unit testing (like run-leaks).  The way you do this is (likely) to refactor away the use of the problematic global variables.

I guess that this is a minimal change for making prepare-ChangeLog just work as a Perl module. On the other hand, I do agree that this patch is doing too much at once. Then, I'd like to split this patch into the following sub-patches:

[1] Moves top level code (outside any subroutines) into prepareChangeLog().
[2] Moves all non-constant global variables' initialization into InitializeGlobalData().
[3] Adds ChangeLog::new().
[4] Adds "package ChangeLog;" at the beginning and "1;" at the end. Rename resolve-ChangeLogs to ChangeLog.pm. Adds a new prepare-ChangeLog, which instantiates a ChangeLog object using new() and calls ChangeLog::prepareChangeLog().
Comment 4 David Kilzer (:ddkilzer) 2011-12-09 17:17:18 PST
(In reply to comment #3)
> (In reply to comment #2)
> > (From update of attachment 117371 [details] [details])
> > This patch tries to do too much at once.  If we're going to refactor prepare-ChangeLog, we should do it in smaller steps (with unit tests written for each smaller patch).
> > 
> > It would also be acceptable to change prepare-ChangeLog just enough to make it possible to load the file as a module for unit testing (like run-leaks).  The way you do this is (likely) to refactor away the use of the problematic global variables.
> 
> I guess that this is a minimal change for making prepare-ChangeLog just work as a Perl module. On the other hand, I do agree that this patch is doing too much at once. Then, I'd like to split this patch into the following sub-patches:
> 
> [1] Moves top level code (outside any subroutines) into prepareChangeLog().

The patches so far that do this look good.

> [2] Moves all non-constant global variables' initialization into InitializeGlobalData().
> [3] Adds ChangeLog::new().
> [4] Adds "package ChangeLog;" at the beginning and "1;" at the end. Rename resolve-ChangeLogs to ChangeLog.pm. Adds a new prepare-ChangeLog, which instantiates a ChangeLog object using new() and calls ChangeLog::prepareChangeLog().

I'm not sure Steps 2-4 are necessary.  Remember, we're able to test the run-leaks script without making it into a Perl module.  At some point, the changes from Step 1 should be enough to use the same technique as we're using with the run-leaks script.  At most, you may need a Step 1.1 and 1.2:

[1.1] Move remaining top-level code into a main() method.
[1.2] Remove most (all?) global variables from the script by moving them into main().

After those steps, please try using the run-leaks method of testing the Perl script again.
Comment 5 Kentaro Hara 2011-12-11 02:08:13 PST
(In reply to comment #4)
> (In reply to comment #3)
> > (In reply to comment #2)
> I'm not sure Steps 2-4 are necessary.  Remember, we're able to test the run-leaks script without making it into a Perl module.  At some point, the changes from Step 1 should be enough to use the same technique as we're using with the run-leaks script.  At most, you may need a Step 1.1 and 1.2:
> 
> [1.1] Move remaining top-level code into a main() method.
> [1.2] Remove most (all?) global variables from the script by moving them into main().
> 
> After those steps, please try using the run-leaks method of testing the Perl script again.

ddkilzer: Thanks. I am not opposed to the run-leaks approach but I still feel that making prepare-ChangeLog.pm a Perl module might be better.

- In the run-leaks approach, we need to prepare RunLeaks.pm for unit-testing. If run-leaks were a Perl module, RunLeaks.pm is not necessary.
- In case of prepare-ChangeLog, since there are already many global variables, removing all global variables will lead to more arguments on methods, e.g. diffCommand(.., $isSVN, $isGit, $gitCommit, $mergeBase). Rather than increasing arguments, using an object might be more readable, like this:

sub diffCommand(...)
{
    my $self = shift;
    if ($self->{isSVN}) {
        ...;
    } elsif ($self->{isGit}) {
        ...;
    }
}

WDYT?
Comment 6 David Kilzer (:ddkilzer) 2011-12-11 07:59:47 PST
(In reply to comment #5)
> ddkilzer: Thanks. I am not opposed to the run-leaks approach but I still feel that making prepare-ChangeLog.pm a Perl module might be better.

I agree that having a nice object-oriented code base for prepare-ChangeLog would be preferable to a monolithic script with lots of functions, but moving all the functions from prepare-ChangeLog into prepareChangeLog.pm does not provide a good OO model for the code.  The fact that the ChangeLog::new() method had 15 arguments is a code smell that moving all the code into a module wasn't the correct direction to take.

For example, a ChangeLog.pm module might represent a ChangeLog file, and most of the things you can do with it.  A new ChangeLog object would take a path to an existing ChangeLog, and then there would be methods to modify it, and write it back out again.

The logic for parsing existing file types might be a separate set of modules, or even a module (class) hierarchy since most would probably share a lot of code.

> - In the run-leaks approach, we need to prepare RunLeaks.pm for unit-testing. If run-leaks were a Perl module, RunLeaks.pm is not necessary.

While this is a bit ugly, it's small, it won't change much, and it let me accomplish (a) writing tests for existing functionality to prevent further regressions and (b) writing tests for the bug fix I wanted to make.

> - In case of prepare-ChangeLog, since there are already many global variables, removing all global variables will lead to more arguments on methods,

True.  The same thing happen when most of prepare-ChangeLog was moved into a module with a new() method that had 15 arguments in the initial patch on this bug.

> e.g. diffCommand(.., $isSVN, $isGit, $gitCommit, $mergeBase). Rather than increasing arguments, using an object might be more readable, like this:
> 
> sub diffCommand(...)
> {
>     my $self = shift;
>     if ($self->{isSVN}) {
>         ...;
>     } elsif ($self->{isGit}) {
>         ...;
>     }
> }
> 
> WDYT?

I was hoping that a small-to-moderate amount of refactoring of prepare-ChangeLog (moving code into methods and removing global variables) would make it testable like run-leaks, then you could fix the original bug.

I agree that moving the code into modules would help to clean it up, but I think some more design needs to be done rather than just moving all of the code into a *.pm file.

Other possible directions could be:

- Refactoring prepare-ChangeLog into modules.  (This reduces the hackability of the script, which was one of the original goals when it was written by Darin/Maciej, but would make it easier to maintain.)

- Extract just the parsing code into a module (or set of modules) to make it testable, then fix the bug.

- Rewrite it in Python since that appears to be the overall direction of the WebKit project (tools written in Python).  This would be a much larger effort, though.

I'm very happy that you're refactoring this code, but I also don't want it to become a full-time job.
Comment 7 Kentaro Hara 2011-12-11 08:38:51 PST
(In reply to comment #6)
> (In reply to comment #5)
> I was hoping that a small-to-moderate amount of refactoring of prepare-ChangeLog (moving code into methods and removing global variables) would make it testable like run-leaks, then you could fix the original bug.
> 
> I agree that moving the code into modules would help to clean it up, but I think some more design needs to be done rather than just moving all of the code into a *.pm file.

ddkilzer: Makes great sense. Thanks. I'll take the run-leaks approach.

> I'm very happy that you're refactoring this code, but I also don't want it to become a full-time job.

Yeah, we should avoid "over-engineering". The original objective is just to fix a bug of prepare-ChangeLog when it parses here-document in Perl, which makes my full time job (i.e. implementing IDL bindings in around CodeGenerator*.pm) frustrating:-) But anyway I am happy to take this opportunity to make prepare-ChangeLog sane using my free time.
Comment 8 Kentaro Hara 2012-01-27 13:49:41 PST
Let me close this meta bug, since we've added unittests for prepare-ChangeLog and solved an original issue.
Comment 9 Hajime Morrita 2012-01-27 15:32:20 PST
Comment on attachment 117371 [details]
Patch

Making this patch obsolete then.