############################################################################### # Codestriker: Copyright (c) 2001, 2002, 2003 David Sitsky. # All rights reserved. # sits@users.sourceforge.net # # This program is free software; you can redistribute it and modify it under # the terms of the GPL. # Parser object for reading ClearCase serial diff formats. package Codestriker::FileParser::ClearCaseSerialDiff; use strict; use Codestriker::FileParser::BasicDiffUtils; # Return the array of filenames, revision number, linenumber and the diff text. # Return () if the file can't be parsed, meaning it is in another format. sub parse ($$$) { my ($type, $fh, $repository) = @_; # Retrieve the repository root, and escape back-slashes in the case of # a Windows CVS repository, as it is used in regular expressions. my $repository_root = (defined $repository) ? $repository->getRoot() : undef; if (defined $repository_root) { $repository_root =~ s/\\/\\\\/g; } # Array of results found. my @result = (); # The current filename and revision being tracked. my $revision = $Codestriker::PATCH_REVISION; my $filename = ""; my $repmatch = 0; # Ignore any whitespace at the start of the file. my $line = <$fh>; while (defined($line)) { # Skip any heading or trailing whitespace contained in the review # text, in addition to the "Files/Directories are identical" lines, # which happen due to the way review texts are generated. while (defined($line) && ($line =~ /^\s*$/o || $line =~ /^Files are identical$/o || $line =~ /^Directories are identical$/o)) { $line = <$fh>; } return @result unless defined $line; # Check if the next fileheader is being read. if (defined $line && $line =~ /^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*$/o) { # Now read the file/directory that has been modified. $line = <$fh>; return () unless defined $line; if ($line =~ /^\<\<\< file 1\: (.*)\@\@(.*)$/o) { $filename = $1; $revision = $2; # Check if the filename matches the clear case repository. # This is very simple for now, but will need to be more # sophisticated later. if (defined $repository_root) { if ($filename =~ /^$repository_root[\/\\](.*)$/o) { $filename = $1; } $repmatch = 1; } else { $repmatch = 0; } # Read the next line which is the local file. $line = <$fh>; return () unless defined $line && $line =~ /^\>\>\> file 2\: .*$/o; # Now expect the end of the file header. $line = <$fh>; return () unless defined $line && $line =~ /^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*$/o; # Read the next line. $line = <$fh>; return () unless defined $line; } elsif ($line =~ /^\<\<\< directory 1\: (.*)\@\@(.*)$/o) { # Currently we don't really support directory # operations. ClearCase captures added/deleted # sub-directories and deleted files as a directory change, # but unfortunately added files go straight into the # VOB - great. Try to fddge this so that we treat the # directory as a file, where the contents are the diff # file itself - better than nothing, and the reviewers # can at least see what is going on. $filename = $1; $revision = $2; # Check if the filename matches the clear case repository. # This is very simple for now, but will need to be more # sophisticated later. if (defined $repository_root && $filename =~ /^$repository_root[\/\\](.*)$/o) { $filename = $1; } # Read the next line which is the local directory. $line = <$fh>; return () unless defined $line && $line =~ /^\>\>\> directory 2\: .*$/o; # Now expect the end of the file header. $line = <$fh>; return () unless defined $line && $line =~ /^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*$/o; # Keep reading text until there is nothing left for this # segment. my $text = ""; $line = <$fh>; while (defined $line && $line !~ /^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*$/o) { if ($line !~ /^Files are identical$/o && $line !~ /^Directories are identical$/o) { $text .= "+$line"; } $line = <$fh>; } # Create the chunk, indicating there is not a repository match, # since this is for a directory entry with some basic text. my $chunk = {}; $chunk->{filename} = $filename; $chunk->{revision} = $revision; $chunk->{old_linenumber} = 0; $chunk->{new_linenumber} = 1; $chunk->{binary} = 0; $chunk->{text} = $text; $chunk->{description} = ""; $chunk->{repmatch} = 0; push @result, $chunk; # Process the next block. next; } else { # Some unknown format. return (); } } # Read the next diff chunk. my $chunk = Codestriker::FileParser::BasicDiffUtils->read_diff_text( $fh, $line, $filename, $revision, $repmatch); return () unless defined $chunk; push @result, $chunk; # Read the next line. $line = <$fh>; } # Return the found diff chunks. return @result; } 1;