/usr/local/CPAN/VCI/VCI/VCS/Svn/Directory.pm
package VCI::VCS::Svn::Directory;
use Moose;
use Path::Abstract::Underload;
use SVN::Core;
with 'VCI::VCS::Svn::Committable';
extends 'VCI::Abstract::Directory';
# There's a bug in the SVN API that causes it to segfault if you don't
# die inside an error handler. So in order to get details about an error,
# we die with a reference to the error.
sub _x_handle_svn_failure { die $_[0]; }
sub _build_contents {
my $self = shift;
my $project = $self->project;
my $vci = $project->vci;
my $ra = $project->repository->x_ra;
my $dir_path = Path::Abstract::Underload->new($project->name, $self->path);
print STDERR "Getting contents for " . $dir_path->stringify
. " rev " . $self->revision . "\n"
if $vci->debug;
my @info;
{
local $SVN::Error::handler = \&_x_handle_svn_failure;
eval { @info = $ra->get_dir($dir_path->stringify, $self->revision) };
}
# When a directory has been copied, and hasn't been modified since,
# SVN says the last revision of its contents is the revision the directory
# was copied *from*.
# However, when you try to get the contents of the path at that
# revision, SVN throws error 175007, meaning "path not found."
# So, to handle that, we find the place our parent was copied from,
# and get the contents of that, at that revision.
if (ref($@) && $@->apr_err == 175007) {
my $history = $self->history;
my $parent_from;
foreach my $commit (@{$history->commits}) {
$parent_from = $commit->copied->{$self->parent->path->stringify};
last if $parent_from;
}
SVN::Error::croak_on_error($@) if !$parent_from;
$@->clear();
my ($my_source) = grep ($_->name eq $self->name,
@{$parent_from->contents});
if ($vci->debug) {
print STDERR $self->path, " was copied from ", $my_source->path,
"\n";
}
return $my_source->contents;
}
else {
SVN::Error::croak_on_error($@);
}
my $svn_contents = shift @info;
my @contents;
foreach my $name (keys %$svn_contents) {
my $item = $svn_contents->{$name};
my $path = Path::Abstract::Underload->new($self->path, $name);
if ($item->kind == $SVN::Node::dir) {
my $dir = VCI::VCS::Svn::Directory->new(
path => $path, project => $project, parent => $self,
x_info => $item);
push(@contents, $dir);
}
elsif ($item->kind == $SVN::Node::file) {
my $file = $self->file_class->new(
path => $path, project => $project, parent => $self,
x_info => $item);
push(@contents, $file);
}
}
return \@contents;
}
# We have to do this because ->isa File or Directory never
# returns true on a FileOrDirectory.
sub _me_from {
my $self = shift;
my $orig_class = blessed $self;
bless $self, 'VCI::VCS::Svn::FileOrDirectory';
my $ret = $self->SUPER::_me_from(@_);
bless $self, $orig_class;
bless $ret, $orig_class;
return $ret;
};
__PACKAGE__->meta->make_immutable;
1;