package App::KGB::Client::Subversion; use utf8; # vim: ts=4:sw=4:et:ai:sts=4 # # KGB - an IRC bot helping collaboration # Copyright © 2008 Martín Ferrari # Copyright © 2009,2010 Damyan Ivanov # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. use strict; use warnings; =head1 NAME App::KGB::Client::Subversion - KGB interface to Subversion =head1 SYNOPSIS use App::KGB::Client::Subversion; my $client = App::KGB::Client::Subversion( # common App::KGB::Client parameters repo_id => 'my-repo', ... # Subversion-specific repo_path => '/svn/project', revision => 42, ); $client->run; =head1 DESCRIPTION B provides Subversion-specific retrieval of commits and changes for L. =head1 CONSTRUCTOR =head2 B ( { initializers } ) Standard constructor. Accepts inline hash with initial field values. =head1 FIELDS App:KGB::Client::Subversion defines two additional fields: =over =item B (B) Physical path to Subversion repository. =item B The revision about which to notify. If omitted defaults to the last revision of the repository. =back =head1 METHODS =over =item describe_commit The first time this method is called, it retrieves commit number and repository path from command-line parameters and returns an instance of L class describing the commit. All subsequential invocations return B. =back =cut require v5.10.0; use base 'App::KGB::Client'; use App::KGB::Change; use App::KGB::Commit; use Carp qw(confess); use SVN::Fs; use SVN::Repos; use SVN::Core; __PACKAGE__->mk_accessors(qw( _called repo_path revision )); use constant rev_prefix => 'r'; sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->_called(0); defined( $self->repo_path ) or confess "'repo_path' is mandatory"; return $self; } sub describe_commit { my ($self) = @_; return undef if $self->_called; my ( $author, $log, @changes ); # Shut up the perl compiler warnings if ( $SVN::Fs::PathChange::modify and $SVN::Fs::PathChange::add and $SVN::Fs::PathChange::delete and $SVN::Fs::PathChange::replace ) { } my $repo = SVN::Repos::open( $self->repo_path ); my $fs = $repo->fs or die $!; $self->revision( $fs->youngest_rev ) unless defined( $self->revision ); $log = $fs->revision_prop( $self->revision, "svn:log" ); $author = $fs->revision_prop( $self->revision, "svn:author" ); my $root = $fs->revision_root( $self->revision ); my $changed = $root->paths_changed(); foreach ( keys %$changed ) { my $k = $changed->{$_}->change_kind(); if ( $k == $SVN::Fs::PathChange::modify ) { $k = "M"; } elsif ( $k == $SVN::Fs::PathChange::add ) { $k = "A"; } elsif ( $k == $SVN::Fs::PathChange::delete ) { $k = "D"; } elsif ( $k == $SVN::Fs::PathChange::replace ) { $k = "R"; } my $pm = $changed->{$_}->prop_mod(); push @changes, App::KGB::Change->new( { action => $k, prop_change => $pm, path => $_, } ); } $self->_called(1); return App::KGB::Commit->new( { id => $self->revision, changes => \@changes, author => $author, log => $log, } ); } 1;