cvsserver: factor out git-log parsing logic

Some field conversion was already duplicated, and more calls will be added soon. Signed-off-by: Matthew Ogilvie <mmogilvi_git@miniinfo.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthew Ogilvie committed Oct 13, 2012 at 23:42 UTC 2c3af7e748206f385c85d35b902bce522107360b
1 file changed +105 -71
git-cvsserver.perl
+105 -71
@@ -3157,45 +3157,10 @@ sub update
3157 push @git_log_params, $self->{module};
3158 }
3159 # git-rev-list is the backend / plumbing version of git-log
3160 - open(GITLOG, '-|', 'git', 'rev-list', @git_log_params) or die "Cannot call git-rev-list: $!";
3161 -
3162 - my @commits;
3163 -
3164 - my %commit = ();
3165 -
3166 - while ( <GITLOG> )
3167 - {
3168 - chomp;
3169 - if (m/^commit\s+(.*)$/) {
3170 - # on ^commit lines put the just seen commit in the stack
3171 - # and prime things for the next one
3172 - if (keys %commit) {
3173 - my %copy = %commit;
3174 - unshift @commits, \%copy;
3175 - %commit = ();
3176 - }
3177 - my @parents = split(m/\s+/, $1);
3178 - $commit{hash} = shift @parents;
3179 - $commit{parents} = \@parents;
3180 - } elsif (m/^(\w+?):\s+(.*)$/ && !exists($commit{message})) {
3181 - # on rfc822-like lines seen before we see any message,
3182 - # lowercase the entry and put it in the hash as key-value
3183 - $commit{lc($1)} = $2;
3184 - } else {
3185 - # message lines - skip initial empty line
3186 - # and trim whitespace
3187 - if (!exists($commit{message}) && m/^\s*$/) {
3188 - # define it to mark the end of headers
3189 - $commit{message} = '';
3190 - next;
3191 - }
3192 - s/^\s+//; s/\s+$//; # trim ws
3193 - $commit{message} .= $_ . "\n";
3194 - }
3195 - }
3196 - close GITLOG;
3197 -
3198 - unshift @commits, \%commit if ( keys %commit );
3160 + open(my $gitLogPipe, '-|', 'git', 'rev-list', @git_log_params)
3161 + or die "Cannot call git-rev-list: $!";
3162 + my @commits=readCommits($gitLogPipe);
3163 + close $gitLogPipe;
3164
3165 # Now all the commits are in the @commits bucket
3166 # ordered by time DESC. for each commit that needs processing,
@@ -3294,7 +3259,7 @@ sub update
3259 }
3260
3261 # convert the date to CVS-happy format
3297 - $commit->{date} = "$2 $1 $4 $3 $5" if ( $commit->{date} =~ /^\w+\s+(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+(\d+)\s+([+-]\d+)$/ );
3262 + my $cvsDate = convertToCvsDate($commit->{date});
3263
3264 if ( defined ( $lastpicked ) )
3265 {
@@ -3303,7 +3268,7 @@ sub update
3268 while ( <FILELIST> )
3269 {
3270 chomp;
3306 - unless ( /^:\d{6}\s+\d{3}(\d)\d{2}\s+[a-zA-Z0-9]{40}\s+([a-zA-Z0-9]{40})\s+(\w)$/o )
3271 + unless ( /^:\d{6}\s+([0-7]{6})\s+[a-f0-9]{40}\s+([a-f0-9]{40})\s+(\w)$/o )
3272 {
3273 die("Couldn't process git-diff-tree line : $_");
3274 }
@@ -3313,11 +3278,7 @@ sub update
3278
3279 # $log->debug("File mode=$mode, hash=$hash, change=$change, name=$name");
3280
3316 - my $git_perms = "";
3317 - $git_perms .= "r" if ( $mode & 4 );
3318 - $git_perms .= "w" if ( $mode & 2 );
3319 - $git_perms .= "x" if ( $mode & 1 );
3320 - $git_perms = "rw" if ( $git_perms eq "" );
3281 + my $dbMode = convertToDbMode($mode);
3282
3283 if ( $change eq "D" )
3284 {
@@ -3327,11 +3288,11 @@ sub update
3288 revision => $head->{$name}{revision} + 1,
3289 filehash => "deleted",
3290 commithash => $commit->{hash},
3330 - modified => $commit->{date},
3291 + modified => $cvsDate,
3292 author => $commit->{author},
3332 - mode => $git_perms,
3293 + mode => $dbMode,
3294 };
3334 - $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms);
3295 + $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $cvsDate, $commit->{author}, $dbMode);
3296 }
3297 elsif ( $change eq "M" || $change eq "T" )
3298 {
@@ -3341,11 +3302,11 @@ sub update
3302 revision => $head->{$name}{revision} + 1,
3303 filehash => $hash,
3304 commithash => $commit->{hash},
3344 - modified => $commit->{date},
3305 + modified => $cvsDate,
3306 author => $commit->{author},
3346 - mode => $git_perms,
3307 + mode => $dbMode,
3308 };
3348 - $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms);
3309 + $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $cvsDate, $commit->{author}, $dbMode);
3310 }
3311 elsif ( $change eq "A" )
3312 {
@@ -3355,11 +3316,11 @@ sub update
3316 revision => $head->{$name}{revision} ? $head->{$name}{revision}+1 : 1,
3317 filehash => $hash,
3318 commithash => $commit->{hash},
3358 - modified => $commit->{date},
3319 + modified => $cvsDate,
3320 author => $commit->{author},
3360 - mode => $git_perms,
3321 + mode => $dbMode,
3322 };
3362 - $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms);
3323 + $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $cvsDate, $commit->{author}, $dbMode);
3324 }
3325 else
3326 {
@@ -3382,7 +3343,7 @@ sub update
3343 die("Couldn't process git-ls-tree line : $_");
3344 }
3345
3385 - my ( $git_perms, $git_type, $git_hash, $git_filename ) = ( $1, $2, $3, $4 );
3346 + my ( $mode, $git_type, $git_hash, $git_filename ) = ( $1, $2, $3, $4 );
3347
3348 $seen_files->{$git_filename} = 1;
3349
@@ -3392,18 +3353,10 @@ sub update
3353 $head->{$git_filename}{mode}
3354 );
3355
3395 - if ( $git_perms =~ /^\d\d\d(\d)\d\d/o )
3396 - {
3397 - $git_perms = "";
3398 - $git_perms .= "r" if ( $1 & 4 );
3399 - $git_perms .= "w" if ( $1 & 2 );
3400 - $git_perms .= "x" if ( $1 & 1 );
3401 - } else {
3402 - $git_perms = "rw";
3403 - }
3356 + my $dbMode = convertToDbMode($mode);
3357
3358 # unless the file exists with the same hash, we need to update it ...
3406 - unless ( defined($oldhash) and $oldhash eq $git_hash and defined($oldmode) and $oldmode eq $git_perms )
3359 + unless ( defined($oldhash) and $oldhash eq $git_hash and defined($oldmode) and $oldmode eq $dbMode )
3360 {
3361 my $newrevision = ( $oldrevision or 0 ) + 1;
3362
@@ -3412,13 +3365,13 @@ sub update
3365 revision => $newrevision,
3366 filehash => $git_hash,
3367 commithash => $commit->{hash},
3415 - modified => $commit->{date},
3368 + modified => $cvsDate,
3369 author => $commit->{author},
3417 - mode => $git_perms,
3370 + mode => $dbMode,
3371 };
3372
3373
3421 - $self->insert_rev($git_filename, $newrevision, $git_hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms);
3374 + $self->insert_rev($git_filename, $newrevision, $git_hash, $commit->{hash}, $cvsDate, $commit->{author}, $dbMode);
3375 }
3376 }
3377 close FILELIST;
@@ -3431,10 +3384,10 @@ sub update
3384 $head->{$file}{revision}++;
3385 $head->{$file}{filehash} = "deleted";
3386 $head->{$file}{commithash} = $commit->{hash};
3434 - $head->{$file}{modified} = $commit->{date};
3387 + $head->{$file}{modified} = $cvsDate;
3388 $head->{$file}{author} = $commit->{author};
3389
3437 - $self->insert_rev($file, $head->{$file}{revision}, $head->{$file}{filehash}, $commit->{hash}, $commit->{date}, $commit->{author}, $head->{$file}{mode});
3390 + $self->insert_rev($file, $head->{$file}{revision}, $head->{$file}{filehash}, $commit->{hash}, $cvsDate, $commit->{author}, $head->{$file}{mode});
3391 }
3392 }
3393 # END : "Detect deleted files"
@@ -3472,6 +3425,87 @@ sub update
3425 $self->{dbh}->commit() or die "Failed to commit changes to SQLite";
3426 }
3427
3428 +sub readCommits
3429 +{
3430 + my $pipeHandle = shift;
3431 + my @commits;
3432 +
3433 + my %commit = ();
3434 +
3435 + while ( <$pipeHandle> )
3436 + {
3437 + chomp;
3438 + if (m/^commit\s+(.*)$/) {
3439 + # on ^commit lines put the just seen commit in the stack
3440 + # and prime things for the next one
3441 + if (keys %commit) {
3442 + my %copy = %commit;
3443 + unshift @commits, \%copy;
3444 + %commit = ();
3445 + }
3446 + my @parents = split(m/\s+/, $1);
3447 + $commit{hash} = shift @parents;
3448 + $commit{parents} = \@parents;
3449 + } elsif (m/^(\w+?):\s+(.*)$/ && !exists($commit{message})) {
3450 + # on rfc822-like lines seen before we see any message,
3451 + # lowercase the entry and put it in the hash as key-value
3452 + $commit{lc($1)} = $2;
3453 + } else {
3454 + # message lines - skip initial empty line
3455 + # and trim whitespace
3456 + if (!exists($commit{message}) && m/^\s*$/) {
3457 + # define it to mark the end of headers
3458 + $commit{message} = '';
3459 + next;
3460 + }
3461 + s/^\s+//; s/\s+$//; # trim ws
3462 + $commit{message} .= $_ . "\n";
3463 + }
3464 + }
3465 +
3466 + unshift @commits, \%commit if ( keys %commit );
3467 +
3468 + return @commits;
3469 +}
3470 +
3471 +sub convertToCvsDate
3472 +{
3473 + my $date = shift;
3474 + # Convert from: "git rev-list --pretty" formatted date
3475 + # Convert to: "the format specified by RFC822 as modified by RFC1123."
3476 + # Example: 26 May 1997 13:01:40 -0400
3477 + if( $date =~ /^\w+\s+(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+(\d+)\s+([+-]\d+)$/ )
3478 + {
3479 + $date = "$2 $1 $4 $3 $5";
3480 + }
3481 +
3482 + return $date;
3483 +}
3484 +
3485 +sub convertToDbMode
3486 +{
3487 + my $mode = shift;
3488 +
3489 + # NOTE: The CVS protocol uses a string similar "u=rw,g=rw,o=rw",
3490 + # but the database "mode" column historically (and currently)
3491 + # only stores the "rw" (for user) part of the string.
3492 + # FUTURE: It might make more sense to persist the raw
3493 + # octal mode (or perhaps the final full CVS form) instead of
3494 + # this half-converted form, but it isn't currently worth the
3495 + # backwards compatibility headaches.
3496 +
3497 + $mode=~/^\d\d(\d)\d{3}$/;
3498 + my $userBits=$1;
3499 +
3500 + my $dbMode = "";
3501 + $dbMode .= "r" if ( $userBits & 4 );
3502 + $dbMode .= "w" if ( $userBits & 2 );
3503 + $dbMode .= "x" if ( $userBits & 1 );
3504 + $dbMode = "rw" if ( $dbMode eq "" );
3505 +
3506 + return $dbMode;
3507 +}
3508 +
3509 sub insert_rev
3510 {
3511 my $self = shift;