Break LCS diffing to its own function. Minor style tweaks.

FossilOrigin-Name: bbd2a789cb94c5ac0a88f470734d6abfe4b1cbb38c6c17113f0e2430a6663630
This commit is contained in:
Mahlon E. Smith 2015-12-08 08:35:58 +00:00
parent b1ff94c067
commit 897837b463

209
shelldap
View file

@ -1238,6 +1238,113 @@ sub unwrap_line {
} }
### Given an LDAP Entry object $e, an array reference to it's LDIF original
### content, and another array reference to updated LDIF content, run an LCS
### comparison, modifying the Entry object in place.
###
sub diff {
my $self = shift;
my $e = shift;
my $orig = shift;
my $new = shift;
$self->unwrap_line( $orig );
$self->unwrap_line( $new );
# parser subref
#
my $parse = sub {
my $line = shift || $_;
return if $line =~ /^\#/; # ignore comments
my ( $attr, $val ) = ( $1, $2 ) if $line =~ /^(.+?): (.*)$/;
return unless $attr;
return if index($attr, ':') != -1; # ignore base64
return ( $attr, $val );
};
my $diff = Algorithm::Diff->new( $orig, $new );
HUNK:
while ( $diff->Next() ) {
next if $diff->Same();
my $diff_bit = $diff->Diff();
my %seen_attr;
# attr removal hunk
#
if ( $diff_bit == 1 ) {
foreach ( $diff->Items(1) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("DELETE: $_");
$e->delete( $attr => [ $val ] );
}
}
# attr insertion hunk
#
if ( $diff_bit == 2 ) {
foreach ( $diff->Items(2) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("INSERT: $_");
$e->add( $attr => $val );
}
}
# attr change hunk
#
if ( $diff_bit == 3 ) {
# modification to existing line
#
foreach ( $diff->Items(2) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("MODIFY: $_");
my $cur_vals = $e->get_value( $attr, asref => 1 ) || [];
my $cur_valcount = scalar @$cur_vals;
next if $cur_valcount == 0; # should have been an 'add'
# replace immediately
#
if ( $cur_valcount == 1 ) {
$e->replace( $attr => $val );
}
else {
# retain attributes that allow multiples, so updating
# one attribute doesn't inadvertently remove others with
# the same name.
#
next if $seen_attr{ $attr };
my @new_vals;
foreach my $line ( @$new ) {
my ( $new_attr, $new_val ) = $parse->( $line ) or next;
next unless $new_attr eq $attr;
$seen_attr{ $attr }++;
push @new_vals, $new_val;
}
$e->replace( $attr => \@new_vals );
}
}
# deletion within the same hunk
#
foreach ( $diff->Items(1) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
my $cur_vals = $e->get_value( $attr, asref => 1 ) || [];
my $cur_valcount = scalar @$cur_vals;
next if $cur_valcount == 1;
next if $seen_attr{ $attr };
$self->debug("DELETE: $_");
$e->delete( $attr => [ $val ] );
}
}
}
}
######################################################################## ########################################################################
### S H E L L M E T H O D S ### S H E L L M E T H O D S
######################################################################## ########################################################################
@ -1628,11 +1735,9 @@ sub run_edit
# checksum it, then open it in an editor # checksum it, then open it in an editor
# #
my $hash_orig = $self->chksum( $self->{'ldif_fname'} ); my $hash_orig = $self->chksum( $self->{'ldif_fname'} );
my @edit_args = split(' ',$self->{'editor'}); my @edit_args = split /\s+/, $self->{'editor'};
push(@edit_args,$self->{'ldif_fname'}); push @edit_args, $self->{'ldif_fname'};
# system( $self->{'editor'}, $self->{'ldif_fname'} ) && system( @edit_args ) && die "Unable to launch editor: $!\n";
system( @edit_args ) &&
die "Unable to launch editor: $!\n";
# detect a total lack of change # detect a total lack of change
# #
@ -1663,99 +1768,7 @@ sub run_edit
my @new_ldif = <LDIF>; my @new_ldif = <LDIF>;
close LDIF; close LDIF;
# parser subref $self->diff( $e, \@orig_ldif, \@new_ldif );
#
my $parse = sub {
my $line = shift || $_;
return if $line =~ /^\#/; # ignore comments
my ( $attr, $val ) = ( $1, $2 ) if $line =~ /^(.+?): (.*)$/;
return unless $attr;
return if index($attr, ':') != -1; # ignore base64
return ( $attr, $val );
};
$self->unwrap_line( \@orig_ldif );
$self->unwrap_line( \@new_ldif );
my $diff = Algorithm::Diff->new( \@orig_ldif, \@new_ldif );
HUNK:
while ( $diff->Next() ) {
next if $diff->Same();
my $diff_bit = $diff->Diff();
my %seen_attr;
# attr removal hunk
#
if ( $diff_bit == 1 ) {
foreach ( $diff->Items(1) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("DELETE: $_");
$e->delete( $attr => [ $val ] );
}
}
# attr insertion hunk
#
if ( $diff_bit == 2 ) {
foreach ( $diff->Items(2) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("INSERT: $_");
$e->add( $attr => $val );
}
}
# attr change hunk
#
if ( $diff_bit == 3 ) {
# modification to existing line
#
foreach ( $diff->Items(2) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
$self->debug("MODIFY: $_");
my $cur_vals = $e->get_value( $attr, asref => 1 ) || [];
my $cur_valcount = scalar @$cur_vals;
next if $cur_valcount == 0; # should have been an 'add'
# replace immediately
#
if ( $cur_valcount == 1 ) {
$e->replace( $attr => $val );
}
else {
# retain attributes that allow multiples, so updating
# one attribute doesn't inadvertently remove others with
# the same name.
#
next if $seen_attr{ $attr };
my @new_vals;
foreach my $line ( @new_ldif ) {
my ( $new_attr, $new_val ) = $parse->( $line ) or next;
next unless $new_attr eq $attr;
$seen_attr{ $attr }++;
push @new_vals, $new_val;
}
$e->replace( $attr => \@new_vals );
}
}
# deletion within the same hunk
#
foreach ( $diff->Items(1) ) {
my ( $attr, $val ) = $parse->( $_ ) or next;
my $cur_vals = $e->get_value( $attr, asref => 1 ) || [];
my $cur_valcount = scalar @$cur_vals;
next if $cur_valcount == 1;
next if $seen_attr{ $attr };
$self->debug("DELETE: $_");
$e->delete( $attr => [ $val ] );
}
}
}
my $update = sub { return $e->update( $self->ldap ); }; my $update = sub { return $e->update( $self->ldap ); };
my $rv = $self->with_retry( $update ); my $rv = $self->with_retry( $update );