* Add support for using git instead of subversion as the RCS backend,

tremendous thanks to Recai Oktaş for this.
* Doc updates for git.
master
joey 2006-06-02 05:32:20 +00:00
parent c0f8126143
commit 30afedcfe2
12 changed files with 584 additions and 92 deletions

491
IkiWiki/Rcs/git.pm 100644
View File

@ -0,0 +1,491 @@
#!/usr/bin/perl
# Git backend for IkiWiki.
# Copyright 2006 Recai Oktaş <roktas@debian.org>
#
# Licensed under the same terms as IkiWiki.
use warnings;
use strict;
use IkiWiki;
package IkiWiki;
my $origin_branch = 'origin'; # Git ref for main repository
my $master_branch = 'master'; # Working branch
my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
my $dummy_commit_msg = 'dummy commit'; # will be used in all dummy commits
# and skipped in recent changes list
my $web_commit_msg = qr/^web commit by (\w+):?(.*)/; # pattern for web commits
sub _safe_git (&@) { #{{{
# Start a child process safely without resorting /bin/sh.
# Return command output or success state (in scalar context).
my ($error_handler, @cmdline) = @_;
my $pid = open my $OUT, "-|";
error("Cannot fork: $!") if !defined $pid;
if (!$pid) {
# In child.
open STDERR, ">&STDOUT"
or error("Cannot dup STDOUT: $!");
# Git commands want to be in wc.
chdir $config{srcdir}
or error("Cannot chdir to $config{srcdir}: $!");
exec @cmdline or error("Cannot exec '@cmdline': $!");
}
# In parent.
my @lines;
while (<$OUT>) {
chomp;
push @lines, $_;
}
close $OUT;
($error_handler || sub { })->("'@cmdline' failed: $!") if $?;
return wantarray ? @lines : ($? == 0);
}
# Convenient wrappers.
sub run_or_die ($@) { _safe_git(\&IkiWiki::error, @_) }
sub run_or_cry ($@) { _safe_git(sub { warn @_ }, @_) }
sub run_or_non ($@) { _safe_git(undef, @_) }
#}}}
sub _merge_past ($$$) { #{{{
# Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'.
# Git merge commands work with the committed changes, except in the
# implicit case of '-m' of git-checkout(1). So we should invent a
# kludge here. In principle, we need to create a throw-away branch
# in preparing for the merge itself. Since branches are cheap (and
# branching is fast), this shouldn't cost high.
#
# The main problem is the presence of _uncommitted_ local changes. One
# possible approach to get rid of this situation could be that we first
# make a temporary commit in the master branch and later restore the
# initial state (this is possible since Git has the ability to undo a
# commit, i.e. 'git-reset --soft HEAD^'). The method can be summarized
# as follows:
#
# - create a diff of HEAD:current-sha1
# - dummy commit
# - create a dummy branch and switch to it
# - rewind to past (reset --hard to the current-sha1)
# - apply the diff and commit
# - switch to master and do the merge with the dummy branch
# - make a soft reset (undo the last commit of master)
#
# The above method has some drawbacks: (1) it needs a redundant commit
# just to get rid of local changes, (2) somewhat slow because of the
# required system forks. Until someone points a more straight method
# (which I would be grateful) I have implemented an alternative method.
# In this approach, we hide all the modified files from Git by renaming
# them (using the 'rename' builtin) and later restore those files in
# the throw-away branch (that is, we put the files themselves instead
# of applying a patch).
my ($sha1, $file, $message) = @_;
my @undo; # undo stack for cleanup in case of an error
my $conflict; # file content with conflict markers
eval {
# Hide local changes from Git by renaming the modified file.
# Relative paths must be converted to absolute for renaming.
my ($target, $hidden) = (
"$config{srcdir}/${file}", "$config{srcdir}/${file}.${sha1}"
);
rename($target, $hidden)
or error("rename '$target' to '$hidden' failed: $!");
# Ensure to restore the renamed file on error.
push @undo, sub {
return if ! -e "$hidden"; # already renamed
rename($hidden, $target)
or debug("rename '$hidden' to '$target' failed: $!");
};
my $branch = "throw_away_${sha1}"; # supposed to be unique
# Create a throw-away branch and rewind backward.
push @undo, sub { run_or_cry('git-branch', '-D', $branch) };
run_or_die('git-branch', $branch, $sha1);
# Switch to throw-away branch for the merge operation.
push @undo, sub {
if (!run_or_cry('git-checkout', $master_branch)) {
run_or_cry('git-checkout','-f',$master_branch);
}
};
run_or_die('git-checkout', $branch);
# Put the modified file in _this_ branch.
rename($hidden, $target)
or error("rename '$hidden' to '$target' failed: $!");
# _Silently_ commit all modifications in the current branch.
run_or_non('git-commit', '-m', $message, '-a');
# ... and re-switch to master.
run_or_die('git-checkout', $master_branch);
# Attempt to merge without complaining.
if (!run_or_non('git-pull', '--no-commit', '.', $branch)) {
$conflict = readfile($target);
run_or_die('git-reset', '--hard');
}
};
my $failure = $@;
# Process undo stack (in reverse order). By policy cleanup
# actions should normally print a warning on failure.
while (my $handle = pop @undo) {
$handle->();
}
error("Git merge failed!\n$failure\n") if $failure;
return $conflict;
} #}}}
sub _parse_diff_tree (@) { #{{{
# Parse the raw diff tree chunk and return the info hash.
# See git-diff-tree(1) for the syntax.
my ($dt_ref) = @_;
# End of stream?
return if !defined @{ $dt_ref } || !length @{ $dt_ref }[0];
my %ci;
# Header line.
HEADER: while (my $line = shift @{ $dt_ref }) {
return if $line !~ m/^diff-tree (\S+)/;
my $sha1 = $1;
$ci{'sha1'} = $sha1;
last HEADER;
}
# Identification lines for the commit.
IDENT: while (my $line = shift @{ $dt_ref }) {
# Regexps are semi-stolen from gitweb.cgi.
if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
$ci{'tree'} = $1;
} elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) {
# XXX: collecting in reverse order
push @{ $ci{'parents'} }, $1;
} elsif ($line =~ m/^(author|committer) (.*) ([0-9]+) (.*)$/) {
my ($who, $name, $epoch, $tz) =
($1, $2, $3, $4 );
$ci{ $who } = $name;
$ci{ "${who}_epoch" } = $epoch;
$ci{ "${who}_tz" } = $tz;
if ($name =~ m/^([^<]+) <([^@]+)/) {
my ($fullname, $username) = ($1, $2);
$ci{"${who}_fullname"} = $fullname;
$ci{"${who}_username"} = $username;
} else {
$ci{"${who}_fullname"} =
$ci{"${who}_username"} = $name;
}
} elsif ($line =~ m/^$/) {
# Trailing empty line signals next section.
last IDENT;
}
}
error("No 'tree' or 'parents' seen in diff-tree output")
if !defined $ci{'tree'} || !defined $ci{'parents'};
$ci{'parent'} = @{ $ci{'parents'} }[0];
# Commit message.
COMMENT: while (my $line = shift @{ $dt_ref }) {
if ($line =~ m/^$/) {
# Trailing empty line signals next section.
last COMMENT;
};
$line =~ s/^ //;
push @{ $ci{'comment'} }, $line;
}
# Modified files.
FILE: while (my $line = shift @{ $dt_ref }) {
if ($line =~ m{^
:([0-7]{6})[ ] # from mode
([0-7]{6})[ ] # to mode
([0-9a-fA-F]{40})[ ] # from sha1
([0-9a-fA-F]{40})[ ] # to sha1
(.) # status
([0-9]{0,3})\t # similarity
(.*) # file
$}xo) {
my ($sha1_from, $sha1_to, $file) =
($3, $4, $7 );
if ($file =~ m/^"(.*)"$/) {
($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg;
}
if (length $file) {
push @{ $ci{'details'} }, {
'file' => $file,
'sha1_from' => $sha1_from,
'sha1_to' => $sha1_to,
};
}
next FILE;
};
last FILE;
}
error("No detail in diff-tree output") if !defined $ci{'details'};
return \%ci;
} #}}}
sub git_commit_info (;$$) { #{{{
# Return an array of commit info hashes of num commits (default: 1)
# starting from the given sha1sum (default: HEAD).
my ($sha1, $num) = @_;
$num ||= 1;
my @raw_lines =
run_or_die(qq{git-rev-list --max-count=$num $sha1 |
git-diff-tree --stdin --pretty=raw -c -M -r});
my @ci;
while (my $parsed = _parse_diff_tree(\@raw_lines)) {
push @ci, $parsed;
}
return wantarray ? @ci : $ci[0];
} #}}}
sub git_sha1 (;$) { #{{{
# Return head sha1sum (of given file).
my $file = shift || q{--};
my ($sha1) = run_or_die('git-rev-list', '--max-count=1', 'HEAD', $file);
($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1sum is untainted now
debug("Empty sha1sum for '$file'.") if !length $sha1;
return $sha1;
} #}}}
sub rcs_update () { #{{{
# Update working directory.
run_or_cry('git-pull', $origin_branch);
} #}}}
sub rcs_prepedit ($) { #{{{
# Return the commit sha1sum of the file when editing begins.
# This will be later used in rcs_commit if a merge is required.
my ($file) = @_;
my $sha1 = git_sha1($file);
return defined $sha1 ? $sha1 : q{};
} #}}}
sub rcs_commit ($$$) { #{{{
# Try to commit the page; returns undef on _success_ and
# a version of the page with the rcs's conflict markers on
# failure.
my ($file, $message, $rcstoken) = @_;
# XXX: Wiki directory is in the unlocked state when starting this
# action. But it takes time for a Git process to finish its job
# (especially if a merge required), so we must re-lock to prevent
# race conditions. Only when the time of the real commit action
# (i.e. git-push(1)) comes, we'll unlock the directory.
lockwiki();
# Check to see if the page has been changed by someone else since
# rcs_prepedit was called.
my $cur = git_sha1($file);
my ($prev) = $rcstoken =~ m/^$sha1_pattern$/; # untaint
if (defined $cur && defined $prev && $cur ne $prev) {
my $conflict = _merge_past($prev, $file, $dummy_commit_msg);
return $conflict if defined $conflict;
}
# git-commit(1) returns non-zero if file has not been really changed.
# so we should ignore its exit status (hence run_or_non).
if (run_or_non('git-commit', '-m', $message, '-i', $file)) {
unlockwiki();
run_or_cry('git-push', $origin_branch);
}
return undef; # success
} #}}}
sub rcs_add ($) { # {{{
# Add file to archive.
my ($file) = @_;
run_or_cry('git-add', $file);
} #}}}
sub rcs_recentchanges ($) { #{{{
# List of recent changes.
my ($num) = @_;
eval q{use CGI 'escapeHTML'};
eval q{use Date::Parse};
eval q{use Time::Duration};
my ($sha1, $type, $when, $diffurl, $user, @pages, @message, @rets);
INFO: foreach my $ci (git_commit_info('HEAD', $num)) {
my $title = @{ $ci->{'comment'} }[0];
# Skip redundant commits.
next INFO if ($title eq $dummy_commit_msg);
$sha1 = $ci->{'sha1'};
$type = "web";
$when = concise(ago(time - $ci->{'author_epoch'}));
foreach my $bit (@{ $ci->{'details'} }) {
my $diffurl = $config{'diffurl'};
my $file = $bit->{'file'};
$diffurl =~ s/\[\[file\]\]/$file/go;
$diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
$diffurl =~ s/\[\[sha1_from\]\]/$bit->{'sha1_from'}/go;
$diffurl =~ s/\[\[sha1_to\]\]/$bit->{'sha1_to'}/go;
push @pages, {
link => htmllink("", pagename($file), 1),
diffurl => $diffurl,
},
}
push @message, { line => escapeHTML($title) };
if (defined $message[0] &&
$message[0]->{line} =~ m/$web_commit_msg/) {
$user = "$1";
$message[0]->{line} = $2;
} else {
$type ="git";
$user = $ci->{'author_username'};
}
push @rets, {
rev => $sha1,
user => htmllink("", $user, 1),
committype => $type,
when => $when,
message => [@message],
pages => [@pages],
} if @pages;
$sha1 = $type = $when = $diffurl = $user = undef;
@pages = @message = ();
}
return @rets;
} #}}}
sub rcs_notify () { #{{{
# Send notification mail to subscribed users.
#
# In usual Git usage, hooks/update script is presumed to send
# notification mails (see git-receive-pack(1)). But we prefer
# hooks/post-update to support IkiWiki commits coming from a
# cloned repository (through command line) because post-update
# is called _after_ each ref in repository is updated (update
# hook is called _before_ the repository is updated). Since
# post-update hook does not accept command line arguments, we
# don't have an $ENV variable in this function.
#
# Here, we rely on a simple fact: we can extract all parts of the
# notification content by parsing the "HEAD" commit (which also
# triggers a refresh of IkiWiki pages) and we can obtain the diff
# by comparing HEAD and HEAD^ (the previous commit).
my $sha1 = 'HEAD'; # the commit which triggers this action
my $ci = git_commit_info($sha1);
if (!defined $ci) {
warn "Cannot parse info for '$sha1' commit";
return;
}
my @changed_pages = map { $_->{'file'} } @{ $ci->{'details'} };
my ($user, $message);
if (@{ $ci->{'comment'} }[0] =~ m/$web_commit_msg/) {
$user = "$1";
$message = $2;
} else {
$user = $ci->{'author_username'};
$message = join "\n", @{ $ci->{'comment'} };
}
require IkiWiki::UserInfo;
my @email_recipients = commit_notify_list($user, @changed_pages);
return if !@email_recipients;
# TODO: if a commit spans multiple pages, this will send
# subscribers a diff that might contain pages they did not
# sign up for. Should separate the diff per page and
# reassemble into one mail with just the pages subscribed to.
my $diff = join "\n", run_or_die('git-diff', "${sha1}^", $sha1);
my $subject = "$config{wikiname} update of ";
if (@changed_pages > 2) {
$subject .= "$changed_pages[0] $changed_pages[1] etc";
} else {
$subject .= join " ", @changed_pages;
}
$subject .= " by $user";
my $template = HTML::Template->new(
filename => "$config{templatedir}/notifymail.tmpl"
);
$template->param(
wikiname => $config{wikiname},
diff => $diff,
user => $user,
message => $message,
);
eval q{use Mail::Sendmail};
foreach my $email (@email_recipients) {
sendmail(
To => $email,
From => "$config{wikiname} <$config{adminemail}>",
Subject => $subject,
Message => $template->output,
) or error("Failed to send update notification mail: $!");
}
} #}}}
sub rcs_getctime ($) { #{{{
# Get the ctime of file.
my ($file) = @_;
my $sha1 = git_sha1($file);
my $ci = git_commit_info($sha1);
my $ctime = $ci->{'author_epoch'};
debug("ctime for '$file': ". localtime($ctime) . "\n");
return $ctime;
} #}}}
1

5
debian/changelog vendored
View File

@ -23,8 +23,11 @@ ikiwiki (1.5) UNRELEASED; urgency=low
can be useful when using link-based globbing for page categorisation. can be useful when using link-based globbing for page categorisation.
* Remove preprocessor directives from inlined pages. * Remove preprocessor directives from inlined pages.
* Allow simple preprocessor directive values to be specified w/o quotes. * Allow simple preprocessor directive values to be specified w/o quotes.
* Add support for using git instead of subversion as the RCS backend,
tremendous thanks to Recai Oktaş for this.
* Doc updates for git.
-- Joey Hess <joeyh@debian.org> Thu, 1 Jun 2006 23:47:43 -0400 -- Joey Hess <joeyh@debian.org> Fri, 2 Jun 2006 01:13:18 -0400
ikiwiki (1.4) unstable; urgency=low ikiwiki (1.4) unstable; urgency=low

6
debian/control vendored
View File

@ -9,17 +9,17 @@ Standards-Version: 3.7.2
Package: ikiwiki Package: ikiwiki
Architecture: all Architecture: all
Depends: ${perl:Depends}, markdown, libtimedate-perl, libhtml-template-perl, libhtml-scrubber-perl, libcgi-formbuilder-perl (>= 3.02.02), libtime-duration-perl, libcgi-session-perl, libmail-sendmail-perl, gcc | c-compiler, libc6-dev | libc-dev Depends: ${perl:Depends}, markdown, libtimedate-perl, libhtml-template-perl, libhtml-scrubber-perl, libcgi-formbuilder-perl (>= 3.02.02), libtime-duration-perl, libcgi-session-perl, libmail-sendmail-perl, gcc | c-compiler, libc6-dev | libc-dev
Recommends: subversion, hyperestraier Recommends: subversion | git-core, hyperestraier
Suggests: viewcvs Suggests: viewcvs
Description: a wiki compiler Description: a wiki compiler
ikiwiki converts a directory full of wiki pages into html pages suitable ikiwiki converts a directory full of wiki pages into html pages suitable
for publishing on a website. Unlike many wikis, ikiwiki does not have its for publishing on a website. Unlike many wikis, ikiwiki does not have its
own means of storing page history or its own markup language. Instead it own means of storing page history or its own markup language. Instead it
uses subversion and markdown. uses subversion (or git) and markdown.
. .
ikiwiki implements all of the other standard features of a wiki, including ikiwiki implements all of the other standard features of a wiki, including
web-based page editing, user registration and logins, a RecentChanges web-based page editing, user registration and logins, a RecentChanges
page, BackLinks, search, Discussion pages, smart merging and conflict page, BackLinks, search, Discussion pages, tags, smart merging and conflict
resolution, page locking, and commit emails. resolution, page locking, and commit emails.
. .
It also supports generating RSS feeds and blogging. It also supports generating RSS feeds and blogging.

View File

@ -76,9 +76,9 @@ off from R1.
(To be continued.) (To be continued.)
## [[Git]] (not yet included) ## [[Git]]
A patch with full [Git](http://git.or.cz) support is at <http://people.debian.org/~roktas/patches/ikiwiki/git.patch>. Regarding the patch, Recai says: Regarding the Git support, Recai says:
I have been testing it for the past few days and it seems satisfactory. I I have been testing it for the past few days and it seems satisfactory. I
haven't observed any race condition regarding the concurrent blog commits haven't observed any race condition regarding the concurrent blog commits
@ -90,35 +90,3 @@ bugs. It also has some drawbacks (especially wrt merge which was the hard
part). GIT doesn't have a similar functionality like 'svn merge -rOLD:NEW part). GIT doesn't have a similar functionality like 'svn merge -rOLD:NEW
FILE' (please see the relevant comment in mergepast for more details), so I FILE' (please see the relevant comment in mergepast for more details), so I
had to invent an ugly hack just for the purpose. had to invent an ugly hack just for the purpose.
Some other notes:
- There are two separate helper packages in git.pm. To keep things self
confined, I haven't split it up.
- I've used a (mini) Debug.pm during the tests and made it a separate file
for the convenience of others. It relies on the "constant folding"
feature of Perl, so there shouldn't be a runtime penalty (at least this
is what the 'perl -MO=Deparse shows', haven't made a real benchmark).
- rcs_notify() has not been implemented yet (I have noticed it after I
finished the main work).
- GIT backend uses the gitweb for repository browsing (the counterpart of
ViewCVS).
- There might be some subs in GIT name space which you may prefer to move to
the main code.
- Due to the reasons explained in the code, I've written an rcs_invoke()
wrapper. May be there should be a better approach to reach the same
goal.
- There are some parts which I may change in future, like using a global
rcs_fatal_error and the ugly error reporting code in _rcs_commit.
- Documentation is missing.
It works for me, but of course in the end, the final decision is yours (due
to mostly GIT quirks, the implementation is not clean as SVN). Feel free
to fix/delete/add whatever you want. Hope it doesn't have any serious bug.

View File

@ -3,7 +3,9 @@ Some of ikiwiki's features:
* [[Subversion]] * [[Subversion]]
Rather than implement its own system for storing page histories etc, Rather than implement its own system for storing page histories etc,
ikiwiki simply uses subversion. (It's also possible to [[plugins/write]] support for other systems.) ikiwiki simply uses subversion. (It's also possible to [[plugins/write]]
support for other systems, and ikiwiki also includes support for [[Git]]
now.)
Instead of editing pages in a stupid web form, you can use vim and commit Instead of editing pages in a stupid web form, you can use vim and commit
changes via svn. Or work disconnected using svk and push your changes out changes via svn. Or work disconnected using svk and push your changes out

View File

@ -2,7 +2,7 @@
ikiwiki is a **wiki compiler**. It converts a directory full of wiki pages ikiwiki is a **wiki compiler**. It converts a directory full of wiki pages
into html pages suitable for publishing on a website. Unlike a traditional into html pages suitable for publishing on a website. Unlike a traditional
wiki, ikiwiki does not have its own means of storing page history or its own wiki, ikiwiki does not have its own means of storing page history or its own
markup language. Instead it uses [[Subversion]] and [[MarkDown]]. markup language. Instead it uses [[Subversion]] (or [[Git]]) and [[MarkDown]].
* [[News]] is a blog (built using ikiwiki) of news items about ikiwiki. It's the best way to find out when there's a new version to [[Download]]. * [[News]] is a blog (built using ikiwiki) of news items about ikiwiki. It's the best way to find out when there's a new version to [[Download]].

View File

@ -1,32 +1,19 @@
A post-commit hook is run every time you commit a change to your subversion A post-commit hook is run every time you commit a change to your
repository. To make the wiki be updated each time a commit is made, it can [[subversion]] (or [[git]]) repository. To make the wiki be updated each
be run from (or as) a post-commit hook. time a commit is made, it can be run from (or as) a post-commit hook.
The best way to run ikiwiki in a [[Subversion]] post-commit hook is using The best way to run ikiwiki in a post-commit hook is using a wrapper, which
a wrapper, which can be generated using `ikiwiki --wrapper`. ikiwiki is usually configured to generate using a setup file.
First, set up the subversion checkout that ikiwiki will update and compile
into your wiki at each subversion commit. Run ikiwiki a few times by hand
to get a feel for it. Now, generate the wrapper by adding "--wrapper"
to whatever command line you've been using to run ikiwiki. For example:
~/wiki-checkout> ikiwiki . ~/public_html/wiki
~/wiki-checkout> ikiwiki . ~/public_html/wiki --wrapper
successfully generated ikiwiki-wrap
The generated wrapper is a C program that is designed to safely be made The generated wrapper is a C program that is designed to safely be made
suid if necessary. It's hardcoded to run ikiwiki with the settings suid if necessary. It's hardcoded to run ikiwiki with the settings
specified when you ran --wrapper, and can only be used to update and specified when you ran --wrapper, and can only be used to update and
compile that one checkout into the specified html directory. compile that one checkout into the specified html directory.
Now, put the wrapper somewhere convenient, and create a post-commit hook Depending on your setup, the post-commit hook might end up
script in your subversion repository for the wiki. All the post-commit getting called by users who have write access to the repository, but not to
hook has to do is run the wrapper (with no parameters).
Depending on your Subversion setup, the post-commit hook might end up
getting called by users who have write access to subversion, but not to
your wiki checkout and html directory. If so, you can safely make your wiki checkout and html directory. If so, you can safely make
ikiwiki-wrap suid to a user who can write there (*not* to root!). You might the wrapper suid to a user who can write there (*not* to root!). You might
want to read [[Security]] first. want to read [[Security]] first.
[[setup]] explains setting this up in more detail. [[setup]] explains setting this up in more detail.

View File

@ -1 +1,3 @@
ikiwiki generates the list of recent changes by examining the [[Subversion]] commit log. You have to have [[CGI]] set up for this feature to be enabled. ikiwiki generates the list of recent changes by examining the
[[Subversion]] or [[Git]] commit log. You have to have [[CGI]] set up for
this feature to be enabled.

View File

@ -1,18 +1,28 @@
So you want to set up your own wiki using ikiwiki? This tutorial will walk So you want to set up your own wiki using ikiwiki? This tutorial will walk
you through setting up a wiki that is stored in [[Subversion]] and that has you through setting up a wiki that is stored in [[Subversion]] or [[Git]],
optional support for commits from the web. and that has optional support for commits from the web.
1. [[Install]] ikiwiki. See [[download]] for where to get it. 1. [[Install]] ikiwiki. See [[download]] for where to get it.
2. Create the subversion repository for your wiki. 2. Create the master rcs repository for your wiki.
# Subversion
svnadmin create /svn/wikirepo svnadmin create /svn/wikirepo
svn mkdir file:///svn/wikirepo/trunk -m create svn mkdir file:///svn/wikirepo/trunk -m create
# Git
mkdir /git/wikirepo
cd /git/wikirepo
git init-db
3. Check out the repository to make the working copy that ikiwiki will use. 3. Check out the repository to make the working copy that ikiwiki will use.
# Subversion
svn co file:///svn/wikirepo/trunk ~/wikiwc svn co file:///svn/wikirepo/trunk ~/wikiwc
# Git
git clone /git/wikirepo ~/wikiwc
4. Build your wiki for the first time. 4. Build your wiki for the first time.
ikiwiki --verbose ~/wikiwc/ ~/public_html/wiki/ \ ikiwiki --verbose ~/wikiwc/ ~/public_html/wiki/ \
@ -25,10 +35,18 @@ optional support for commits from the web.
used if you don't have a custom version, so let's start by making a used if you don't have a custom version, so let's start by making a
custom version of the wiki's index page: custom version of the wiki's index page:
cp /usr/share/ikiwiki/basewiki/index.mdwn ~/wikiwc cd ~/wikiwc
svn add ~/wikiwc/index.mdwn cp /usr/share/ikiwiki/basewiki/index.mdwn .
$EDITOR ~/wikiwc/index.mdwn $EDITOR index.mdwn
svn commit ~/wikiwc/index.mdwn -m customised
# Subversion
svn add index.mdwn
svn commit -m customised index.mdwn
# Git
git add index.mdwn
git commit -m customised index.mdwn
git push origin
You can also add any files you like from scratch of course. You can also add any files you like from scratch of course.
@ -46,15 +64,15 @@ optional support for commits from the web.
`doc/ikiwiki.setup` in the ikiwiki sources), and edit it. `doc/ikiwiki.setup` in the ikiwiki sources), and edit it.
Most of the options, like `wikiname` in the setup file are the same as Most of the options, like `wikiname` in the setup file are the same as
ikiwiki's command line options (documented in [[usage]]. `srcdir` ikiwiki's command line options (documented in [[usage]]. `srcdir` and
and `destdir` are the two directories you specify when `destdir` are the two directories you specify when running ikiwiki by
running ikiwiki by hand. `svnrepo` is the path to your subversion hand. `rcsrepo` is the path to your master rcs repository. Make sure
repository. Make sure that all of these are pointing to the right that all of these are pointing to the right directories, and read
directories, and read through and configure the rest of the file to your through and configure the rest of the file to your liking.
liking.
Note that the default file has a block to configure a svn wrapper. This Note that the default file has a block to configure an Rcs wrapper to
sets up a [[post-commit]] hook to update the wiki. update the wiki. You need to uncomment the related block for whatever
rcs you use and comment out the other rcs blocks.
When you're satisfied, run `ikiwiki --setup ikiwiki.setup`, and it When you're satisfied, run `ikiwiki --setup ikiwiki.setup`, and it
will set everything up and update your wiki. will set everything up and update your wiki.
@ -66,13 +84,21 @@ optional support for commits from the web.
`ikiwiki --setup ikiwiki.setup`, and you're done! `ikiwiki --setup ikiwiki.setup`, and you're done!
9. Add [[PageHistory]] links to the top of pages. This requires you to have 9. Add [[PageHistory]] links to the top of pages. This requires you to have
setup [[ViewCVS]] or something similar to access your [[Subversion]] setup a repository browser. For Subversion, you may use [[ViewCVS]] or
repository. The `historyurl` setting makes ikiwiki add the links, and something similar to access your [[Subversion]] repository. For Git,
in that url, "\[[file]]" is replaced with the name of the file to view. So [[Gitweb]] can be used.
edit ikiwiki.setup and set `historyurl` to something like this:
The `historyurl` setting makes ikiwiki add the links, and in that url,
"\[[file]]" is replaced with the name of the file to view. So edit
ikiwiki.setup and set `historyurl` to something like this for
Subversion:
`http://svn.host/trunk/\[[file]]?root=wiki` `http://svn.host/trunk/\[[file]]?root=wiki`
Or this for Git:
`http://git.host/gitweb.cgi?p=wiki.git;a=history;f=[[file]]`
Then run `ikiwiki --setup ikiwiki.setup` again. Then run `ikiwiki --setup ikiwiki.setup` again.
10. Enjoy your new wiki! Add yourself to [[IkiWikiUsers]] 10. Enjoy your new wiki! Add yourself to [[IkiWikiUsers]]

View File

@ -1,4 +1,9 @@
Subversion is a revision control system. While ikiwiki is relatively Subversion is a revision control system. While ikiwiki is relatively
independant of the underlying revision control system, and can easily be used without one, using it with Subversion is recommended. independant of the underlying revision control system, and can easily be
used without one, using it with Subversion is recommended since it's how
the author uses it.
Ikiwiki can run as a [[post-commit]] hook to update a wiki whenever commits come in. When running as a [[cgi]] with Subversion, ikiwiki automatically commits edited pages to the subversion repostory, and uses the Subversion log to generate the [[RecentChanges]] page. Ikiwiki can run as a [[post-commit]] hook to update a wiki whenever commits
come in. When running as a [[cgi]] with Subversion, ikiwiki automatically
commits edited pages to the subversion repostory, and uses the Subversion
log to generate the [[RecentChanges]] page.

View File

@ -46,7 +46,7 @@ These options control the mode that ikiwiki is operating in.
directory. The filename to use for the wrapper is optional. directory. The filename to use for the wrapper is optional.
The wrapper is designed to be safely made suid and be run by untrusted The wrapper is designed to be safely made suid and be run by untrusted
users, as a [[Subversion]] [[post-commit]] hook, or as a [[CGI]]. users, as a [[post-commit]] hook, or as a [[CGI]].
Note that the generated wrapper will ignore all command line parameters. Note that the generated wrapper will ignore all command line parameters.
@ -88,14 +88,17 @@ These options configure the wiki.
* --notify * --notify
Enable email notification of commits. This should be used when running Enable email notification of commits. This should be used when running
ikiwiki as a [[Subversion]] [[post-commit]] hook. ikiwiki as a [[post-commit]] hook.
* --rcs=svn, --no-rcs * --rcs=svn, --no-rcs
Enable or disable use of a revision control system. Enable or disable use of a revision control system.
If you use svn ([[Subversion]]), the `source` directory is assumed to be If you use svn, the `source` directory is assumed to be
a working copy, and is automatically updated before building the wiki. a [[Subversion]] working copy.
If you use git, the `source` directory is assumed to be a clone of the
[[git]] repository.
In [[CGI]] mode, with a revision control system enabled pages edited via In [[CGI]] mode, with a revision control system enabled pages edited via
the web will be committed. Also, the [[RecentChanges]] link will be placed the web will be committed. Also, the [[RecentChanges]] link will be placed
@ -164,8 +167,8 @@ These options configure the wiki.
* --plugin name * --plugin name
Enables the use of the specified plugin in the wiki. See [[plugins]] for Enables the use of the specified [[plugin|plugins]] in the wiki.
details. Note that plugin names are case sensative. Note that plugin names are case sensative.
* --disable-plugin name * --disable-plugin name

View File

@ -3,8 +3,13 @@ this a pretty Iky Wiki, since it's so different from other Wikis. Partly
because "ikiwiki" is a nice palindrome. Partly because its design turns because "ikiwiki" is a nice palindrome. Partly because its design turns
the usual design for a Wiki inside-out and backwards. the usual design for a Wiki inside-out and backwards.
(BTW, I'm told that "iki" is Finnish for "forever" so ikiwiki is "forever wiki".) (BTW, I'm told that "iki" is Finnish for "forever" so ikiwiki is "forever
wiki".)
Oh, maybe you wanted to know why you'd want to choose ikiwiki instead of all the other wikis out there? Unless your personal strangeness significantly aligns with [[Joey]]'s, so that keeping everything in subversion, compiling websites to static html, and like design [[features]] appeal to you, you probably won't. Oh, maybe you wanted to know why you'd want to choose ikiwiki instead of
all the other wikis out there? Unless your personal strangeness
significantly aligns with [[Joey]]'s, so that keeping everything in
subversion, compiling websites to static html, and like design [[features]]
appeal to you, you probably won't.
Hmm, the above paragraph is less true today than it was when I wrote it. Hmm, the above paragraph is less true today than it was when I wrote it.