VCS-Lite-0.10/0000755000175000017500000000000012076757313012225 5ustar barbiebarbieVCS-Lite-0.10/t/0000755000175000017500000000000012076757313012470 5ustar barbiebarbieVCS-Lite-0.10/t/21merge.t0000644000175000017500000000147512076757276014136 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More tests => 5; use VCS::Lite; my $el1 = VCS::Lite->new('data/mariner.txt'); #01 isa_ok($el1,'VCS::Lite','Return from new, passed filespec'); my $el2 = VCS::Lite->new('data/marinerx.txt'); my $el3 = VCS::Lite->new('data/marinery.txt'); $el1->apply($el2); #02 ok(!$el1->delta($el2), "Not different once applied"); my $el1a = $el1->original; #03 ok($el1->delta($el1a), "but different from original"); #04 isa_ok($el1a,'VCS::Lite','Return from original'); $el1a->apply($el3); $el1->apply($el1a, base => 'original'); my $merged = $el1->text; #Uncomment for debugging open MERGE,'>merge1.out'; print MERGE $merged; close MERGE; my $results = do { local (@ARGV, $/) = 'data/marinerxy.txt'; <> }; # slurp entire file #05 is($merged, $results, 'Merge matches expected results'); VCS-Lite-0.10/t/01load.t0000644000175000017500000000017512076757276013750 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More tests => 2; BEGIN { use_ok( 'VCS::Lite' ); use_ok( 'VCS::Lite::Delta' ); } VCS-Lite-0.10/t/10diff.t0000644000175000017500000000750512076757276013745 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More tests => 17; use VCS::Lite; my $save_output = $ENV{VCS_LITE_KEEP_OUTPUT}; my $el1 = VCS::Lite->new('data/mariner.txt'); #01 isa_ok($el1,'VCS::Lite','Return from new, passed filespec'); #02 is($el1->id,'data/mariner.txt','Correct name returned by id'); my $el2 = VCS::Lite->new('data/marinerx.txt'); #03 ok(!$el1->delta($el1),'Compare with same returns empty array'); my $dt1 = $el1->delta($el2); #04 isa_ok($dt1,'VCS::Lite::Delta','Delta return'); #05 my @id = $dt1->id; is_deeply(\@id,['data/mariner.txt', 'data/marinerx.txt'], 'id method of delta returns correct ids'); #06 my @hunks = $dt1->hunks; is_deeply(\@hunks, [ [ ['-', 3, "Now wherefore stopp'st thou me?\n"], ['+', 3, "Now wherefore stoppest thou me?\n"], ],[ ['-', 20, "The Wedding-Guest sat on a stone:\n"], ['-', 21, "He cannot chuse but hear;\n"], ['-', 22, "And thus spake on that ancient man,\n"], ['-', 23, "The bright-eyed Mariner.\n"], ['-', 24, "\n"], ],[ ['+', 32, "Wondering about the wretched loon\n"], ],[ ['-', 94, "Whiles all the night, through fog-smoke white,\n"], ['-', 95, "Glimmered the white Moon-shine.\n"], ['+', 90, "While all the night, through fog-smoke white,\n"], ['+', 91, "Glimmered the white Moonshine.\n"], ] ], 'Full comparison of hunks'); my $diff = $dt1->diff; #07 ok($diff, 'Diff returns differences'); if ($save_output) { open (my $dfh, '>', 'diff1.out') or die "Failed to write output: $!"; print $dfh $diff; } my $results = do { local (@ARGV, $/) = 'data/marinerx.dif'; <> }; #08 is($diff, $results, 'Diff matches expected results (diff)'); my $el1c = VCS::Lite->new('data/mariner.txt', { chomp => 1 } ); my $el2c = VCS::Lite->new('data/marinerx.txt', { chomp => 1 } ); my $dt1c = $el1c->delta($el2c); $diff = $dt1c->diff; if ($save_output) { open (my $dfh, '>', 'diff1c.out') or die "Failed to write output: $!"; print $dfh $diff; } #09 is($diff, $results, 'Chomped mode: diff matches expected results'); my $el3 = VCS::Lite->new('data/marinery.txt'); $diff = $el1->diff($el3); # old form of call #10 ok($diff, 'Diff returns differences'); if ($save_output) { open (my $dfh, '>', 'diff2.out') or die "Failed to write output: $!"; print $dfh $diff; } $results = do { local (@ARGV, $/) = 'data/marinery.dif'; <> }; #11 is($diff, $results, 'Diff matches expected results (diff)'); my $udiff = $dt1->udiff; #12 ok($udiff, 'udiff returns differences'); if ($save_output) { open (my $dfh, '>', 'diff3.out') or die "Failed to write output: $!"; print $dfh $udiff; } $results = do { local (@ARGV, $/) = 'data/marinerx1.udif'; <> }; #13 is($udiff, $results, 'Diff matches expected results (udiff)'); $dt1 = $el1->delta($el2, window => 3); $udiff = $dt1->udiff; $results = do { local (@ARGV, $/) = 'data/marinerx.udif'; <> }; #14 is($udiff, $results, 'Diff matches expected results (udiff, 3 window)'); $dt1c = $el1c->delta($el2c, window => 3); $udiff = $dt1c->udiff; #15 is($udiff, $results, 'Chomped diff matches expected results (udiff, 3 window)'); if ($save_output) { open (my $dfh, '>', 'diff4.out') or die "Failed to write output: $!"; print $dfh $udiff; } #Test with no newline at end of file my $el4 = VCS::Lite->new('data/snarka.txt'); my $el5 = VCS::Lite->new('data/snarkb.txt'); my $dt2 = $el4->delta($el5); $results = do { local (@ARGV, $/) = 'data/snarkab.dif'; <> }; $diff = $dt2->diff; #16 is($diff, $results, 'Diff matches expected results (diff)'); $results = do { local (@ARGV, $/) = 'data/snarkab.udif'; <> }; $udiff = $dt2->udiff; #17 is($udiff, $results, 'Diff matches expected results (udiff)'); if ($save_output) { open (my $dfh, '>', 'diff5.out') or die "Failed to write output: $!"; print $dfh $udiff; } VCS-Lite-0.10/t/96metatest.t0000644000175000017500000000125312076757276014673 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More; # Skip if doing a regular install plan skip_all => "Author tests not required for installation" unless ( $ENV{AUTOMATED_TESTING} ); eval "use Test::CPAN::Meta::JSON"; plan skip_all => "Test::CPAN::Meta::JSON required for testing META.json files" if $@; plan 'no_plan'; my $meta = meta_spec_ok(undef,undef,@_); use VCS::Lite; my $version = $VCS::Lite::VERSION; is($meta->{version},$version, 'META.json distribution version matches'); if($meta->{provides}) { for my $mod (keys %{$meta->{provides}}) { is($meta->{provides}{$mod}{version},$version, "META.json entry [$mod] version matches"); } } VCS-Lite-0.10/t/91podcover.t0000644000175000017500000000051312076757276014657 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More; # Skip if doing a regular install plan skip_all => "Author tests not required for installation" unless ( $ENV{AUTOMATED_TESTING} ); eval "use Test::Pod::Coverage 0.08"; plan skip_all => "Test::Pod::Coverage 0.08 required for testing POD coverage" if $@; all_pod_coverage_ok(); VCS-Lite-0.10/t/95changedate.t0000644000175000017500000000227512076757276015134 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More; use IO::File; # Skip if doing a regular install plan skip_all => "Author tests not required for installation" unless ( $ENV{AUTOMATED_TESTING} ); my $fh = IO::File->new('Changes','r') or plan skip_all => "Cannot open Changes file"; plan 'no_plan'; use VCS::Lite; my $version = $VCS::Lite::VERSION; my $latest = 0; while(<$fh>) { next unless(m!^\d!); $latest = 1 if(m!^$version!); # 2012-08-26T01:02 or 2012-08-26T01:02:03 or 2012-08-26T01:02:03.04 or 2012-08-26T01:02+01:00 like($_, qr!^ \d[\d._]+\s+ # version ( \d{4}-\d{2}-\d{2} # 2012-08-26 - YYYY-MM-DD ( T\d{2}:\d{2} # T01:02 - Thh:mm ( :\d{2} # :02 - :ss ( \.\d+ # .2 - .ss (microseconds) )? )? ( (Z|[-+]\d+:\d+) # +01:00 - timezone )? )? ) \s*$!x,'... version has a date'); } is($latest,1,'... latest version not listed'); VCS-Lite-0.10/t/94metatest.t0000644000175000017500000000122612076757276014671 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More; # Skip if doing a regular install plan skip_all => "Author tests not required for installation" unless ( $ENV{AUTOMATED_TESTING} ); eval "use Test::CPAN::Meta"; plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@; plan 'no_plan'; my $meta = meta_spec_ok(undef,undef,@_); use VCS::Lite; my $version = $VCS::Lite::VERSION; is($meta->{version},$version, 'META.yml distribution version matches'); if($meta->{provides}) { for my $mod (keys %{$meta->{provides}}) { is($meta->{provides}{$mod}{version},$version, "META.yml entry [$mod] version matches"); } } VCS-Lite-0.10/t/20merge.t0000644000175000017500000000155412076757276014133 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More tests => 4; use VCS::Lite; my $el1 = VCS::Lite->new('data/mariner.txt'); #01 isa_ok($el1,'VCS::Lite','Return from new, passed filespec'); my $el2 = VCS::Lite->new('data/marinerx.txt'); my $el3 = VCS::Lite->new('data/marinery.txt'); my $el4 = $el1->merge($el2,$el3); #02 isa_ok($el4,'VCS::Lite','Return from merge method'); my $merged = $el4->text; #Uncomment for debugging #open MERGE,'>merge1.out'; #print MERGE $merged; #close MERGE; my $results = do { local (@ARGV, $/) = 'data/marinerxy.txt'; <> }; # slurp entire file #03 is($merged, $results, 'Merge matches expected results'); $el3 = VCS::Lite->new('data/marinerz.txt'); $el4 = $el1->merge($el2,$el3); $merged = $el4->text; #04 isa_ok($el4,'VCS::Lite','merge returns'); #Uncomment for debugging #open MERGE,'>merge2.out'; #print MERGE $merged; #close MERGE; VCS-Lite-0.10/t/90podtest.t0000644000175000017500000000045312076757276014522 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More; # Skip if doing a regular install plan skip_all => "Author tests not required for installation" unless ( $ENV{AUTOMATED_TESTING} ); eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); VCS-Lite-0.10/t/30patch.t0000644000175000017500000000641112076757276014131 0ustar barbiebarbie#!/usr/bin/perl -w use strict; use Test::More tests => 19; use VCS::Lite; my $save_output = $ENV{VCS_LITE_KEEP_OUTPUT}; my $el1 = VCS::Lite->new('data/mariner.txt'); #01 isa_ok($el1,'VCS::Lite','Return from new, passed filespec'); my $el2 = VCS::Lite->new('data/marinerx.txt'); my $dt1 = VCS::Lite::Delta->new('data/marinerx.dif',undef,'mariner.txt','marinerx.txt'); #02 isa_ok($dt1,'VCS::Lite::Delta','New delta'); my $el3 = $el1->patch($dt1); #03 isa_ok($el3,'VCS::Lite','Return from patch method'); my $out2 = $el2->text; my $out3 = $el3->text; if ($save_output) { open (my $dfh, '>', 'patch1.out') or die "Failed to write output: $!"; print $dfh $out3; } #04 is($out2, $out3, 'Patched file is the same as marinerx'); my $dt2 = VCS::Lite::Delta->new('data/marinerx.udif',undef,'mariner.txt','marinerx.txt'); #05 isa_ok($dt2,'VCS::Lite::Delta','New delta'); my $el4 = $el1->patch($dt2); #06 isa_ok($el4,'VCS::Lite','Patch applied'); my $out4 = $el4->text; #07 is($out2, $out4, 'Patched file is the same as marinerx'); my $el1c = VCS::Lite->new('data/mariner.txt', {chomp => 1}); my $el2c = VCS::Lite->new('data/marinerx.txt', {chomp => 1}); my $dt1c = VCS::Lite::Delta->new('data/marinerx.dif',{chomp => 1}, 'mariner.txt','marinerx.txt'); #08 isa_ok($dt1c,'VCS::Lite::Delta','New delta (chomped)'); my $el3c = $el1c->patch($dt1c); #09 isa_ok($el3c,'VCS::Lite','Return from patch method (chomped)'); $out2 = $el2c->text; $out3 = $el3c->text; if ($save_output) { open (my $dfh, '>', 'patch1c.out') or die "Failed to write output: $!"; print $dfh $out3; } #10 is($out2, $out3, 'Patched file is the same as marinerx'); my $dt2c = VCS::Lite::Delta->new('data/marinerx.udif',{chomp => 1}, 'mariner.txt','marinerx.txt'); #11 isa_ok($dt2c,'VCS::Lite::Delta','New delta'); my $el4c = $el1c->patch($dt2c); #12 isa_ok($el4c,'VCS::Lite','Patch applied'); $out4 = $el4c->text; #13 is($out2, $out4, 'Patched file is the same as marinerx (chomped)'); my $udiff = $dt2->udiff; #14 ok($udiff, "udiff returns text"); if ($save_output) { open (my $dfh, '>', 'patch2.out') or die "Failed to write output: $!"; print $dfh $udiff; } my $results = do { local (@ARGV, $/) = 'data/marinerx.udif'; <> }; # slurp entire file $results =~ s/^\+\+\+.*\n//s; $results =~ s/^---.*\n//s; $udiff =~ s/^\+\+\+.*\n//s; $udiff =~ s/^---.*\n//s; #15 is($udiff,$results,'udiff output matches original udiff'); $udiff = $dt2c->udiff; #16 ok($udiff, "udiff returns text (chomped)"); if ($save_output) { open (my $dfh, '>', 'patch2c.out') or die "Failed to write output: $!"; print $dfh $udiff; } $udiff =~ s/^\+\+\+.*\n//s; $udiff =~ s/^---.*\n//s; #17 is($udiff,$results,'udiff output matches original udiff'); my $el5 = VCS::Lite->new('data/snarka.txt'); my $el6 = VCS::Lite->new('data/snarkb.txt'); my $dt3 = VCS::Lite::Delta->new('data/snarkab.dif',undef,'snarka.txt','snarkb.txt'); my $el7 = $el5->patch($dt3); my $out6 = $el6->text; my $out7 = $el7->text; #16 is($out6, $out7, 'Patched file is the same as snarkb (diff)'); my $dt4 = VCS::Lite::Delta->new('data/snarkab.udif',undef,'snarka.txt','snarkb.txt'); my $el8 = $el5->patch($dt4); $out7 = $el7->text; my $out8 = $el8->text; #17 is($out6, $out8, 'Patched file is the same as snarkb (udiff)'); VCS-Lite-0.10/lib/0000755000175000017500000000000012076757313012773 5ustar barbiebarbieVCS-Lite-0.10/lib/VCS/0000755000175000017500000000000012076757313013426 5ustar barbiebarbieVCS-Lite-0.10/lib/VCS/Lite.pm0000644000175000017500000004041012076757275014667 0ustar barbiebarbiepackage VCS::Lite; use strict; use warnings; our $VERSION = '0.10'; #---------------------------------------------------------------------------- =head1 NAME VCS::Lite - Minimal version control system =head1 SYNOPSIS use VCS::Lite; # diff my $lit = VCS::Lite->new('/home/me/foo1.txt'); my $lit2 = VCS::Lite->new('/home/me/foo2.txt'); my $difftxt = $lit->delta($lit2)->diff; print OUTFILE $difftxt; # patch my $delt = VCS::Lite::Delta->new('/home/me/patch.diff'); my $lit3 = $lit->patch($delt); print OUTFILE $lit3->text; # merge my $lit4 = $lit->merge($lit->delta($lit2),$lit->delta($lit3)); print OUTFILE $lit4->text; =head1 DESCRIPTION This module provides the functions normally associated with a version control system, but without needing or implementing a version control system. Applications include wikis, document management systems and configuration management. It makes use of the module Algorithm::Diff. It provides the facility for basic diffing, patching and merging. =cut #---------------------------------------------------------------------------- ############################################################################# #Library Modules # ############################################################################# use Carp; use Algorithm::Diff qw(traverse_sequences); use VCS::Lite::Delta; #---------------------------------------------------------------------------- ############################################################################# #Interface Methods # ############################################################################# sub new { my ($class,$id,$sep,$src,@args) = @_; my %proto = (); # Decode $sep as needed if (ref($sep) eq 'HASH') { %proto = %$sep; $sep = $proto{in}; delete $proto{in}; } # DWIM logic, based on $src parameter. # Case 0: $src missing. Use $id as file name, becomes case 3 open $src,$id or croak("failed to open '$id': $!") unless $src; my $atyp = ref $src; $sep ||= $/; local $/ = $sep if $sep; $proto{out} ||= $\ || ''; my $out_sep = $proto{out}; my @contents; # Case 1: $src is string if (!$atyp) { @contents = split /(?=$sep)/,$src; } # Case 2: $src is arrayref elsif ($atyp eq 'ARRAY') { @contents = @$src; } # Case 3: $src is globref (file handle) elsif ($atyp eq 'GLOB') { @contents = <$src>; } # Case 4: $src is coderef - callback elsif ($atyp eq 'CODE') { while (my $item=&$src(@args)) { push @contents,$item; } } # Case otherwise is an error. else { croak "Invalid argument"; } $proto{last_line_short} = 1 if @contents && ($contents[-1] !~ /$sep$/); if ($proto{chomp}) { s/$sep$//s for @contents; $proto{out} ||= $sep; } bless { id => $id, contents => \@contents, separator => $sep, %proto },$class; } sub original { my $self = shift; my $pkg = ref $self; exists($self->{original}) ? bless ({ id => $self->id, contents => $self->{original}, separator => $self->{separator}, out => $self->{out}, chomp => $self->{chomp}, }, $pkg ) : $self; } sub apply { my ($self,$other,%par) = @_; my $pkg = ref $self; my $base = $par{base}; $base ||= 'contents'; $base = $pkg->new( $self->id, $self->{separator}, $self->{$base}) unless ref $base; my $cbase = exists($other->{original}) ? $other->original : $base; my $mrg = $cbase->merge($base,$other); my $mrg2 = $base->merge($self,$mrg); $self->{original} ||= $self->{contents}; $self->{contents} = [$mrg2->text]; } sub text { my ($self,$sep) = @_; $sep ||= $self->{out} || ''; wantarray ? @{$self->{contents}} : join $sep,@{$self->{contents}}; } sub id { my $self = shift; @_ ? ($self->{id} = shift) : $self->{id}; } sub delta { my $lite1 = shift; my $lite2 = shift; my %par = @_; my @wl1 = $lite1->_window($par{window}); my @wl2 = $lite2->_window($par{window}); my @d = map { [map { [$_->[0] . ($_->[2]{short} ? '/' : ''), $_->[1], $_->[2]{line} ] } @$_ ] } Algorithm::Diff::diff(\@wl1,\@wl2,sub { $_[0]{window}; }) or return undef; VCS::Lite::Delta->new(\@d,$lite1->id,$lite2->id,$lite1->{out}); } sub _window { my $self = shift; my $win = shift || 0; my ($win_from,$win_to) = ref($win) ? (-$win->[0],$win->[1]) : (-$win,$win); my @wintxt; my $max = $#{$self->{contents}}; for (0..$max) { my $win_lb = $_ + $win_from; $win_lb = 0 if $win_lb < 0; my $win_ub = $_ + $win_to; $win_ub = $max if $win_ub > $max; push @wintxt, join $self->{out}, (@{$self->{contents}}[$win_lb .. $win_ub], (($win_ub < $max) || !$self->{last_line_short}) ? '' : ()); } map { {line => $self->{contents}[$_], window => $wintxt[$_], ( $self->{last_line_short} && ($_ == $max)) ? ( short => 1 ) : (), } } (0..$max); } sub diff { my $self = shift; $self->delta(@_)->diff; } sub patch { my $self = shift; my $patch = shift; $patch = VCS::Lite::Delta->new($patch,@_) unless ref $patch eq 'VCS::Lite::Delta'; my @out = @{$self->{contents}}; my $id = $self->id; my $pkg = ref $self; my @pat = $patch->hunks; for (@pat) { for (@$_) { my ($ind,$lin,$txt) = @$_; next unless $ind =~ /^-/; _error($lin,'Patch failed'),return undef if $out[$lin] ne $txt; } } my $line_offset = 0; my $lls = 0; for (@pat) { my @txt1 = grep {$_->[0] =~ /^\-/} @$_; my @txt2 = grep {$_->[0] =~ /^\+/} @$_; my $base_line = @txt2 ? $txt2[0][1] : $txt1[0][1] + $line_offset; splice @out,$base_line,scalar(@txt1),map {$_->[2]} @txt2; $line_offset += @txt2 - @txt1; $lls += grep {$_->[0] eq '+/'} @txt2; } $pkg->new($id,{ in => $self->{separator}, chomp => $self->{chomp}, out => $self->{out}, last_line_short => $lls, },\@out); } # Equality of two array references (contents) sub _equal { my ($a,$b) = @_; return 0 if @$a != @$b; foreach (0..$#$a) { return 0 if $a->[$_] ne $b->[$_]; } 1; } sub merge { my ($self,$d1,$d2) = @_; my $pkg = ref $self; my $orig = [$self->text]; my $chg1 = [$d1->text]; my $chg2 = [$d2->text]; my $out_title = $d1->{id} . '|' . $d2->{id}; my %ins1; my $del1 = ''; traverse_sequences( $self->{contents}, $chg1, { MATCH => sub { $del1 .= ' ' }, DISCARD_A => sub { $del1 .= '-' }, DISCARD_B => sub { push @{$ins1{$_[0]}},$chg1->[$_[1]] }, } ); my %ins2; my $del2 = ''; traverse_sequences( $self->{contents}, $chg2, { MATCH => sub { $del2 .= ' ' }, DISCARD_A => sub { $del2 .= '-' }, DISCARD_B => sub { push @{$ins2{$_[0]}},$chg2->[$_[1]] }, } ); # First pass conflict detection: deletion on file 1 and insertion on file 2 $del1 =~ s(\-+){ my $stlin = length $`; my $numdel = length $&; my @confl = map {exists $ins2{$_} ? ($_) : ()} ($stlin+1..$stlin+$numdel-1); @confl ? '*' x $numdel : $&; }eg; # Now the other way round: deletion on file 2 and insertion on file 1 $del2 =~ s(\-+){ my $stlin = length $`; my $numdel = length $&; my @confl = map {exists $ins1{$_} ? ($_) : ()} ($stlin+1..$stlin+$numdel-1); @confl ? '*' x $numdel : $&; }eg; # Conflict type 1 is insert of 2 into deleted 1, Conflict type 2 is insert of 1 into deleted 2 # @defer is used to hold the 'other half' alternative for the conflict my $conflict = 0; my $conflict_type = 0; my @defer; my @out; for (0..@{$self->{contents}}) { # Get details pertaining to current @f0 input line my $line = $self->{contents}[$_]; my $d1 = substr $del1,$_,1; my $ins1 = $ins1{$_} if exists $ins1{$_}; my $d2 = substr $del2,$_,1; my $ins2 = $ins2{$_} if exists $ins2{$_}; # Insert/insert conflict. This is not a conflict if both inserts are identical. if ($ins1 && $ins2 && !&_equal($ins1,$ins2)) { push @out, ('*'x20)."Start of conflict ".(++$conflict). " Insert to Primary, Insert to Secondary ".('*'x60)."\n"; push @out, @$ins1, ('*'x100)."\n", @$ins2; push @out, ('*'x20)."End of conflict ".$conflict.('*'x80)."\n"; } elsif (!$conflict_type) { #Insert/Delete conflict # Normal insertion - may be from $ins1 or $ins2. Apply the inser and junk both $ins1 and $ins2 $ins1 ||= $ins2; push @out, @$ins1 if defined $ins1; undef $ins1; undef $ins2; } # Detect start of conflict 1 and 2 if (!$conflict_type && $d1 eq '*') { push @out, ('*'x20)."Start of conflict ".(++$conflict). " Delete from Primary, Insert to Secondary ".('*'x60)."\n"; $conflict_type = 1; } if (!$conflict_type && $d2 eq '*') { push @out, ('*'x20)."Start of conflict ".(++$conflict). " Delete from Secondary, Insert to Primary ".('*'x60)."\n"; $conflict_type = 2; } # Handle case where we are in an Insert/Delete conflict block already if ($conflict_type == 1) { if ($d1 eq '*') { # Deletion block continues... push @defer,(@$ins2) if $ins2; push @defer,$line if !$d2; } else { # handle end of block, dump out @defer and clear it push @out, ('*'x100)."\n",@defer; undef @defer; push @out, ('*'x20)."End of conflict ".$conflict.('*'x80)."\n"; $conflict_type = 0; } } if ($conflict_type == 2) { if ($d2 eq '*') { # Deletion block continues... push @defer,(@$ins1) if $ins1; push @defer,$line if !$d1; } else { # handle end of block, dump out @defer and clear it push @out, ('*'x100),"\n", @defer; undef @defer; push @out, ('*'x20)."End of conflict ".$conflict.('*'x80)."\n"; $conflict_type = 0; } } last unless defined $line; # for end of file, don't want to push undef push @out, $line unless ($d1 eq '-' || $d2 eq '-') && !$conflict_type; } $pkg->new($out_title, undef, \@out); } sub _error {}; 1; __END__ #---------------------------------------------------------------------------- =head1 API =head2 new The underlying storage concept of VCS::Lite is an array. The members of the array can be anything that a scalar can represent (including references to structures and objects). The default is for the object to hold an array of scalars as strings corresponding to lines of text. The basic form of the constructor is as follows: my $lite = VCS::Lite->new( '/my/file'); which slurps the file to make an object. The full form is as follows: my $lite = VCS::Lite->new( $object_id, $separation, $source, ...); =over 4 =item C<$object_id> This is a string to identify what is being diffed, patched or merged, in the application's environment. If there is no $source, this is used as a filename from which to read the content. =item C<$separation> This is an optional parameter, which can be used via $/ to split the input file into tokens. The default is for lines of text. If you pass in a string to be tokenized, this will use $sep as a regular expression $separation can be a scalar or scalar ref, where this is used to break up the input stream. All values permitted for $/ are allowed (see L). $separation can also be a hashref, to give a finer level of control. For example: { in => '\n', out => '\n', chomp => 1 } 'in' is the input record separator to use (the same as you would pass as $sep). Note that all values allowed for $/, and indeed the value of $/ passed in is what is used as a default. 'in' can be a string or a regexp. 'out' is the character used on joining the members to output the results (text method in scalar context). This is the output record separator $\. Note that 'out' defaults differently depening on the setting of 'chomp': if 'chomp' is off, 'out' will default to the empty string, or rather the passed in value of $\. If 'chomp' is on, 'out' will default to 'in' - note that you should specify 'out' explicitly if you are using a regexp for 'in'. If the 'chomp' flag is set, the text matching 'in' is removed from the input lines as they are read. 'chomp' is not on by default, as this is new functionality in release 0.08. =item C<$source> if unspecified causes $object_id to be opened as a file and its entire contents read in. The alternative is to supply $source, which can be one of the following: =over 4 =item C This is a string which is tokenized using $separation =item C Array of tokens =item C or C Contents of file are slurped =item C This is called successively to obtain tokens until received undef. =back =back In the Perl spirit of DWIM, new assumes that given an arrayref, you have already done all the work of making your list of whatevers. Given a string (filename) or a file handle, the file is slurped, reading each line of text into a member of the array. Given a callback, the routine is called successively with arguments $p1, $p2, etc. and is expected to return a scalar which is added (pushed on) to the array. =head2 apply $lite->apply($lite2); $lite->apply($lite3, base => 'original'); This method call corresponds approximately to a version control system's check-in function. This causes $lite to be modified, so that its contents now reflect those of $lite2. $lite does retain the original contents, available via L. However, unlike in a version control system, the object holds only the first original and latest contents. The VCS::Lite object passed in can also have its own original version. If this is the case, merging will be performed to incorporate the change as if it had come from a different branch. To facilitiate the merging process, optionally specify a base version, which can be the string 'original', 'contents' (the default) or a VCS::Lite object whose contents will be used. This corresponds to the "common ancestor" in version control systems. =head2 original This returns a VCS::Lite object for the original version, before changes were applied with apply. =head2 text my $foo = $lite->text; my $bar = $lit2->text('|'); my @baz = $lit3->text; In scalar context, returns the equivalent of the file contents slurped (the optional separation parameter, defaulting to $_, is used to join the strings together). In list context, returns the list of lines or records. =head2 id my $fil = $lite->id Returns the name associated with the VCS::Lite element when it was created by new. This is usually the file name. =head2 delta my $delt = $lit->delta($lit2); Perform the difference between two VCS::Lite objects. This object returns a L object. =head2 diff This is for backward compatibility with early versions. $lite->diff($lite2) is equivalent to $lite->delta($lite2)->diff. =head2 patch my $lit3 = $lit->patch($delt); Applies a patch to a VCS::Lite object. Accepts a file handle or file name string. Reads the file in diff format, and applies it. Returns a VCS::Lite object for the patched source. =head2 merge my $lit4 = $lit->merge($lit1,$lit2,\&confl); Performs the "parallelogram of merging". This applies two different change streams represented by VCS::Lite objects. Returns a VCS::Lite object with both sets of changes merged. The third parameter to the method is a sub which is called whenever a merge conflict occurs. This needs to either resolve the conflict or insert the necessary text to highlight the conflict. =head1 SEE ALSO L. =head1 BUGS, PATCHES & FIXES At the time of release there is one known bug within VCS-Lite: http://rt.cpan.org/Public/Bug/Display.html?id=20738 Unfortunately Ivor's original svn repository is no longer available, and any work which had done on fixing this bug has now been lost. As time allows I will review the examples and try to implement an appropriate solution. If you spot a bug or are experiencing difficulties that are not explained within the POD documentation, please send an email to barbie@cpan.org or submit a bug to the RT system (see link below). However, it would help greatly if you are able to pinpoint problems or even supply a patch. http://rt.cpan.org/Public/Dist/Display.html?Name=VCS-Lite Fixes are dependent upon their severity and my availability. Should a fix not be forthcoming, please feel free to (politely) remind me. =head1 AUTHOR Original Author: Ivor Williams (RIP) 2002-2009 Current Maintainer: Barbie 2009-2013 =head1 COPYRIGHT Copyright (c) Ivor Williams, 2002-2006 Copyright (c) Barbie, 2009-2013 =head1 LICENCE This distribution is free software; you can redistribute it and/or modify it under the Artistic Licence v2. =head1 ACKNOWLEDGEMENTS Colin Robertson for suggesting and providing patches for support of files with unterminated last lines. =cut VCS-Lite-0.10/lib/VCS/Lite/0000755000175000017500000000000012076757313014323 5ustar barbiebarbieVCS-Lite-0.10/lib/VCS/Lite/Delta.pm0000644000175000017500000003641112076757275015726 0ustar barbiebarbiepackage VCS::Lite::Delta; use strict; use warnings; our $VERSION = '0.10'; #---------------------------------------------------------------------------- =head1 NAME VCS::Lite::Delta - VCS::Lite differences =head1 SYNOPSIS use VCS::Lite; # diff my $lit = VCS::Lite->new('/home/me/foo1.txt'); my $lit2 = VCS::Lite->new('/home/me/foo2.txt'); my $difftxt = $lit->delta($lit2)->diff; print OUTFILE $difftxt; # patch my $delt = VCS::Lite::Delta->new('/home/me/patch.diff'); my $lit3 = $lit->patch($delt); print OUTFILE $lit3->text; =head1 DESCRIPTION This module provides a Delta class for the differencing functionality of VCS::Lite =cut #---------------------------------------------------------------------------- ############################################################################# #Library Modules # ############################################################################# use Carp; #---------------------------------------------------------------------------- # Error handling, use package vars to control it for now. use vars qw($error_action $error_msg $error_line); #---------------------------------------------------------------------------- ############################################################################# #Interface Methods # ############################################################################# sub new { my $class = shift; my $src = shift; # DWIM logic, based on $src parameter. # Case 0: string. Use $id as file name, becomes case 2 if ( !ref $src ) { open my $fh, $src or croak("failed to open '$src': $!"); $src = $fh; # becomes case 2 below } my $atyp = ref $src; # Case 1: $src is arrayref return bless { id1 => $_[0], id2 => $_[1], sep => $_[2], diff => [@$src] }, $class if $atyp eq 'ARRAY'; my $sep = shift; my %proto; # Decode $sep as needed if (ref($sep) eq 'HASH') { %proto = %$sep; $sep = $proto{in}; delete $proto{in}; } $sep ||= $/; local $/ = $sep if $sep; $sep ||= ''; my @diff; # Case 2: $src is globref (file handle) - slurp file if ( $atyp eq 'GLOB' ) { @diff = <$src>; } # Case 3: $src is scalar ref (string) elsif ( $atyp eq 'SCALAR' ) { @diff = split /(?=$sep)/, $$src; } # Case otherwise is an error. else { croak "Invalid argument to VCS::Lite::Delta::new"; } # If we have reached this point, we have been passed something in a # text/diff format. It could be diff or udiff format. my ( $id1, $id2 ) = @_; my @out; if ( $diff[0] =~ /^---/ ) { # udiff format my $state = 'inputdef'; my ( $a_line, $a_count, @a_hunk, $b_line, $b_count, @b_hunk ); for my $lin ( 0 .. $#diff ) { local $_ = $diff[$lin]; chomp if $proto{chomp}; # inputdef = --- and +++ to identify the files being diffed if ( $state eq 'inputdef' ) { $id1 = $1 if /^--- # --- \s (\S+)/x; # file => $1 $id2 = $1 if /^\+{3} # +++ \s (\S+)/x; # file => $1 $state = 'patch' if /^\@\@/; } # patch expects @@ -a,b +c,d @@ if ( $state eq 'patch' ) { next unless /^\@\@ \s+ - (\d+) # line of file 1 => $1 , (\d+) # count of file 1 => $2 \s* \+ (\d+) # line of file 2 => $3 , (\d+) # count of file 2 => $4 \s* \@\@/x; $a_line = $1 - 1; $a_count = $2; $b_line = $3 - 1; $b_count = $4; $state = 'detail'; next; } # detail expects [-+ ]line of text if ( $state eq 'detail' ) { my $ind = substr $_, 0, 1, ''; _error( $lin, 'Bad diff' ), return undef unless $ind =~ /[ +\-i\\]/; next if $ind eq '\\'; #[- ]line, add to @a_hunk if ( $ind ne '+' ) { my $lead = '-'; if (($lin < $#diff) && $diff[$lin+1] =~ /^\\/) { $lead .= '/'; s/$sep$//s; } push @a_hunk, [ $lead, $a_line++, $_ ]; $a_count--; _error( $lin, 'Too large diff' ), return undef if $a_count < 0; } #[+ ]line, add to @b_hunk if ( $ind ne '-' ) { my $lead = '+'; if (($lin < $#diff) && $diff[$lin+1] =~ /^\\/) { $lead .= '/'; s/$sep$//s; } push @b_hunk, [ $lead, $b_line++, $_ ]; $b_count--; _error( $lin, 'Too large diff' ), return undef if $b_count < 0; } # are we there yet, daddy? if ( !$a_count and !$b_count ) { push @out, [ @a_hunk, @b_hunk ]; @a_hunk = @b_hunk = (); $state = 'patch'; } } } # next line of patch return bless { id1 => $id1, id2 => $id2, sep => $sep, diff => \@out, %proto }, $class; } # not a udiff mode patch, assume straight diff mode my $state = 'patch'; my ( $a_line, $a_count, @a_hunk, $b_line, $b_count, @b_hunk ); for my $lin ( 0 .. $#diff ) { local $_ = $diff[$lin]; chomp if $proto{chomp}; # patch expects ww,xx[acd]yy,zz style if ( $state eq 'patch' ) { next unless /^(\d+) # start line of file 1 => $1 (?:,(\d+))? # end line of file 1 => $2 ([acd]) # Add, change, delete => $3 (\d+) # start line of file 2 => $4 (?:,(\d+))? # end line of file 2 => $5 /x; $a_line = $1 - 1; $a_count = $2 ? ( $2 - $a_line ) : 1; $b_line = $4 - 1; $b_count = $5 ? ( $5 - $b_line ) : 1; $a_count = 0 if $3 eq 'a'; $b_count = 0 if $3 eq 'd'; $state = 'detail'; next; } # detail expects < lines --- > lines if ( $state eq 'detail' ) { next if /^---/; # ignore separator my $ind = substr $_, 0, 2, ''; _error( $lin, 'Bad diff' ), return undef unless $ind =~ /[<>\\] /; # < line goes to @a_hunk if ( $ind eq '< ' ) { my $lead = '-'; if (($lin < $#diff) && $diff[$lin+1] =~ /^\\/) { $lead .= '/'; s/$sep$//s; } push @a_hunk, [ $lead, $a_line++, $_ ]; $a_count--; _error( $lin, 'Too large diff' ), return undef if $a_count < 0; } # > line goes to @b_hunk if ( $ind eq '> ' ) { my $lead = '+'; if (($lin < $#diff) && $diff[$lin+1] =~ /^\\/) { $lead .= '/'; s/$sep$//s; } push @b_hunk, [ $lead, $b_line++, $_ ]; $b_count--; _error( $lin, 'Too large diff' ), return undef if $b_count < 0; } # are we there yet, daddy? if ( !$a_count and !$b_count ) { push @out, [ @a_hunk, @b_hunk ]; @a_hunk = @b_hunk = (); $state = 'patch'; } } } return bless { id1 => $id1, id2 => $id2, sep => $sep, diff => \@out, %proto }, $class; } sub _error { ( $error_line, my $msg ) = @_; $error_msg = "Line $error_line: $msg"; goto &$error_action if ref($error_action) eq 'CODE'; confess $error_msg if $error_action eq 'raise'; print STDERR $error_msg, "\n" unless $error_action eq 'silent'; } sub _diff_hunk { my $sep = shift; my $r_line_offset = shift; my @ins; my ( $ins_firstline, $ins_lastline ) = ( 0, 0 ); my @del; my ( $del_firstline, $del_lastline ) = ( 0, 0 ); my $op; my $shortins = ''; my $shortdel = ''; # construct @ins and @del from hunk for (@_) { my ( $typ, $lno, $txt ) = @$_; my $short = substr($typ, 1, 1, ''); $lno++; if ( $typ eq '+' ) { push @ins, $txt; $ins_firstline ||= $lno; $ins_lastline = $lno; $shortins = "\n\\ No newline at end of file\n" if $short; } else { push @del, $txt; $del_firstline ||= $lno; $del_lastline = $lno; $shortdel = "\n\\ No newline at end of file\n" if $short; } } # Work out whether we are a, c or d if ( !@del ) { $op = 'a'; $del_firstline = $ins_firstline - $$r_line_offset - 1; } elsif ( !@ins ) { $op = 'd'; $ins_firstline = $del_firstline + $$r_line_offset - 1; } else { $op = 'c'; } $$r_line_offset += @ins - @del; $ins_lastline ||= $ins_firstline; $del_lastline ||= $del_firstline; # Make the header line my $outstr = "$del_firstline,$del_lastline$op$ins_firstline,$ins_lastline\n"; $outstr =~ s/(^|\D)(\d+),\2(?=\D|$)/$1$2/g; # < deletions for (@del) { $outstr .= '< ' . $_ . $sep; } $outstr .= $shortdel; # --- $outstr .= "---\n" if @ins && @del; # > insertions for (@ins) { $outstr .= '> ' . $_ . $sep; } $outstr .= $shortins; $outstr; } sub diff { my $self = shift; my $sep = shift || $self->{sep} || ''; my $off = 0; join '', map { _diff_hunk( $sep, \$off, @$_ ) } @{ $self->{diff} }; } sub udiff { my $self = shift; my $sep = shift || $self->{sep} || ''; my ( $in, $out, $diff ) = @{$self}{qw/id1 id2 diff/}; # Header with file names my @out = ( "--- $in \n", "+++ $out \n" ); my $offset = 0; for (@$diff) { my @t1 = grep { $_->[0] =~ /^\-/ } @$_; my @t2 = grep { $_->[0] =~ /^\+/ } @$_; my $short1 = ''; $short1 = "\n\\ No newline at end of file\n" if grep { $_->[0] eq '-/' } @t1; my $short2 = ''; $short2 = "\n\\ No newline at end of file\n" if grep { $_->[0] eq '+/' } @t2; # Work out base line numbers in both files my $base1 = @t1 ? $t1[0][1] : $t2[0][1] - $offset; my $base2 = @t2 ? $t2[0][1] : $t1[0][1] + $offset; $base1++; $base2++; # Our lines were 0 based $offset += @t2 - @t1; my $count1 = @t1; my $count2 = @t2; # Header line push @out, "@@ -$base1,$count1 +$base2,$count2 @@\n"; # Use Algorithm::Diff::sdiff to munge out any lines in common inside # the hunk my @txt1 = map { $_->[2] } @t1; my @txt2 = map { $_->[2] } @t2; my @ad = Algorithm::Diff::sdiff( \@txt1, \@txt2 ); my @defer; # for each subhunk, we want all the file1 lines first, then all the file2 lines for (@ad) { my ( $ind, $txt1, $txt2 ) = @$_; # we want to flush out the + lines when we run off the end of a 'c' section ( push @out, @defer ), @defer = () unless $ind eq 'c'; # unchanged lines, just wack 'em out ( push @out, ' ' . $txt1 . $sep ), next if $ind eq 'u'; # output original line (- line) push @out, '-' . $txt1 . $sep unless $ind eq '+'; # defer changed + lines push @defer, '+' . $txt2 . $sep unless $ind eq '-'; } push @out, $short1; # and flush at the end push @out, @defer, $short2; } wantarray ? @out : join '', @out; } sub id { my $self = shift; if (@_) { $self->{id1} = shift; $self->{id2} = shift; } @{$self}{qw/id1 id2/}; } sub hunks { my $self = shift; @{ $self->{diff} }; } 1; __END__ #---------------------------------------------------------------------------- =head1 API =head2 new The underlying object of VCS::Lite::Delta is an array of difference chunks (hunks) such as that returned by Algorithm::Diff. The constructor takes the following forms: my $delt = VCS::Lite::Delta->new( '/my/file.diff',$sep); # File name my $delt = VCS::Lite::Delta->new( \*FILE,$sep); # File handle my $delt = VCS::Lite::Delta->new( \$string,$sep); # String as scalar ref my $delt = VCS::Lite::Delta->new( \@foo, $id1, $id2) # Array ref $sep here is a regexp by which to split strings into tokens. The default is to use the natural perl mechanism of $/ (which is emulated when not reading from a file). The arrayref form is assuming an array of hunks such as the output from L. The other forms assume the input is the text form of a diff listing, either in diff format, or in unified format. The input is parsed, and errors are reported. =head2 diff print OUTFILE $delt->diff This generates a standard diff format, for example: 4c4 < Now wherefore stopp'st thou me? --- > Now wherefore stoppest thou me? =head2 udiff print OUTFILE $delt->udiff This generates a unified diff (like diff -u) similar to the form in which patches are submitted. =head2 id my ($id1,$id2) = $delt->id; $delt2->id('foo.pl@@1','foo.pl@@3') The I method allows get and set of the names associated with the two elements being diffed. The id is set for delta objects returned by VCS::Lite->diff, to the element IDs of the VCS::Lite objects being diffed. Diff format omits the file names, hence the IDs will not be populated by new. This is not the case with diff -u format, which includes the file names which are passed in and available as IDs. =head2 hunks my @hunklist = $delt->hunks A hunk is a technical term for a section of input containing a difference. Each hunk is an arrayref, containing the block of lines. Each line is itself an arrayref, for example: [ [ '+', 9, 'use Acme::Foo;'], [ '-', 9, 'use Acme::Bar;'], ] See the documentation on L for more details of this structure. =head1 SEE ALSO L. =head1 BUGS, PATCHES & FIXES There are no known bugs at the time of this release. However, if you spot a bug or are experiencing difficulties that are not explained within the POD documentation, please send an email to barbie@cpan.org or submit a bug to the RT system (see link below). However, it would help greatly if you are able to pinpoint problems or even supply a patch. http://rt.cpan.org/Public/Dist/Display.html?Name=VCS-Lite Fixes are dependent upon their severity and my availability. Should a fix not be forthcoming, please feel free to (politely) remind me. =head1 AUTHOR Original Author: Ivor Williams (RIP) 2002-2009 Current Maintainer: Barbie 2009-2013 =head1 COPYRIGHT Copyright (c) Ivor Williams, 2002-2006 Copyright (c) Barbie, 2009-2013 =head1 LICENCE This distribution is free software; you can redistribute it and/or modify it under the Artistic Licence v2. =cut VCS-Lite-0.10/data/0000755000175000017500000000000012076757313013136 5ustar barbiebarbieVCS-Lite-0.10/data/marinery.txt0000644000175000017500000000537612076757276015550 0ustar barbiebarbieHere is the first part of Coleridge's "Rime of the Ancient Mariner" There are no copyright issues as this text is in the public domain It is an ancient Mariner, And he stoppeth one of three. <> He holds him with his skinny hand, <> quoth he. <> Eftsoons his hand dropt he. He holds him with his glittering eye-- The Wedding-Guest stood still, And listens like a three years child: The Mariner hath his will. The Wedding-Guest sat on a stone: He cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. The ship was cheered, the harbour cleared, Merrily did we drop Below the kirk, below the hill, Below the light-house top. The Sun came up upon the left, Out of the sea came he! And he shone bright, and on the right Went down into the sea. Higher and higher every day, Till over the mast at noon-- The Wedding-Guest here beat his breast, For he heard the loud bassoon. The bride hath paced into the hall, Red as a rose is she; Nodding their heads before her goes The merry minstrelsy. The Wedding-Guest he beat his breast, Yet he cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. And now the STORM-BLAST came, and he Was tyrannous and strong: He struck with his o'ertaking wings, And chased south along. With sloping masts and dipping prow, As who pursued with yell and blow Still treads the shadow of his foe And forward bends his head, The ship drove fast, loud roared the blast, And southward aye we fled. And now there came both mist and snow, And it grew wondrous cold: And ice, mast-high, came floating by, As green as emerald. And through the drifts the snowy clifts Did send a dismal sheen: Nor shapes of men nor beasts we ken-- The ice was all between. The ice was here, the ice was there, The ice was all around: It cracked and growled, and roared and howled, Like noises in a swound! At length did cross an Albatross: Thorough the fog it came; As if it had been a Christian soul, We hailed it in God's name. It ate the food it ne'er had eat, And round and round it flew. The ice did split with a thunder-fit; The helmsman steered us through! And a good south wind sprung up behind; The Albatross did follow, And every day, for food or play, Came to the mariners' hollo! In mist or cloud, on mast or shroud, It perched for vespers nine; Whiles all the night, through fog-smoke white, Glimmered the white Moon-shine. <>--With my cross-bow I shot the B. VCS-Lite-0.10/data/snarkab.udif0000644000175000017500000000043412076757275015440 0ustar barbiebarbie--- data/snarka.txt +++ data/snarkb.txt @@ -2,1 +2,1 @@ - As he landed his crew with care; + As he landed his crew with care; @@ -4,1 +4,1 @@ - By a finger entwined in his hair. \ No newline at end of file + By a finger entwined in his hair. \ No newline at end of file VCS-Lite-0.10/data/marinery.dif0000644000175000017500000000146612076757275015466 0ustar barbiebarbie0a1,3 > Here is the first part of Coleridge's "Rime of the Ancient Mariner" > There are no copyright issues as this text is in the public domain > 3c6 < "By thy long grey beard and glittering eye, --- > < < May'st hear the merry din.>> 12,13c15,16 < "There was a ship," quoth he. < "Hold off! unhand me, grey-beard loon!" --- > <> quoth he. > <> 98c101 < "God save thee, ancient Mariner! --- > < Why look'st thou so?>>--With my cross-bow > I shot the B. VCS-Lite-0.10/data/marinerx.dif0000644000175000017500000000066712076757275015467 0ustar barbiebarbie4c4 < Now wherefore stopp'st thou me? --- > Now wherefore stoppest thou me? 21,25d20 < The Wedding-Guest sat on a stone: < He cannot chuse but hear; < And thus spake on that ancient man, < The bright-eyed Mariner. < 37a33 > Wondering about the wretched loon 95,96c91,92 < Whiles all the night, through fog-smoke white, < Glimmered the white Moon-shine. --- > While all the night, through fog-smoke white, > Glimmered the white Moonshine. VCS-Lite-0.10/data/mariner.txt0000644000175000017500000000515212076757275015346 0ustar barbiebarbieIt is an ancient Mariner, And he stoppeth one of three. "By thy long grey beard and glittering eye, Now wherefore stopp'st thou me? "The Bridegroom's doors are opened wide, And I am next of kin; The guests are met, the feast is set: May'st hear the merry din." He holds him with his skinny hand, "There was a ship," quoth he. "Hold off! unhand me, grey-beard loon!" Eftsoons his hand dropt he. He holds him with his glittering eye-- The Wedding-Guest stood still, And listens like a three years child: The Mariner hath his will. The Wedding-Guest sat on a stone: He cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. The ship was cheered, the harbour cleared, Merrily did we drop Below the kirk, below the hill, Below the light-house top. The Sun came up upon the left, Out of the sea came he! And he shone bright, and on the right Went down into the sea. Higher and higher every day, Till over the mast at noon-- The Wedding-Guest here beat his breast, For he heard the loud bassoon. The bride hath paced into the hall, Red as a rose is she; Nodding their heads before her goes The merry minstrelsy. The Wedding-Guest he beat his breast, Yet he cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. And now the STORM-BLAST came, and he Was tyrannous and strong: He struck with his o'ertaking wings, And chased south along. With sloping masts and dipping prow, As who pursued with yell and blow Still treads the shadow of his foe And forward bends his head, The ship drove fast, loud roared the blast, And southward aye we fled. And now there came both mist and snow, And it grew wondrous cold: And ice, mast-high, came floating by, As green as emerald. And through the drifts the snowy clifts Did send a dismal sheen: Nor shapes of men nor beasts we ken-- The ice was all between. The ice was here, the ice was there, The ice was all around: It cracked and growled, and roared and howled, Like noises in a swound! At length did cross an Albatross: Thorough the fog it came; As if it had been a Christian soul, We hailed it in God's name. It ate the food it ne'er had eat, And round and round it flew. The ice did split with a thunder-fit; The helmsman steered us through! And a good south wind sprung up behind; The Albatross did follow, And every day, for food or play, Came to the mariners' hollo! In mist or cloud, on mast or shroud, It perched for vespers nine; Whiles all the night, through fog-smoke white, Glimmered the white Moon-shine. "God save thee, ancient Mariner! From the fiends, that plague thee thus!-- Why look'st thou so?"--With my cross-bow I shot the ALBATROSS. VCS-Lite-0.10/data/snarkab.dif0000644000175000017500000000034612076757275015255 0ustar barbiebarbie2c2 < As he landed his crew with care; --- > As he landed his crew with care; 4c4 < By a finger entwined in his hair. \ No newline at end of file --- > By a finger entwined in his hair. \ No newline at end of file VCS-Lite-0.10/data/snarkb.txt0000644000175000017500000000024412076757276015167 0ustar barbiebarbie"Just the place for a Snark!" the Bellman cried, As he landed his crew with care; Supporting each man on the top of the tide By a finger entwined in his hair.VCS-Lite-0.10/data/marinerx.txt0000644000175000017500000000502012076757275015530 0ustar barbiebarbieIt is an ancient Mariner, And he stoppeth one of three. "By thy long grey beard and glittering eye, Now wherefore stoppest thou me? "The Bridegroom's doors are opened wide, And I am next of kin; The guests are met, the feast is set: May'st hear the merry din." He holds him with his skinny hand, "There was a ship," quoth he. "Hold off! unhand me, grey-beard loon!" Eftsoons his hand dropt he. He holds him with his glittering eye-- The Wedding-Guest stood still, And listens like a three years child: The Mariner hath his will. The ship was cheered, the harbour cleared, Merrily did we drop Below the kirk, below the hill, Below the light-house top. The Sun came up upon the left, Out of the sea came he! And he shone bright, and on the right Went down into the sea. Higher and higher every day, Till over the mast at noon-- Wondering about the wretched loon The Wedding-Guest here beat his breast, For he heard the loud bassoon. The bride hath paced into the hall, Red as a rose is she; Nodding their heads before her goes The merry minstrelsy. The Wedding-Guest he beat his breast, Yet he cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. And now the STORM-BLAST came, and he Was tyrannous and strong: He struck with his o'ertaking wings, And chased south along. With sloping masts and dipping prow, As who pursued with yell and blow Still treads the shadow of his foe And forward bends his head, The ship drove fast, loud roared the blast, And southward aye we fled. And now there came both mist and snow, And it grew wondrous cold: And ice, mast-high, came floating by, As green as emerald. And through the drifts the snowy clifts Did send a dismal sheen: Nor shapes of men nor beasts we ken-- The ice was all between. The ice was here, the ice was there, The ice was all around: It cracked and growled, and roared and howled, Like noises in a swound! At length did cross an Albatross: Thorough the fog it came; As if it had been a Christian soul, We hailed it in God's name. It ate the food it ne'er had eat, And round and round it flew. The ice did split with a thunder-fit; The helmsman steered us through! And a good south wind sprung up behind; The Albatross did follow, And every day, for food or play, Came to the mariners' hollo! In mist or cloud, on mast or shroud, It perched for vespers nine; While all the night, through fog-smoke white, Glimmered the white Moonshine. "God save thee, ancient Mariner! From the fiends, that plague thee thus!-- Why look'st thou so?"--With my cross-bow I shot the ALBATROSS. VCS-Lite-0.10/data/snarka.txt0000644000175000017500000000025012076757275015162 0ustar barbiebarbie"Just the place for a Snark!" the Bellman cried, As he landed his crew with care; Supporting each man on the top of the tide By a finger entwined in his hair.VCS-Lite-0.10/data/marinerz.txt0000644000175000017500000000515312076757275015541 0ustar barbiebarbieIt is an ancient Mariner, And he stoppeth one of three. "By thy long grey beard and glittering eye, Now wherefore stopp'st thou me? "The Bridegroom's doors are opened wide, And I am next of kin; The guests are met, the feast is set: May'st hear the merry din." He holds him with his skinny hand, "There was a ship," quoth he. "Hold off! unhand me, grey-beard loon!" Eftsoons his hand dropt he. He holds him with his glittering eye-- The Wedding-Guest stood still, And listens like a three years child: The Mariner hath his will. The Wedding-Guest sat on a stone: He cannot choose but hear; And thus spoke on that ancient man, The bright-eyed Mariner. The ship was cheered, the harbour cleared, Merrily did we drop Below the kirk, below the hill, Below the light-house top. The Sun came up upon the left, Out of the sea came he! And he shone bright, and on the right Went down into the sea. Higher and higher every day, Till over the mast at noon-- The Wedding-Guest here beat his breast, For he heard the loud bassoon. The bride hath paced into the hall, Red as a rose is she; Nodding their heads before her goes The merry minstrelsy. The Wedding-Guest he beat his breast, Yet he cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. And now the STORM-BLAST came, and he Was tyrannous and strong: He struck with his o'ertaking wings, And chased south along. With sloping masts and dipping prow, As who pursued with yell and blow Still treads the shadow of his foe And forward bends his head, The ship drove fast, loud roared the blast, And southward aye we fled. And now there came both mist and snow, And it grew wondrous cold: And ice, mast-high, came floating by, As green as emerald. And through the drifts the snowy clifts Did send a dismal sheen: Nor shapes of men nor beasts we ken-- The ice was all between. The ice was here, the ice was there, The ice was all around: It cracked and growled, and roared and howled, Like noises in a swound! At length did cross an Albatross: Thorough the fog it came; As if it had been a Christian soul, We hailed it in God's name. It ate the food it ne'er had eat, And round and round it flew. The ice did split with a thunder-fit; The helmsman steered us through! And a good south wind sprung up behind; The Albatross did follow, And every day, for food or play, Came to the mariners' hollo! In mist or cloud, on mast or shroud, It perched for vespers nine; Whiles all the night, through fag-smoke white, Glimmered the white Moon-shine. "God save thee, ancient Mariner! From the fiends, that plague thee thus!-- Why look'st thou so?"--With my cross-bow I shot the ALBATROSS. VCS-Lite-0.10/data/marinerx.udif0000644000175000017500000000210612076757276015643 0ustar barbiebarbie--- data/mariner.txt +++ data/marinerx.txt @@ -1,7 +1,7 @@ It is an ancient Mariner, And he stoppeth one of three. "By thy long grey beard and glittering eye, -Now wherefore stopp'st thou me? +Now wherefore stoppest thou me? "The Bridegroom's doors are opened wide, And I am next of kin; @@ -18,10 +18,5 @@ And listens like a three years child: The Mariner hath his will. -The Wedding-Guest sat on a stone: -He cannot chuse but hear; -And thus spake on that ancient man, -The bright-eyed Mariner. - The ship was cheered, the harbour cleared, Merrily did we drop @@ -35,6 +30,7 @@ Higher and higher every day, Till over the mast at noon-- +Wondering about the wretched loon The Wedding-Guest here beat his breast, For he heard the loud bassoon. @@ -92,8 +88,8 @@ In mist or cloud, on mast or shroud, It perched for vespers nine; -Whiles all the night, through fog-smoke white, -Glimmered the white Moon-shine. +While all the night, through fog-smoke white, +Glimmered the white Moonshine. "God save thee, ancient Mariner! From the fiends, that plague thee thus!-- VCS-Lite-0.10/data/marinerx1.udif0000644000175000017500000000076712076757276015737 0ustar barbiebarbie--- data/mariner.txt +++ data/marinerx.txt @@ -4,1 +4,1 @@ -Now wherefore stopp'st thou me? +Now wherefore stoppest thou me? @@ -21,5 +21,0 @@ -The Wedding-Guest sat on a stone: -He cannot chuse but hear; -And thus spake on that ancient man, -The bright-eyed Mariner. - @@ -38,0 +33,1 @@ +Wondering about the wretched loon @@ -95,2 +91,2 @@ -Whiles all the night, through fog-smoke white, -Glimmered the white Moon-shine. +While all the night, through fog-smoke white, +Glimmered the white Moonshine. VCS-Lite-0.10/data/marinerxy.txt0000644000175000017500000000524412076757275015731 0ustar barbiebarbieHere is the first part of Coleridge's "Rime of the Ancient Mariner" There are no copyright issues as this text is in the public domain It is an ancient Mariner, And he stoppeth one of three. <> He holds him with his skinny hand, <> quoth he. <> Eftsoons his hand dropt he. He holds him with his glittering eye-- The Wedding-Guest stood still, And listens like a three years child: The Mariner hath his will. The ship was cheered, the harbour cleared, Merrily did we drop Below the kirk, below the hill, Below the light-house top. The Sun came up upon the left, Out of the sea came he! And he shone bright, and on the right Went down into the sea. Higher and higher every day, Till over the mast at noon-- Wondering about the wretched loon The Wedding-Guest here beat his breast, For he heard the loud bassoon. The bride hath paced into the hall, Red as a rose is she; Nodding their heads before her goes The merry minstrelsy. The Wedding-Guest he beat his breast, Yet he cannot chuse but hear; And thus spake on that ancient man, The bright-eyed Mariner. And now the STORM-BLAST came, and he Was tyrannous and strong: He struck with his o'ertaking wings, And chased south along. With sloping masts and dipping prow, As who pursued with yell and blow Still treads the shadow of his foe And forward bends his head, The ship drove fast, loud roared the blast, And southward aye we fled. And now there came both mist and snow, And it grew wondrous cold: And ice, mast-high, came floating by, As green as emerald. And through the drifts the snowy clifts Did send a dismal sheen: Nor shapes of men nor beasts we ken-- The ice was all between. The ice was here, the ice was there, The ice was all around: It cracked and growled, and roared and howled, Like noises in a swound! At length did cross an Albatross: Thorough the fog it came; As if it had been a Christian soul, We hailed it in God's name. It ate the food it ne'er had eat, And round and round it flew. The ice did split with a thunder-fit; The helmsman steered us through! And a good south wind sprung up behind; The Albatross did follow, And every day, for food or play, Came to the mariners' hollo! In mist or cloud, on mast or shroud, It perched for vespers nine; While all the night, through fog-smoke white, Glimmered the white Moonshine. <>--With my cross-bow I shot the B. VCS-Lite-0.10/Changes0000644000175000017500000000413612076757275013533 0ustar barbiebarbieRevision history for Perl extension VCS::Lite. 0.10 2013-01-20 - change file dates changed to meet W3CDTF standards. - License updated to Artistic License v2.0. - added minimum perl version (5.006). - reworked Makefile.PL for clarity. - added LICENSE & META.json files. - updated test suite. - updated README file. - added VCS::Lite::Delta to META files. 0.09 2009-08-17 - new maintainer, Barbie, due to the untimely death of Ivor Williams. - updated documentation - added more tests 0.08 2006-02-22 - Rationalise end of line termination. Allow passing in a hashref for $sep implement chomp mode. - Add support for diff and patch of files with an unterminated last line. 0.07 2003-04-03 - Fix script errors in vldiff.pl and vlpatch.pl - Lose the .pl in the script names. - Add apply method to VCS::Lite, which provides an anternative interface to merging. 0.06 2004-12-29T10:05:12 - Change underlying object type to be a hash. - Implement windowing of diffs. - Distribute vldiff,vlpatch and vlmerge as exe_files. 0.05 2003-12-14T15:00:16 - Resolve bugs reported on RT by removing merge method in VCS::Lite::Delta and references to it. Remove merge.t, keep merge1.t this eliminates the todo tests. - Provide and document API calls VCS::Lite->id, VCS::Lite::Delta->id and VCS::Lite::Delta->hunks. 0.04 2003-04-20T08:54:27 - Redesign of API - split of module into VCS::Lite and VCS::Lite::Delta - vldiff.pl, vlpatch.pl and vlmerge.pl scripts included in kit - udiff (diff -u) capability added - merge using new api incomplete (old merge still available) 0.03 0000-00-00 - Patched version supplied by Reuben Thomas 0.02 2002-12-18T16:05:23 - Original manifest was incomplete. This was uploaded to PAUSE 0.01 2002-12-16T14:03:18 - original version; created by h2xs 1.21 with options -AX -n VCS::Lite VCS-Lite-0.10/MANIFEST0000644000175000017500000000100212076757275013356 0ustar barbiebarbieChanges data/mariner.txt data/marinerx.dif data/marinerx.txt data/marinerx.udif data/marinerx1.udif data/marinerxy.txt data/marinery.dif data/marinery.txt data/marinerz.txt data/snarka.txt data/snarkab.dif data/snarkab.udif data/snarkb.txt lib/VCS/Lite.pm lib/VCS/Lite/Delta.pm LICENSE Makefile.PL MANIFEST META.json META.yml README scripts/vldiff scripts/vlmerge scripts/vlpatch t/01load.t t/10diff.t t/20merge.t t/21merge.t t/30patch.t t/90podtest.t t/91podcover.t t/94metatest.t t/95changedate.t t/96metatest.t VCS-Lite-0.10/META.yml0000644000175000017500000000163712076757275013514 0ustar barbiebarbie--- #YAML:1.0 name: VCS-Lite version: 0.10 abstract: A minimal version control system author: - Barbie license: artistic_2 distribution_type: module installdirs: site requires: perl: 5.006 Algorithm::Diff: 1.13 Carp: 0 Getopt::Long: 0 recommends: Test::CPAN::Meta: 0 Test::CPAN::Meta::JSON: 0 Test::Pod: 1.00 Test::Pod::Coverage: 0.08 build_requires: IO::File: 0 Test::More: 0.70 provides: VCS::Lite: file: lib/VCS/Lite.pm version: 0.10 VCS::Lite::Delta: file: lib/VCS/Lite/Delta.pm version: 0.10 no_index: directory: - t - examples meta-spec: version: 1.4 url: http://module-build.sourceforge.net/META-spec-v1.4.html generated_by: Hand 1.0 VCS-Lite-0.10/META.json0000644000175000017500000000275712076757275013670 0ustar barbiebarbie{ "name": "VCS-Lite", "version": "0.10", "abstract": "A minimal version control system", "author": ["Barbie "], "license": "artistic_2", "dynamic_config" : 0, "release_status" : "stable", "meta-spec": { "version": "2", "url": "http://search.cpan.org/dist/CPAN-Meta/lib/CPAN/Meta/Spec.pm" }, "generated_by": "Hand 1.0", "keywords" : [ "version control" ], "prereqs" : { "runtime" : { "requires" : { "perl": "5.006", "Algorithm::Diff": "1.13", "Carp": "0", "Getopt::Long": "0" } }, "test" : { "requires": { "IO::File": "0", "Test::More": "0.70" }, "recommends": { "Test::CPAN::Meta": "0", "Test::CPAN::Meta::JSON": "0", "Test::Pod": "1.00", "Test::Pod::Coverage": "0.08" } } }, "provides": { "VCS::Lite": { "file": "lib/VCS/Lite.pm", "version": "0.10" }, "VCS::Lite::Delta": { "file": "lib/VCS/Lite/Delta.pm", "version": "0.10" } }, "no_index": { "directory": ["t","examples"] }, "resources": { "license": "http://dev.perl.org/licenses/", "bugtracker": { "web": "http://rt.cpan.org/Public/Dist/Display.html?Name=VCS-Lite" } } } VCS-Lite-0.10/scripts/0000755000175000017500000000000012076757313013714 5ustar barbiebarbieVCS-Lite-0.10/scripts/vlmerge0000644000175000017500000000123412076757275015307 0ustar barbiebarbie#!/usr/bin/perl use strict; use warnings; use VCS::Lite; use Getopt::Long; my $output; GetOptions( 'output=s' => \$output ); if (@ARGV != 3) { print <new($orig); my $el2 = VCS::Lite->new($chg1); my $el3 = VCS::Lite->new($chg2); my $el4 = $el1->merge($el2,$el3) or die "Merge failed"; if (!$output) { rename $orig, "$orig.orig"; $output = $orig; } open MERGE,">$output"; print MERGE $el4->text; close MERGE; VCS-Lite-0.10/scripts/vlpatch0000644000175000017500000000142112076757275015305 0ustar barbiebarbie#!/usr/bin/perl use strict; use warnings; use Getopt::Long; my $output; GetOptions( 'output=s' => \$output, ); if (!@ARGV) { print <new($orig); my $dt1 = VCS::Lite::Delta->new($patsrc,undef,$orig,$pat); my $chg = $el1->patch($dt1) or die "Patch failed"; if (!$output) { rename $orig, "$orig.orig"; $output = $orig; } open PAT,">$output" or die "Failed to write output, $!"; print PAT $chg->text; close PAT; VCS-Lite-0.10/scripts/vldiff0000644000175000017500000000133512076757275015122 0ustar barbiebarbie#!/usr/bin/perl use strict; use warnings; use VCS::Lite; use Getopt::Long; my $uflag = 0; my $wintxt = ''; GetOptions( 'unified+' => \$uflag, 'window=s' => \$wintxt, ); if (@ARGV != 2) { print <new(shift @ARGV); my $el2 = VCS::Lite->new(shift @ARGV); my $win = 0; if ($wintxt =~ /(\d+),(\d+)/) { $win = [$1,$2]; } elsif ($wintxt =~ /(\d+)/) { $win = $1; } my $dt1 = $el1->delta($el2, window => $win); my $diff = $uflag ? $dt1->udiff : $dt1->diff; print $diff; VCS-Lite-0.10/LICENSE0000644000175000017500000000034312076757275013241 0ustar barbiebarbieLICENSE FOR VCS::Lite Copyright © 2002-2009 Ivor Williams Copyright © 2009-2013 Barbie for Miss Barbell Productions. This distribution is free software; you can redistribute it and/or modify it under the Artistic Licence v2. VCS-Lite-0.10/Makefile.PL0000644000175000017500000000130512076757275014205 0ustar barbiebarbie#!/usr/bin/perl use strict; use warnings; use 5.006; use ExtUtils::MakeMaker; WriteMakefile( AUTHOR => 'Barbie ', NAME => 'VCS::Lite', VERSION_FROM => 'lib/VCS/Lite.pm', ABSTRACT => 'A minimal version control system', NO_META => 1, PREREQ_PM => { # prereqs 'Algorithm::Diff' => '1.13', 'Carp' => '0', 'Getopt::Long' => '0', # required by installed scripts # build/test prereqs 'IO::File' => '0', 'Test::More' => '0.70' }, EXE_FILES => [qw(scripts/vldiff scripts/vlpatch scripts/vlmerge)] ); VCS-Lite-0.10/README0000644000175000017500000000367712076757275013131 0ustar barbiebarbieVCS-Lite ======== DESCRIPTION This module provides the functions normally associated with a version control system, but without needing or implementing a version control system. Applications include wikis, document management systems and configuration management. It makes use of the module Algorithm::Diff. It provides the facility for basic diffing, patching and merging. UPGRADING Note that the underlying object type has changed from an ARRAY to a HASH. DEPENDENCIES The distribution requires the following modules: Algorithm::Diff (version 1.13 or later) Carp Getopt::Long For testing purposes, the following modules are desirable, but not essential: Pod::Coverage Test::CPAN::Meta Test::CPAN::Meta::JSON Test::Pod Test::Pod::Coverage INSTALLATION To install this module type the following: perl Makefile.PL make make test make install If you are on a windows box you should use 'nmake' rather than 'make'. SCRIPTS This module puts in place vldiff.pl, vlpatch.pl and vlmerge.pl. BUGS, PATCHES & FIXES There are no known bugs at the time of this release. However, if you spot a bug or are experiencing difficulties that are not explained within the POD documentation, please submit a bug to the RT system (see link below). However, it would help greatly if you are able to pinpoint problems or even supply a patch. Fixes are dependent upon their severity and my availability. Should a fix not be forthcoming, please feel free to (politely) remind me by sending an email to barbie@cpan.org . RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Template-Plugin-WikiFormat AUTHOR Original Author: Ivor Williams (RIP) 2002-2009 Current Maintainer: Barbie 2009-2013 COPYRIGHT AND LICENSE Copyright © 2002-2009 Ivor Williams Copyright © 2009-2013 Barbie for Miss Barbell Productions. This distribution is free software; you can redistribute it and/or modify it under the Artistic License v2.