[Bps-public-commit] Prophet - A disconnected, replicated p2p database branch, master, updated. 781c9447798e85a03f5ce618052100a22ee07a62
spang at bestpractical.com
spang at bestpractical.com
Tue Jan 27 05:25:53 EST 2009
The branch, master has been updated
via 781c9447798e85a03f5ce618052100a22ee07a62 (commit)
via 1491c8e757c078494a1ec5df318319c9fc17b5dc (commit)
via e6278a5ce606848276ec234f6e46f3b88ff8f81a (commit)
via 1a555a39533708f33ce4f77675eb80b190918d1d (commit)
via 20b0b4c6c6271a90038fb0ac0c07fdeb92b93259 (commit)
from d68518866547f2795fe6dc38338266d709740969 (commit)
Summary of changes:
lib/Prophet/CLI/Command/Log.pm | 92 +++++++++++++++++++++++++++++++----
lib/Prophet/CLI/Dispatcher.pm | 7 +++
lib/Prophet/CLIContext.pm | 2 +-
lib/Prophet/Replica.pm | 2 +-
lib/Prophet/Replica/prophet.pm | 9 +++-
lib/Prophet/Replica/sqlite.pm | 10 +++-
lib/Prophet/Test.pm | 56 ++++++++++++++++-----
t/log.t | 106 ++++++++++++++++++++++++++++++++++++++++
8 files changed, 253 insertions(+), 31 deletions(-)
create mode 100644 t/log.t
- Log -----------------------------------------------------------------
commit 20b0b4c6c6271a90038fb0ac0c07fdeb92b93259
Author: Christine Spang <spang at bestpractical.com>
Date: Mon Jan 26 12:53:34 2009 +0200
allow specifying an endpoint in traverse_changesets
diff --git a/lib/Prophet/Replica.pm b/lib/Prophet/Replica.pm
index 5bc288a..5ef13c2 100644
--- a/lib/Prophet/Replica.pm
+++ b/lib/Prophet/Replica.pm
@@ -724,7 +724,7 @@ sub _read_luid2guid_mappings {
return \%luid2guid;
}
-=head3 traverse_changesets { after => SEQUENCE_NO, callback => sub {} }
+=head3 traverse_changesets { after => SEQUENCE_NO, until => SEQUENCE_NO, callback => sub {} }
Walk through each changeset in the replica after SEQUENCE_NO, calling the
C<callback> for each one in turn.
diff --git a/lib/Prophet/Replica/prophet.pm b/lib/Prophet/Replica/prophet.pm
index 9c0f6c7..a0e8f66 100644
--- a/lib/Prophet/Replica/prophet.pm
+++ b/lib/Prophet/Replica/prophet.pm
@@ -635,7 +635,9 @@ sub _get_changeset_index_entry {
=head2 traverse_changesets { after => SEQUENCE_NO, callback => sub { } }
-Walks through all changesets after $after, calling $callback on each.
+Walks through all changesets from $after to $until, calling $callback on each.
+
+If no $until is specified, the latest changeset is assumed.
=cut
@@ -648,11 +650,14 @@ sub traverse_changesets {
@_,
{ after => 1,
callback => 1,
+ until => 0,
}
);
my $first_rev = ( $args{'after'} + 1 ) || 1;
- my $latest = $self->latest_sequence_no();
+ my $latest = $args{until} ? $args{until} : $self->latest_sequence_no();
+
+ $latest = $self->latest_sequence_no() if $latest > $self->latest_sequence_no();
my $chgidx = $self->_read_changeset_index;
$self->log_debug("Traversing changesets between $first_rev and $latest");
diff --git a/lib/Prophet/Replica/sqlite.pm b/lib/Prophet/Replica/sqlite.pm
index cff2d35..7c1264f 100644
--- a/lib/Prophet/Replica/sqlite.pm
+++ b/lib/Prophet/Replica/sqlite.pm
@@ -383,10 +383,11 @@ sub _delete_record_props_from_db {
}
-=head2 traverse_changesets { after => SEQUENCE_NO, callback => sub { } }
+=head2 traverse_changesets { after => SEQUENCE_NO, UNTIL => SEQUENCE_NO, callback => sub { } }
-Walks through all changesets after $after, calling $callback on each.
+Walks through all changesets from $after to $until, calling $callback on each.
+If no $until is specified, the latest changeset is assumed.
=cut
@@ -396,11 +397,14 @@ sub traverse_changesets {
@_,
{ after => 1,
callback => 1,
+ until => 0,
}
);
my $first_rev = ( $args{'after'} + 1 ) || 1;
- my $latest = $self->latest_sequence_no();
+ my $latest = $args{until} ? $args{until} : $self->latest_sequence_no();
+
+ $latest = $self->latest_sequence_no() if $latest > $self->latest_sequence_no();
$self->log_debug("Traversing changesets between $first_rev and $latest");
for my $rev ( $first_rev .. $latest ) {
commit 1a555a39533708f33ce4f77675eb80b190918d1d
Author: Christine Spang <spang at bestpractical.com>
Date: Mon Jan 26 19:30:51 2009 +0200
anchor the end of this regex to avoid incorrect matches on things like '1..10'
diff --git a/lib/Prophet/CLIContext.pm b/lib/Prophet/CLIContext.pm
index ebe2ebc..58a6dd1 100644
--- a/lib/Prophet/CLIContext.pm
+++ b/lib/Prophet/CLIContext.pm
@@ -187,7 +187,7 @@ sub parse_args {
# "ticket show 4" should DWIM and "ticket show --id=4"
$self->set_arg( id => pop @primary )
- if @primary && $primary[-1] =~ /^(?:\d+|[0-9a-f]{8}\-)/i;
+ if @primary && $primary[-1] =~ /^(?:\d+|[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12})$/i;
my $collecting_props = 0;
commit e6278a5ce606848276ec234f6e46f3b88ff8f81a
Author: Christine Spang <spang at bestpractical.com>
Date: Mon Jan 26 22:21:31 2009 +0200
tests for log command
diff --git a/t/log.t b/t/log.t
new file mode 100644
index 0000000..61afce0
--- /dev/null
+++ b/t/log.t
@@ -0,0 +1,106 @@
+use warnings;
+use strict;
+use Test::More tests => 22;
+use File::Temp qw'tempdir';
+use Prophet::Test;
+
+# tests for log command
+
+use_ok('Prophet::CLI');
+$ENV{'PROPHET_REPO'} = tempdir( CLEANUP => ! $ENV{PROPHET_DEBUG} ) . '/repo-' . $$;
+
+my $cli = Prophet::CLI->new();
+my $handle = $cli->handle;
+
+isa_ok( $handle, 'Prophet::Replica', "Got the handle" );
+
+$handle->initialize;
+
+use_ok('Prophet::CLI::Command::Log');
+
+# make some changes so the tests below don't pass just because they always
+# get zero as the latest sequence number
+use_ok('Prophet::Record');
+my $record = Prophet::Record->new( handle => $handle, type => 'Person' );
+my $mao = $record->create( props => { name => 'Mao', age => 0.7, species => 'cat' } );
+$record->set_prop( name => 'age', value => 1 );
+$record->set_prop( name => 'color', value => 'black' );
+
+diag("latest sequence no is ".$handle->latest_sequence_no);
+
+# test the range parsing / setting
+my $log = new Prophet::CLI::Command::Log(handle => $handle, cli => $cli, context => $cli->context );
+
+$log->set_arg('range', '0..20');
+my ($start, $end) = $log->parse_range_arg();
+is($start, 0, '0..20 starts at 0');
+is($end, 20, '0..20 ends at 20');
+
+$log->set_arg('range', '0..LATEST~5');
+($start, $end) = $log->parse_range_arg();
+is($start, 0, '0..LATEST~5 starts at 0');
+is($end, $handle->latest_sequence_no - 5,
+ '0..LATEST~5 ends at latest changeset - 5');
+
+$log->set_arg('range', 'LATEST~8..50');
+($start, $end) = $log->parse_range_arg();
+is($start, $handle->latest_sequence_no - 8, 'LATEST~8..50 starts at latest - 8');
+is($end, 50, 'LATEST~8..50 ends at 50');
+
+$log->set_arg('range', 'LATEST~10..LATEST~5');
+($start, $end) = $log->parse_range_arg();
+is($start, $handle->latest_sequence_no - 10, 'LATEST~10..LATEST~5 starts at latest - 10');
+is($end, $handle->latest_sequence_no - 5, 'LATEST~10..LATEST~5 ends at latest - 5');
+
+$log->set_arg('range', 'LATEST~10');
+($start, $end) = $log->parse_range_arg();
+is($start, $handle->latest_sequence_no - 10, 'LATEST~10 starts at latest - 10');
+is($end, $handle->latest_sequence_no, 'LATEST~10 ends at latest');
+
+$log->set_arg('range', 'LATEST');
+($start, $end) = $log->parse_range_arg();
+is($start, $handle->latest_sequence_no, 'LATEST starts at latest');
+is($end, $handle->latest_sequence_no, 'LATEST ends at latest');
+
+# run the command and test its output
+
+my $replica_uuid = replica_uuid;
+my $first = " $ENV{USER}".' at \d{4}-\d{2}-\d{2} .+ \(1\@'.$replica_uuid.'\)
+ # Person 1 \(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\)
+ \+ "original_replica" set to "'.$replica_uuid.'"
+ \+ "creator" set to "'.$ENV{USER}.'"
+ \+ "name" set to "Mao"
+ \+ "species" set to "cat"
+ \+ "age" set to "0.7"';
+
+my $second = " $ENV{USER}".' at \d{4}-\d{2}-\d{2} .+ \(2\@'.$replica_uuid.'\)
+ # Person 1 \(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\)
+ > "age" changed from "0.7" to "1"\.';
+
+my $third = " $ENV{USER}".' at \d{4}-\d{2}-\d{2} .+ \(3\@'.$replica_uuid.'\)
+ # Person 1 \(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\)
+ \+ "color" set to "black"';
+
+# --all
+my $out = run_command('log', '--all');
+like($out, qr{$first\n\n$second\n\n$third\n\n}, "--all outputs all changes");
+
+# range: digit and LATEST
+$out = run_command('log', '--range=0..LATEST~2');
+like($out, qr{$first\n\n}, "just the first change");
+
+# range: assumed end
+$out = run_command('log', '--range=LATEST~2');
+like($out, qr{$second\n\n$third\n\n}, "last two changes");
+
+# syntactic sugar
+$out = run_command('log', 'LATEST~2');
+like($out, qr{$second\n\n$third\n\n}, "syntactic sugar doesn't change output");
+
+# error -- invalid input
+run_output_matches('prophet', [ 'log', 'invalid' ],
+ [], [ "Invalid range specified.\n" ], "invalid input caught correctly" );
+
+# error -- end is before start
+run_output_matches('prophet', [ 'log', '10..5' ],
+ [], [ "START must be before END in START..END." ], "caught START before END correctly" );
commit 1491c8e757c078494a1ec5df318319c9fc17b5dc
Author: Christine Spang <spang at bestpractical.com>
Date: Mon Jan 26 22:23:21 2009 +0200
git-style <since>..<until> ranges in log command
diff --git a/lib/Prophet/CLI/Command/Log.pm b/lib/Prophet/CLI/Command/Log.pm
index e380b37..447b34c 100644
--- a/lib/Prophet/CLI/Command/Log.pm
+++ b/lib/Prophet/CLI/Command/Log.pm
@@ -2,17 +2,38 @@ package Prophet::CLI::Command::Log;
use Moose;
extends 'Prophet::CLI::Command';
+# Default: last 20 entries.
+# sd log --all # show it all (overrides everything else)
+# sd log --range 0..LATEST~5 # shows the first until 5 from the latest
+# sd log --range LATEST~10 # shows last 10 entries
+# sd log --range LATEST # shows the latest entry
+
+# syntactic sugar in dispatcher:
+# sd log 0..LATEST~5 => sd log --range 0..LATEST~5
+# sd log LATEST~10 => sd log --range LATEST~10
+
sub run {
my $self = shift;
+ my $handle = $self->handle;
- $self->validate_args;
+ # --all overrides any other args
+ if ($self->has_arg('all')) {
+ $self->set_arg('range', '0..'.$handle->latest_sequence_no);
+ }
+
+ my ($start, $end) = $self->has_arg('range') ? $self->parse_range_arg() :
+ ($handle->latest_sequence_no - 20, $handle->latest_sequence_no);
+
+ # parse_range returned undef
+ die "Invalid range specified.\n" if !defined($start) || !defined($end);
- my $handle = $self->handle;
- my $newest = $self->arg('last') || $handle->latest_sequence_no;
- my $start = $newest - ( $self->arg('count') || '20' );
$start = 0 if $start < 0;
+
+ die "START must be before END in START..END.\n" if $end - $start < 0;
+
$handle->traverse_changesets(
- after => $start,
+ after => $start - 1,
+ until => $end,
callback => sub {
my $changeset = shift;
$self->handle_changeset($changeset);
@@ -22,14 +43,65 @@ sub run {
}
-sub validate_args {
+=head2 parse_range_arg
+
+Parses the string in the 'range' arg into start and end sequence numbers
+and returns them in that order.
+
+Returns undef if the string is malformed.
+
+=cut
+
+sub parse_range_arg {
my $self = shift;
- if ($self->has_arg('last') && $self->arg('last') !~ /\d+/) {
- die "Value passed to --last must be a number.\n";
+ my $range = $self->arg('range');
+
+ # split on .. (denotes range)
+ my @start_and_end = split(/\.\./, $range, 2);
+ my ($start, $end);
+ if (@start_and_end == 1) {
+ # only one delimiter was specified -- this will be the
+ # START; END defaults to the latest
+ $end = $self->handle->latest_sequence_no;
+ $start = $self->_parse_delimiter($start_and_end[0]);
+ } elsif (@start_and_end == 2) {
+ # both delimiters were specified
+ # parse the first one as START
+ $start = $self->_parse_delimiter($start_and_end[0]);
+ # parse the second one as END
+ $end = $self->_parse_delimiter($start_and_end[1]);
+ } else {
+ # something wrong was specified
+ return undef;
}
- if ($self->has_arg('count') && $self->arg('count') !~ /\d+/) {
- die "Value passed to --count must be a number.\n";
+ return ($start, $end);
+}
+
+=head2 _parse_delimiter($delim)
+
+Takes a delimiter string and parses into a sequence number. If
+it is not either an integer number or of the form LATEST~#,
+returns undef (invalid delimiter).
+
+=cut
+
+sub _parse_delimiter {
+ my ($self, $delim) = @_;
+
+ if ($delim =~ m/^\d+$/) {
+ # a sequence number was specified, just use it
+ return $delim;
+ } else {
+ # try to parse what was given as LATEST~#
+ # if it's just LATEST, we want only the last change
+ my $offset;
+ $offset = 0 if $delim eq 'LATEST';
+ (undef, $offset) = split(/~/, $delim, 2) if $delim =~ m/^LATEST~/;
+ return undef unless $offset =~ m/^\d+$/;
+
+ return $self->handle->latest_sequence_no - $offset;
}
+ return undef;
}
sub handle_changeset {
diff --git a/lib/Prophet/CLI/Dispatcher.pm b/lib/Prophet/CLI/Dispatcher.pm
index e520006..1cec543 100644
--- a/lib/Prophet/CLI/Dispatcher.pm
+++ b/lib/Prophet/CLI/Dispatcher.pm
@@ -44,6 +44,13 @@ on qr{^(clone|pull) (\S+)$} => sub {
run($1, $self);
};
+# log range => log --range range
+on qr{log\s*([0-9LATEST.~]+)} => sub {
+ my $self = shift;
+ $self->context->set_arg(range => $1);
+ run('log', $self);
+};
+
on [ ['create', 'new'] ] => run_command("Create");
on [ ['show', 'display'] ] => run_command("Show");
on [ ['update', 'edit'] ] => run_command("Update");
commit 781c9447798e85a03f5ce618052100a22ee07a62
Author: Christine Spang <spang at bestpractical.com>
Date: Tue Jan 27 12:11:33 2009 +0200
as it turns out, sorting Regexp objects and expecting them to end up in the same order as the strings they will match turns out to be a bad assumption
diff --git a/lib/Prophet/Test.pm b/lib/Prophet/Test.pm
index 48dbdf3..677fa75 100644
--- a/lib/Prophet/Test.pm
+++ b/lib/Prophet/Test.pm
@@ -262,9 +262,6 @@ sub _mk_cmp_closure {
}
}
-# factored out so it can be shared between is_script_output
-# and run_script_matches_unordered
-
# XXX note that this sub doesn't check to make sure we got
# all the errors we were expecting (there can be more lines
# in the expected stderr than the received stderr as long
@@ -312,25 +309,56 @@ outputs.
sub run_output_matches_unordered {
my ($cmd, $args, $stdout, $stderr, $msg) = @_;
+ $stderr ||= [];
my ($val, $out, $err) = run_script( $cmd, $args );
local $Test::Builder::Level = $Test::Builder::Level + 1;
- # in order to not force an ordering on the output, we sort both
- # the expected and received output before comparing them
- my $sorted_exp_out = [sort @$stdout];
- my $sorted_exp_err = [sort @{$stderr||[]} ];
+ # Check if each line matches a line in the expected output and
+ # delete that line if we have a match. If no match is found,
+ # add an error.
+ my $errors = [];
+ my @lines = split /\n/, $out;
+ OUTPUT: while (my $line = shift @lines) {
+ for my $exp_line (@$stdout) {
+ if ((ref($exp_line) eq 'Regexp' ? ( $line =~ m/$exp_line/ ) :
+ ( $line eq $exp_line ))) {
+ # remove the found element from the array of expected output
+ $stdout = [grep { $_ ne $exp_line } @$stdout];
+ next OUTPUT;
+ }
+ }
+ # we didn't find a match
+ push @$errors, "couldn't find match for ($line)\n";
+ }
+
+ # do the same for STDERR
+ @lines = split /\n/, $err;
+ ERROR: while (my $line = shift @lines) {
+ for my $exp_line (@$stderr) {
+ if ((ref($exp_line) eq 'Regexp' ? ( $line =~ m/$exp_line/ ) :
+ ( $line eq $exp_line ))) {
+ # remove the found element from the array of expected output
+ $stderr = [grep { $_ ne $exp_line } @$stderr];
+ next ERROR;
+ }
+ }
+ # we didn't find a match
+ push @$errors, "couldn't find match for ($line)\n";
+ }
- # compare and put errors into $error
- my $error = [];
- my $check_exp_out = _mk_cmp_closure($sorted_exp_out, $error);
- my $check_exp_err = _mk_cmp_closure($sorted_exp_err, $error);
+ # add any expected lines that we didn't find to the errors
+ for my $exp_line (@$stdout, @$stderr) {
+ push @$errors, "got nothing, expected: $exp_line";
+ }
- map { $check_exp_out->($_) } sort split(/\n/,$out);
- map { $check_exp_err->($_) } sort split(/\n/,$err);
+ my $test_name = join( ' ', $msg ? "$msg:" : '', $cmd, @$args );
+ is(scalar(@$errors), 0, $test_name);
- _check_cmp_closure_output($cmd, $msg, $args, $sorted_exp_out, $error);
+ if (@$errors) {
+ diag( "Errors: " . join( "\n", @$errors ) );
+ }
}
=head2 repo_path_for($username)
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list