Plugin: irker
Author: anarcat
Included in ikiwiki: no
Enabled by default: no
Included in goodstuff: no
Currently enabled: no

This plugin will configure your wiki to send IRC notifications using the irker notification bot.

It is fairly simple and requires no configuration but installation of the irker package. For template configuration, patches from Debian bug #824512 are necessary. Note that they have been factored into irker 2.18.

package IkiWiki::Plugin::irker;

use warnings;
use strict;
use IkiWiki 3.00;

sub import {
    hook(type => "getsetup", id => "irker", call => \&getsetup);
    hook(type => "checkconfig", id => "branchable", call => \&checkconfig,
         first => 1);
    hook(type => "genwrapper", id => "irker", call => \&genwrapper,
         last => 1);
}

sub getsetup() {
    return
        plugin => {
            safe => 0,
            rebuild => undef,
            section => "core",
        },
        irker_channels => {
            type => "string",
            example => ['ircs://irc.example.com/example'],
            description => "IRC channels to send notifications to",
            safe => 1,
            rebuild => 0,
        },
        irker_template => {
            type => "string",
            example => "'%(bold)s%(project)s:%(reset)s %(green)s%(author)s%(reset)s %(repo)s:%(yellow)s%(branch)s%(reset)s * %(bold)s%(rev)s%(reset)s / %(bold)s%(files)s%(reset)s: %(logmsg)s %(brown)s%(url)s%(reset)s",
            description => "Template to use for messages. Only supported with patch from https://bugs.debian.org/824512",
            safe => 1,
            rebuild => 0,
        },
        irker_hook => {
            type => "string",
            example => "irkerhook-git",
            description => 'Hook to setup for notifications, will look in $PATH if File::Which is available, otherwise use absolute path.',
            safe => 1,
            rebuild => 0,
        },
}

sub checkconfig {
    use URI; # ikiwiki Depends on it
    foreach my $channel (@{$config{'irker_channels'}}) {
        my $uri = URI->new( $channel );
        # inspired by http://stackoverflow.com/a/2599378/1174784
        # and http://stackoverflow.com/a/4953329/1174784
        if (!$uri->scheme || $uri->path =~ m/^([#&]?[^\x07\x2C\s]{,200})/) {
            error("$channel is not a valid IRC channel URI");
        }
    }
    # check if hook exists
    if (-x $config{irker_hook}) {
        # shortcut: already configured
        return;
    }
    eval q{use File::Which};
    # check with which, i available
    if (!$@) {
        my $hook;
        if (!defined $config{'irker_hook'}) {
            $config{'irker_hook'} = 'irkerhook-git';
        }
        $hook = which($config{'irker_hook'});
        if (defined $hook) {
            $config{'irker_hook'} = $hook;
        }
        else {
            error("irker hook '$config{irker_hook}' not found in PATH");
        }
    }
    if (!-x $config{irker_hook}) {
        error("irker hook '$config{irker_hook}' not executable");
    }
}

# Parses git_wrapper to find out where the git repository is.
# cargo-culted from branchable.pm
sub find_git_repository {
    if ($config{rcs} eq 'git' &&
        $config{git_wrapper}=~m!^(.*)/hooks/post-update$!) {
        return $1;
    }
    else {
        return undef;
    }
}

# setup the hook symlink and git configuration
sub genwrapper() {
    my $repo=find_git_repository();
    if (defined $repo && defined $config{'irker_channels'}) {
        if (!-l $repo . '/hooks/post-receive') {
            if (-e $repo . '/hooks/post-receive') {
                error('post-receive hook exists and is not a symlink, failed to setup hook');
            }
            symlink($config{'irker_hook'}, $repo . '/hooks/post-receive') || error('failed to symlink: $!');
        }
        my $channels = join(",", @{$config{'irker_channels'}});
        system { 'git' } ('config', '-C', $repo, 'config', 'irker.channels', $channels);
        system { 'git' } ('config', '-C', $repo, 'config', 'irker.channels', $config{'wikiname'});
        if ($config{'irker_template'}) {
            exec { 'git' } ('config', '-C', $repo, 'config', 'irker.channels', $config{'irker_template'});
        }
    }
    else {
        system { 'git' } ('config', '-C', $repo, 'config', '--remove-section', 'irker');
        if (-l $repo . '/hooks/post-receive' && 
            readlink($repo . '/hooks/post-receive') =~ m/irkerhook/) {
            unlink($repo . '/hooks/post-receive');
        }
    }
    return "";
}

1