forked from github/kensanata.oddmuse
Added: $GitPageFile variable. Set it to true if you want to keep complete page files in git and not just text. Fixed: previously git extension was chdir-ing into $GitRepo directory without ever going back, this could have lead to problems if some other code needed access to file system. Fixed: now this extension will work smoothly if $DataDir is set to a relative path. Fixed: this extension was probably broken for wiki pages starting with two dashes (e.g. --SomePage), this is now fixed by using -- to indicate the end of command-line options. Changed: GitCleanup is now using GitRun instead of backticks (like everywhere else). It will also print the exit status of 'git commit' command. Changed: some tiny style improvements.
185 lines
5.1 KiB
Perl
185 lines
5.1 KiB
Perl
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
|
|
|
|
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
=head1 NAME
|
|
|
|
git - An Oddmuse module to save all changes made into a git repository.
|
|
|
|
=head1 INSTALLATION
|
|
|
|
This module is easily installable; move this file into the B<modules>
|
|
subdirectory for your data directory (C<$DataDir>).
|
|
|
|
=cut
|
|
|
|
package OddMuse;
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
Set these variables in the B<config> file within your data directory.
|
|
|
|
=head2 $GitBinary
|
|
|
|
Default: C</usr/bin/git>
|
|
|
|
The fully qualified name for the binary to run. Your PATH will not be searched.
|
|
|
|
=head2 $GitRepo
|
|
|
|
Default: C<$DataDir/git>
|
|
|
|
The directory in which the repository resides. If it doesn't exist,
|
|
Oddmuse will create it for you.
|
|
|
|
=head2 $GitMail
|
|
|
|
Default: C<unknown@oddmuse.org>
|
|
|
|
The email address used to identify users in git.
|
|
|
|
=cut
|
|
|
|
use Cwd;
|
|
use vars qw($GitBinary $GitRepo $GitMail $GitPageFile);
|
|
|
|
$GitBinary = 'git';
|
|
$GitMail = 'unknown@oddmuse.org';
|
|
$GitPageFile = 0;
|
|
|
|
push(@MyInitVariables, \&GitInitVariables);
|
|
|
|
sub GitRun {
|
|
my $oldDir = cwd;
|
|
chdir($GitRepo);
|
|
my $result = '';
|
|
local *STDOUT;
|
|
open(STDOUT, '>', \$result) or die "Can't open memory file: $!";
|
|
my $exitStatus = system($GitBinary, @_);
|
|
chdir($oldDir);
|
|
if (not defined wantarray) { # void context
|
|
return if $exitStatus == 0;
|
|
ReportError("git failed: $!",
|
|
'500 INTERNAL SERVER ERROR',
|
|
undef,
|
|
$q->p($q->tt(join(' ', $GitBinary, map {
|
|
if (index($_, ' ') == -1) {
|
|
$_;
|
|
} else {
|
|
"'$_'";
|
|
}
|
|
} @_))),
|
|
$q->pre($result));
|
|
} else {
|
|
return $exitStatus;
|
|
}
|
|
}
|
|
|
|
sub GitInitVariables {
|
|
$GitRepo = $DataDir . '/git';
|
|
}
|
|
|
|
sub GitInitRepository {
|
|
return if -d "$GitRepo/.git";
|
|
CreateDir($GitRepo);
|
|
GitRun(qw(init --quiet));
|
|
foreach my $id (AllPagesList()) {
|
|
OpenPage($id);
|
|
WriteStringToFile("$GitRepo/$id", $GitPageFile ? EncodePage(%Page) : $Page{text});
|
|
GitRun(qw(add --), $id);
|
|
}
|
|
GitRun(qw(commit --quiet -m), 'initial import', "--author=Oddmuse <$GitMail>");
|
|
}
|
|
|
|
*GitOldSave = *Save;
|
|
*Save = *GitNewSave;
|
|
|
|
sub GitNewSave {
|
|
GitOldSave(@_);
|
|
GitInitRepository();
|
|
my ($id) = @_;
|
|
WriteStringToFile("$GitRepo/$id", $GitPageFile ? EncodePage(%Page) : $Page{text});
|
|
GitRun(qw(add --), $id) if ($Page{revision} == 1);
|
|
my $message = $Page{summary};
|
|
$message =~ s/^\s+$//;
|
|
$message ||= T('no summary available');
|
|
my $author = $Page{username} || T('Anonymous');
|
|
GitRun(qw(commit --quiet -m), $message,
|
|
"--author=$author <$GitMail>", '--', $id);
|
|
}
|
|
|
|
*GitOldDeletePage = *DeletePage;
|
|
*DeletePage = *GitNewDeletePage;
|
|
|
|
sub GitNewDeletePage {
|
|
my $error = GitOldDeletePage(@_);
|
|
return $error if $error;
|
|
GitInitRepository();
|
|
my ($id) = @_;
|
|
GitRun(qw(rm --quiet --ignore-unmatch --), $id);
|
|
my $message = T('page was marked for deletion');
|
|
my $author = T('Oddmuse');
|
|
GitRun(qw(commit --quiet -m), $message,
|
|
"--author=$author <$GitMail>", '--', $id);
|
|
return ''; # no error
|
|
}
|
|
|
|
push(@MyMaintenance, \&GitCleanup);
|
|
|
|
$Action{git} = \&DoGitCleanup;
|
|
|
|
sub DoGitCleanup {
|
|
UserIsAdminOrError();
|
|
print GetHeader('', 'Git', '');
|
|
print $q->start_div({-class=>'content git'});
|
|
RequestLockOrError();
|
|
print $q->p(T('Main lock obtained.')), '<p>', T('Cleaning up git repository');
|
|
GitCleanup();
|
|
ReleaseLock();
|
|
print $q->p(T('Main lock released.')), $q->end_div();
|
|
PrintFooter();
|
|
}
|
|
|
|
sub GitCleanup {
|
|
if (-d $GitRepo) {
|
|
print $q->p('Git cleanup starting');
|
|
AllPagesList();
|
|
# delete all the files including all the files starting with a dot
|
|
opendir(DIR, $GitRepo) or ReportError("cannot open directory $GitRepo: $!");
|
|
foreach my $file (readdir(DIR)) {
|
|
my $name = $file;
|
|
utf8::decode($name); # filenames are bytes
|
|
next if $file eq '.git' or $file eq '.' or $file eq '..' or $IndexHash{$name};
|
|
print $q->p("Deleting left over file $name");
|
|
unlink "$GitRepo/$file" or ReportError("cannot delete $GitRepo/$name: $!");
|
|
}
|
|
closedir DIR;
|
|
# write all the files again, just to be sure
|
|
print $q->p('Rewriting all the files, just to be sure');
|
|
foreach my $id (@IndexList) {
|
|
OpenPage($id);
|
|
WriteStringToFile("$GitRepo/$id", $GitPageFile ? EncodePage(%Page) : $Page{text});
|
|
}
|
|
# run git!
|
|
# add any new files
|
|
print $q->p('Adding new files, if any');
|
|
GitRun(qw(add -A));
|
|
# commit the new state
|
|
print $q->p('Committing changes, if any');
|
|
my $exitStatus = GitRun(qw(commit --quiet -m), 'maintenance job',
|
|
"--author=Oddmuse <$GitMail>");
|
|
print $q->p('git commit finished with ' . $exitStatus . ' exit status.');
|
|
print $q->p('Git done');
|
|
}
|
|
}
|