package SVN::Hook::Redispatch; use strict; use Path::Class; use SVN::Hook; sub import { my $class = shift; my $spec = shift; return unless $spec; my $hook_base = Path::Class::File->new($0); my $type; my $svnlook_arg; # $0 can be either hooks/_pre-commit/random_name or # hooks/pre-commit itself if ($hook_base->parent =~ m'hooks$') { # the hook file itself $type = $hook_base->basename; $hook_base = $hook_base->parent->subdir("_".$type); } else { $hook_base = $hook_base->parent; $type = $hook_base; $type =~ s{^.*/_}{}; } # if we are able to pull out the toplevel path if ($type eq 'pre-commit') { $svnlook_arg = "-t $_[1]"; } elsif ($type eq 'post-commit') { $svnlook_arg = "-r $_[1]"; } else { } my $ignore_error = $type =~ m/^post-/? 1 : 0; if (defined (my $dir = delete $spec->{''})) { # global ones my @scripts = SVN::Hook::Script->load_from_dir ( $hook_base.'/'.$dir ); SVN::Hook->run_scripts( \@scripts, $ignore_error, @_ ); } return unless $svnlook_arg; my $toplevel = $class->find_toplevel_change($_[0], $svnlook_arg); for (map { Path::Class::Dir->new_foreign('Unix', $_) } sort keys %$spec) { next unless $_ eq $toplevel || $_->subsumes($toplevel); my @scripts = SVN::Hook::Script->load_from_dir ( $hook_base.'/'.$spec->{$_} ); SVN::Hook->run_scripts( \@scripts, $ignore_error, @_ ); } }; sub find_toplevel_change { my $class = shift; my $repos = shift; my $arg = shift; my $svnlook = $ENV{SVNLOOK} || 'svnlook'; open my $fh, '-|', "$svnlook dirs-changed $arg $repos" or die "Unable to run svnlook: $!"; my $toplevel; while (<$fh>) { chomp; if (!$toplevel) { $toplevel = Path::Class::Dir->new_foreign('Unix', $_); } else { while (!$toplevel->subsumes($_)) { $toplevel = $toplevel->parent; } } } return $toplevel; } 1;