1package CGI::Kwiki::Backup::SVNPerl;
2$VERSION = '0.01';
3
4use strict;
5use base 'CGI::Kwiki::Backup::SVN';
6use File::Spec;
7use SVN::Core '0.28';
8use SVN::Repos;
9use SVN::Fs;
10use SVN::Delta;
11use SVN::Simple::Edit;
12use Text::Diff ();
13
14use constant SVN_DIR => 'metabase/svn';
15
16my $user_name = '';
17
18my ($repos, $fs, $pool, $init);
19
20sub init {
21    my $self = shift;
22    $pool = SVN::Pool->new_default;
23    if (-d SVN_DIR) {
24	$repos = SVN::Repos::open (SVN_DIR);
25    }
26    else {
27	$repos = SVN::Repos::create(SVN_DIR, undef, undef,
28				    undef, undef);
29	my $edit = $self->_get_edit ('kwiki-install', 'kwiki install');
30
31	$edit->open_root (0);
32
33        for my $page_id ($self->database->pages) {
34	    $edit->add_file ($page_id);
35	    open my $fh, $self->database->file_path($page_id);
36	    $edit->modify_file ($page_id, $fh)
37	}
38	$edit->close_edit;
39    }
40    $fs = $repos->fs;
41    ++$init;
42}
43
44sub new {
45    my ($class) = shift;
46    my $self = $class->SUPER::new(@_);
47    $self->init unless $init;
48    $self->{pool} = SVN::Pool->new_default_sub();
49
50    $self->{headrev} = $fs->youngest_rev;
51
52    return $self;
53}
54
55sub _get_edit {
56    my ($self, $author, $comment, $pool) = @_;
57    SVN::Simple::Edit->new (_editor => [SVN::Repos::get_commit_editor
58					($repos, '', '/', $author,
59					 $comment, sub {})],
60			    pool => $pool || SVN::Pool->new ($pool));
61
62}
63
64sub commit {
65    my ($self, $page_id) = @_;
66    my $edit = $self->_get_edit ($user_name || $self->metadata->edit_by, '',
67				 $self->{pool});
68    $edit->open_root ($self->{headrev});
69    if ($self->database->exists ($page_id)) {
70	open my $fh, $self->database->file_path ($page_id);
71	$edit->modify_file ($self->has_history ($page_id) ?
72			    $edit->open_file ($page_id) :
73			    $edit->add_file ($page_id),
74			    $fh);
75    }
76    else {
77	$edit->delete_entry ($page_id);
78    }
79
80    $edit->close_edit();
81}
82
83sub has_history {
84    my ($self, $page_id) = @_;
85    $page_id ||= $self->cgi->page_id;
86    my $root = $fs->revision_root($self->{headrev});
87
88    SVN::Fs::check_path($root, $page_id) == $SVN::Core::node_file;
89}
90
91sub history {
92    my ($self, $page_id) = @_;
93    $page_id ||= $self->cgi->page_id;
94    return [] unless $page_id;
95
96    my $revs = SVN::Repos::revisions_changed ($fs, $page_id, 0,
97					      $self->{headrev}, 0);
98
99    my $history = [map {
100	{ revision => $_,
101	  edit_by => $fs->revision_prop($_, 'svn:author'),
102	  date => $fs->revision_prop($_, 'svn:date')}} @$revs];
103
104    return $self->_build_history($history);
105}
106
107sub fetch {
108    my ($self, $page_id, $revision) = @_;
109    my $root = $fs->revision_root($revision || $self->{headrev});
110
111    my $stream = SVN::Fs::file_contents($root, $page_id);
112    local $/;
113    return <$stream>;
114}
115
116sub diff {
117    my ($self, $page_id, $r1, $r2, $context) = @_;
118
119    my $root1 = $fs->revision_root ($r1);
120    my $root2 = $fs->revision_root ($r2);
121
122    Text::Diff::diff(SVN::Fs::file_contents($root1, $page_id),
123		     SVN::Fs::file_contents($root2, $page_id),
124		     { STYLE => "Unified" });
125}
126
1271;
128