diff options
Diffstat (limited to 'Bugzilla/PatchReader/FixPatchRoot.pm')
-rw-r--r-- | Bugzilla/PatchReader/FixPatchRoot.pm | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/Bugzilla/PatchReader/FixPatchRoot.pm b/Bugzilla/PatchReader/FixPatchRoot.pm new file mode 100644 index 000000000..e67fb2796 --- /dev/null +++ b/Bugzilla/PatchReader/FixPatchRoot.pm @@ -0,0 +1,130 @@ +package Bugzilla::PatchReader::FixPatchRoot; + +use Bugzilla::PatchReader::FilterPatch; +use Bugzilla::PatchReader::CVSClient; + +use strict; + +@Bugzilla::PatchReader::FixPatchRoot::ISA = qw(Bugzilla::PatchReader::FilterPatch); + +sub new { + my $class = shift; + $class = ref($class) || $class; + my $this = $class->SUPER::new(); + bless $this, $class; + + my %parsed = Bugzilla::PatchReader::CVSClient::parse_cvsroot($_[0]); + $this->{REPOSITORY_ROOT} = $parsed{rootdir}; + $this->{REPOSITORY_ROOT} .= "/" if substr($this->{REPOSITORY_ROOT}, -1) ne "/"; + + return $this; +} + +sub diff_root { + my $this = shift; + if (@_) { + $this->{DIFF_ROOT} = $_[0]; + } else { + return $this->{DIFF_ROOT}; + } +} + +sub flush_delayed_commands { + my $this = shift; + return if ! $this->{DELAYED_COMMANDS}; + + my $commands = $this->{DELAYED_COMMANDS}; + delete $this->{DELAYED_COMMANDS}; + $this->{FORCE_COMMANDS} = 1; + foreach my $command_arr (@{$commands}) { + my $command = $command_arr->[0]; + my $arg = $command_arr->[1]; + if ($command eq "start_file") { + $this->start_file($arg); + } elsif ($command eq "end_file") { + $this->end_file($arg); + } elsif ($command eq "section") { + $this->next_section($arg); + } + } +} + +sub end_patch { + my $this = shift; + $this->flush_delayed_commands(); + $this->{TARGET}->end_patch(@_) if $this->{TARGET}; +} + +sub start_file { + my $this = shift; + my ($file) = @_; + # If the file is new, it will not have a filename that fits the repository + # root and therefore needs to be fixed up to have the same root as everyone + # else. At the same time we need to fix DIFF_ROOT too. + if (exists($this->{DIFF_ROOT})) { + # XXX Return error if there are multiple roots in the patch by verifying + # that the DIFF_ROOT is not different from the calculated diff root on this + # filename + + $file->{filename} = $this->{DIFF_ROOT} . $file->{filename}; + + $file->{canonical} = 1; + } elsif ($file->{rcs_filename} && + substr($file->{rcs_filename}, 0, length($this->{REPOSITORY_ROOT})) eq + $this->{REPOSITORY_ROOT}) { + # Since we know the repository we can determine where the user was in the + # repository when they did the diff by chopping off the repository root + # from the rcs filename + $this->{DIFF_ROOT} = substr($file->{rcs_filename}, + length($this->{REPOSITORY_ROOT})); + $this->{DIFF_ROOT} =~ s/,v$//; + # If the RCS file exists in the Attic then we need to correct for + # this, stripping off the '/Attic' suffix in order to reduce the name + # to just the CVS root. + if ($this->{DIFF_ROOT} =~ m/Attic/) { + $this->{DIFF_ROOT} = substr($this->{DIFF_ROOT}, 0, -6); + } + # XXX More error checking--that filename exists and that it is in fact + # part of the rcs filename + $this->{DIFF_ROOT} = substr($this->{DIFF_ROOT}, 0, + -length($file->{filename})); + $this->flush_delayed_commands(); + + $file->{filename} = $this->{DIFF_ROOT} . $file->{filename}; + + $file->{canonical} = 1; + } else { + # DANGER Will Robinson. The first file in the patch is new. We will try + # "delayed command mode" + # + # (if force commands is on we are already in delayed command mode, and sadly + # this means the entire patch was unintelligible to us, so we just output + # whatever the hell was in the patch) + + if (!$this->{FORCE_COMMANDS}) { + push @{$this->{DELAYED_COMMANDS}}, [ "start_file", { %{$file} } ]; + return; + } + } + $this->{TARGET}->start_file($file) if $this->{TARGET}; +} + +sub end_file { + my $this = shift; + if (exists($this->{DELAYED_COMMANDS})) { + push @{$this->{DELAYED_COMMANDS}}, [ "end_file", { %{$_[0]} } ]; + } else { + $this->{TARGET}->end_file(@_) if $this->{TARGET}; + } +} + +sub next_section { + my $this = shift; + if (exists($this->{DELAYED_COMMANDS})) { + push @{$this->{DELAYED_COMMANDS}}, [ "section", { %{$_[0]} } ]; + } else { + $this->{TARGET}->next_section(@_) if $this->{TARGET}; + } +} + +1 |