+ikiwiki.setup
Makefile
Makefile.old
blib/*
memoize("pagespec_translate");
memoize("file_pruned");
+sub getsetup () { #{{{
+ wikiname => {
+ type => "string",
+ default => "wiki",
+ description => "name of the wiki",
+ safe => 1,
+ rebuild => 1,
+ },
+ srcdir => {
+ type => "string",
+ default => undef,
+ example => "$ENV{HOME}/wiki",
+ description => "where the source of the wiki is located",
+ safe => 0, # path
+ rebuild => 1,
+ },
+ destdir => {
+ type => "string",
+ default => undef,
+ example => "/var/www/wiki",
+ description => "where to build the wiki",
+ safe => 0, # path
+ rebuild => 1,
+ },
+ adminuser => {
+ type => "string",
+ default => [],
+ description => "user names of wiki admins",
+ safe => 1,
+ rebuild => 0,
+ },
+ adminemail => {
+ type => "string",
+ default => undef,
+ example => 'me@example.com',
+ description => "contact email for wiki",
+ safe => 1,
+ rebuild => 0,
+ },
+ url => {
+ type => "string",
+ default => '',
+ example => "http://example.com/wiki",
+ description => "base url to the wiki",
+ safe => 1,
+ rebuild => 1,
+ },
+ cgiurl => {
+ type => "string",
+ default => '',
+ example => "http://example.com/wiki/ikiwiki.cgi",
+ description => "url to the ikiwiki.cgi",
+ safe => 1,
+ rebuild => 1,
+ },
+ cgi_wrapper => {
+ type => "string",
+ default => '',
+ example => "/var/www/wiki/ikiwiki.cgi",
+ description => "cgi executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ cgi_wrappermode => {
+ type => "string",
+ default => '06755',
+ description => "mode for cgi_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ rcs => {
+ type => "string",
+ default => '',
+ description => "rcs backend to use",
+ safe => 0, # don't allow overriding
+ rebuild => 0,
+ },
+ default_plugins => {
+ type => "internal",
+ default => [qw{mdwn link inline htmlscrubber passwordauth
+ openid signinedit lockedit conditional
+ recentchanges parentlinks}],
+ description => "plugins to enable by default",
+ safe => 1,
+ rebuild => 1,
+ },
+ add_plugins => {
+ type => "string",
+ default => [],
+ description => "plugins to add to the default configuration",
+ safe => 1,
+ rebuild => 1,
+ },
+ disable_plugins => {
+ type => "string",
+ default => [],
+ description => "plugins to disable",
+ safe => 1,
+ rebuild => 1,
+ },
+ templatedir => {
+ type => "string",
+ default => "$installdir/share/ikiwiki/templates",
+ description => "location of template files",
+ safe => 0, # path
+ rebuild => 1,
+ },
+ underlaydir => {
+ type => "string",
+ default => "$installdir/share/ikiwiki/basewiki",
+ description => "base wiki source location",
+ safe => 0, # path
+ rebuild => 0,
+ },
+ wrappers => {
+ type => "internal",
+ default => [],
+ description => "wrappers to generate",
+ safe => 0,
+ rebuild => 0,
+ },
+ underlaydirs => {
+ type => "internal",
+ default => [],
+ description => "additional underlays to use",
+ safe => 0,
+ rebuild => 0,
+ },
+ verbose => {
+ type => "boolean",
+ default => 0,
+ description => "display verbose messages when building?",
+ safe => 1,
+ rebuild => 0,
+ },
+ syslog => {
+ type => "boolean",
+ default => 0,
+ description => "log to syslog?",
+ safe => 1,
+ rebuild => 0,
+ },
+ usedirs => {
+ type => "boolean",
+ default => 1,
+ description => "create output files named page/index.html?",
+ safe => 0, # changing requires manual transition
+ rebuild => 1,
+ },
+ prefix_directives => {
+ type => "boolean",
+ default => 0,
+ description => "use '!'-prefixed preprocessor directives?",
+ safe => 0, # changing requires manual transition
+ rebuild => 1,
+ },
+ discussion => {
+ type => "boolean",
+ default => 1,
+ description => "enable Discussion pages?",
+ safe => 1,
+ rebuild => 1,
+ },
+ default_pageext => {
+ type => "string",
+ default => "mdwn",
+ description => "extension to use for new pages",
+ safe => 0, # not sanitized
+ rebuild => 0,
+ },
+ htmlext => {
+ type => "string",
+ default => "html",
+ description => "extension to use for html files",
+ safe => 0, # not sanitized
+ rebuild => 1,
+ },
+ timeformat => {
+ type => "string",
+ default => '%c',
+ description => "strftime format string to display date",
+ safe => 1,
+ rebuild => 1,
+ },
+ locale => {
+ type => "string",
+ default => undef,
+ example => "en_US.UTF-8",
+ description => "UTF-8 locale to use",
+ safe => 0,
+ rebuild => 1,
+ },
+ sslcookie => {
+ type => "boolean",
+ default => 0,
+ description => "only send cookies over SSL connections?",
+ safe => 1,
+ rebuild => 0,
+ },
+ userdir => {
+ type => "string",
+ default => "",
+ example => "users",
+ description => "put user pages below specified page",
+ safe => 1,
+ rebuild => 1,
+ },
+ numbacklinks => {
+ type => "integer",
+ default => 10,
+ description => "how many backlinks to show before hiding excess (0 to show all)",
+ safe => 1,
+ rebuild => 1,
+ },
+ hardlink => {
+ type => "boolean",
+ default => 0,
+ description => "attempt to hardlink source files? (optimisation for large files)",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ umask => {
+ type => "integer",
+ description => "",
+ example => "022",
+ description => "force ikiwiki to use a particular umask",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ libdir => {
+ type => "string",
+ default => "",
+ example => "$ENV{HOME}/.ikiwiki/",
+ description => "extra library and plugin directory",
+ safe => 0, # directory
+ rebuild => 0,
+ },
+ ENV => {
+ type => "string",
+ default => {},
+ description => "environment variables",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ exclude => {
+ type => "string",
+ default => undef,
+ example => '\.wav$',
+ description => "regexp of source files to ignore",
+ safe => 0, # regexp
+ rebuild => 1,
+ },
+ wiki_file_prune_regexps => {
+ type => "internal",
+ default => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./,
+ qr/\.x?html?$/, qr/\.ikiwiki-new$/,
+ qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
+ qr/(^|\/)_MTN\//,
+ qr/\.dpkg-tmp$/],
+ description => "regexps of source files to ignore",
+ safe => 0,
+ rebuild => 1,
+ },
+ wiki_file_regexp => {
+ type => "internal",
+ default => qr/(^[-[:alnum:]_.:\/+]+$)/,
+ description => "regexp of legal source files",
+ safe => 0,
+ rebuild => 1,
+ },
+ web_commit_regexp => {
+ type => "internal",
+ default => qr/^web commit (by (.*?(?=: |$))|from (\d+\.\d+\.\d+\.\d+)):?(.*)/,
+ description => "regexp to parse web commits from logs",
+ safe => 0,
+ rebuild => 0,
+ },
+ cgi => {
+ type => "internal",
+ default => 0,
+ description => "run as a cgi",
+ safe => 0,
+ rebuild => 0,
+ },
+ cgi_disable_uploads => {
+ type => "internal",
+ default => 1,
+ description => "whether CGI should accept file uploads",
+ safe => 0,
+ rebuild => 0,
+ },
+ post_commit => {
+ type => "internal",
+ default => 0,
+ description => "run as a post-commit hook",
+ safe => 0,
+ rebuild => 0,
+ },
+ rebuild => {
+ type => "internal",
+ default => 0,
+ description => "running in rebuild mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ refresh => {
+ type => "internal",
+ default => 0,
+ description => "running in refresh mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ getctime => {
+ type => "internal",
+ default => 0,
+ description => "running in getctime mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ w3mmode => {
+ type => "internal",
+ default => 0,
+ description => "running in w3mmode",
+ safe => 0,
+ rebuild => 0,
+ },
+ setup => {
+ type => "internal",
+ default => undef,
+ description => "setup file to read",
+ safe => 0,
+ rebuild => 0,
+ },
+} #}}}
+
sub defaultconfig () { #{{{
- return
- wiki_file_prune_regexps => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./,
- qr/\.x?html?$/, qr/\.ikiwiki-new$/,
- qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
- qr/(^|\/)_MTN\//,
- qr/\.dpkg-tmp$/],
- wiki_file_regexp => qr/(^[-[:alnum:]_.:\/+]+$)/,
- web_commit_regexp => qr/^web commit (by (.*?(?=: |$))|from (\d+\.\d+\.\d+\.\d+)):?(.*)/,
- verbose => 0,
- syslog => 0,
- wikiname => "wiki",
- default_pageext => "mdwn",
- htmlext => "html",
- cgi => 0,
- post_commit => 0,
- rcs => '',
- url => '',
- cgiurl => '',
- historyurl => '',
- diffurl => '',
- rss => 0,
- atom => 0,
- allowrss => 0,
- allowatom => 0,
- discussion => 1,
- rebuild => 0,
- refresh => 0,
- getctime => 0,
- w3mmode => 0,
- wrapper => undef,
- wrappermode => undef,
- svnpath => "trunk",
- gitorigin_branch => "origin",
- gitmaster_branch => "master",
- srcdir => undef,
- destdir => undef,
- pingurl => [],
- templatedir => "$installdir/share/ikiwiki/templates",
- underlaydir => "$installdir/share/ikiwiki/basewiki",
- underlaydirs => [],
- setup => undef,
- adminuser => undef,
- adminemail => undef,
- plugin => [qw{mdwn link inline htmlscrubber passwordauth openid
- signinedit lockedit conditional recentchanges
- parentlinks}],
- libdir => undef,
- timeformat => '%c',
- locale => undef,
- sslcookie => 0,
- httpauth => 0,
- userdir => "",
- usedirs => 1,
- numbacklinks => 10,
- account_creation_password => "",
- prefix_directives => 0,
- hardlink => 0,
- cgi_disable_uploads => 1,
+ my %s=getsetup();
+ my @ret;
+ foreach my $key (keys %s) {
+ push @ret, $key, $s{$key}->{default};
+ }
+ use Data::Dumper;
+ return @ret;
} #}}}
sub checkconfig () { #{{{
unless exists $config{wikistatedir};
if ($config{rcs}) {
- eval qq{use IkiWiki::Rcs::$config{rcs}};
- if ($@) {
- error("Failed to load RCS module IkiWiki::Rcs::$config{rcs}: $@");
- }
+ loadplugin($config{rcs});
}
else {
- require IkiWiki::Rcs::Stub;
+ loadplugin("norcs");
}
- if (exists $config{umask}) {
+ if (defined $config{umask}) {
umask(possibly_foolish_untaint($config{umask}));
}
return 1;
} #}}}
+sub listplugins () { #{{{
+ my %ret;
+
+ foreach my $dir (@INC, $config{libdir}) {
+ next unless defined $dir && length $dir;
+ foreach my $file (glob("$dir/IkiWiki/Plugin/*.pm")) {
+ my ($plugin)=$file=~/.*\/(.*)\.pm$/;
+ $ret{$plugin}=1;
+ }
+ }
+ foreach my $dir ($config{libdir}, "$installdir/lib/ikiwiki") {
+ next unless defined $dir && length $dir;
+ foreach my $file (glob("$dir/plugins/*")) {
+ $ret{basename($file)}=1 if -x $file;
+ }
+ }
+
+ return keys %ret;
+} #}}}
+
sub loadplugins () { #{{{
- if (defined $config{libdir}) {
+ if (defined $config{libdir} && length $config{libdir}) {
unshift @INC, possibly_foolish_untaint($config{libdir});
}
- loadplugin($_) foreach @{$config{plugin}};
+ loadplugin($_) foreach @{$config{default_plugins}}, @{$config{add_plugins}};
run_hooks(getopt => sub { shift->() });
if (grep /^-/, @ARGV) {
return 1;
} #}}}
+sub rcs_update () { #{{{
+ $hooks{rcs}{rcs_update}{call}->(@_);
+} #}}}
+
+sub rcs_prepedit ($) { #{{{
+ $hooks{rcs}{rcs_prepedit}{call}->(@_);
+} #}}}
+
+sub rcs_commit ($$$;$$) { #{{{
+ $hooks{rcs}{rcs_commit}{call}->(@_);
+} #}}}
+
+sub rcs_commit_staged ($$$) { #{{{
+ $hooks{rcs}{rcs_commit_staged}{call}->(@_);
+} #}}}
+
+sub rcs_add ($) { #{{{
+ $hooks{rcs}{rcs_add}{call}->(@_);
+} #}}}
+
+sub rcs_remove ($) { #{{{
+ $hooks{rcs}{rcs_remove}{call}->(@_);
+} #}}}
+
+sub rcs_rename ($$) { #{{{
+ $hooks{rcs}{rcs_rename}{call}->(@_);
+} #}}}
+
+sub rcs_recentchanges ($) { #{{{
+ $hooks{rcs}{rcs_recentchanges}{call}->(@_);
+} #}}}
+
+sub rcs_diff ($) { #{{{
+ $hooks{rcs}{rcs_diff}{call}->(@_);
+} #}}}
+
+sub rcs_getctime ($) { #{{{
+ $hooks{rcs}{rcs_getctime}{call}->(@_);
+} #}}}
+
sub globlist_to_pagespec ($) { #{{{
my @globlist=split(' ', shift);
sub import { #{{{
hook(type => "getopt", id => "aggregate", call => \&getopt);
+ hook(type => "getsetup", id => "aggregate", call => \&getsetup);
hook(type => "checkconfig", id => "aggregate", call => \&checkconfig);
hook(type => "needsbuild", id => "aggregate", call => \&needsbuild);
hook(type => "preprocess", id => "aggregate", call => \&preprocess);
);
} #}}}
+sub getsetup () { #{{{
+ return
+ aggregateinternal => {
+ type => "boolean",
+ example => 0,
+ description => "enable aggregation to internal pages?",
+ safe => 0, # enabling needs manual transition
+ rebuild => 0,
+ },
+ aggregate_webtrigger => {
+ type => "boolean",
+ example => 0,
+ description => "allow aggregation to be triggered via the web?",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
sub checkconfig () { #{{{
if ($config{aggregate} && ! ($config{post_commit} &&
IkiWiki::commit_hook_enabled())) {
sub import { #{{{
hook(type => "getopt", id => "amazon_s3", call => \&getopt);
+ hook(type => "getsetup", id => "amazon_s3", call => \&getsetup);
hook(type => "checkconfig", id => "amazon_s3", call => \&checkconfig);
} # }}}
});
} #}}}
+sub getsetup () { #{{{
+ return
+ amazon_s3_key_id => {
+ type => "string",
+ example => "XXXXXXXXXXXXXXXXXXXX",
+ description => "public access key id",
+ safe => 1,
+ rebuild => 0,
+ },
+ amazon_s3_key_id => {
+ type => "string",
+ example => "$ENV{HOME}/.s3_key",
+ description => "file holding secret key (must not be readable by others!)",
+ safe => 0, # ikiwiki reads this file
+ rebuild => 0,
+ },
+ amazon_s3_bucket => {
+ type => "string",
+ example => "mywiki",
+ description => "globally unique name of bucket to store wiki in",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_prefix => {
+ type => "string",
+ example => "wiki/",
+ description => "a prefix to prepend to each page name",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_location => {
+ type => "string",
+ example => "EU",
+ description => "which S3 datacenter to use (leave blank for default)",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_dupindex => {
+ type => "boolean",
+ example => 0,
+ description => "store each index file twice? (allows urls ending in \"/index.html\" and \"/\")",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub checkconfig { #{{{
foreach my $field (qw{amazon_s3_key_id amazon_s3_key_file
amazon_s3_bucket}) {
use IkiWiki 2.00;
sub import { #{{{
- hook(type => "canedit", id => "anonok", call => \&canedit,);
+ hook(type => "getsetup", id => "anonok", call => \&getsetup);
+ hook(type => "canedit", id => "anonok", call => \&canedit);
} # }}}
+sub getsetup () { #{{{
+ return
+ anonok_pagespec => {
+ type => "string",
+ example => "*/discussion",
+ description => "PageSpec to limit which pages anonymous users can edit",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
sub canedit ($$$) { #{{{
my $page=shift;
my $cgi=shift;
use IkiWiki 2.00;
sub import { #{{{
+ hook(type => "getsetup", id => "attachment", call => \&getsetup);
hook(type => "checkconfig", id => "attachment", call => \&checkconfig);
hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup);
hook(type => "formbuilder", id => "attachment", call => \&formbuilder);
} # }}}
+sub getsetup () { #{{{
+ return
+ virus_checker => {
+ type => "string",
+ example => "clamdscan -",
+ description => "virus checker program (reads STDIN, returns nonzero if virus found)",
+ safe => 0, # executed
+ rebuild => 0,
+ },
+} #}}}
+
sub check_canattach ($$;$) { #{{{
my $session=shift;
my $dest=shift; # where it's going to be put, under the srcdir
#!/usr/bin/perl
-
-package IkiWiki;
+package IkiWiki::Plugin::bzr;
use warnings;
use strict;
use Encode;
use open qw{:utf8 :std};
+sub import { #{{{
+ hook(type => "checkconfig", id => "bzr", call => \&checkconfig);
+ hook(type => "getsetup", id => "bzr", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
+ if (defined $config{bzr_wrapper} && length $config{bzr_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{bzr_wrapper},
+ wrappermode => (defined $config{bzr_wrappermode} ? $config{bzr_wrappermode} : "06755"),
+ };
+ }
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ bzr_wrapper => {
+ type => "string",
+ #example => "", # FIXME add example
+ description => "bzr post-commit executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ bzr_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for bzr_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ #example => "", # FIXME add example
+ description => "url to show file history, using loggerhead ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s",
+ description => "url to view a diff, using loggerhead ([[file]] and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub bzr_log ($) { #{{{
my $out = shift;
my @infos = ();
my ($user, $ipaddr) = @_;
if (defined $user) {
- return possibly_foolish_untaint($user);
+ return IkiWiki::possibly_foolish_untaint($user);
}
elsif (defined $ipaddr) {
- return "Anonymous from ".possibly_foolish_untaint($ipaddr);
+ return "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr);
}
else {
return "Anonymous";
$user = bzr_author($user, $ipaddr);
- $message = possibly_foolish_untaint($message);
+ $message = IkiWiki::possibly_foolish_untaint($message);
if (! length $message) {
$message = "no message given";
}
$user = bzr_author($user, $ipaddr);
- $message = possibly_foolish_untaint($message);
+ $message = IkiWiki::possibly_foolish_untaint($message);
if (! length $message) {
$message = "no message given";
}
sub rcs_rename ($$) { # {{{
my ($src, $dest) = @_;
- my $parent = dirname($dest);
+ my $parent = IkiWiki::dirname($dest);
if (system("bzr", "add", "--quiet", "$config{srcdir}/$parent") != 0) {
warn("bzr add $parent failed\n");
}
# Skip source name in renames
$filename =~ s/^.* => //;
- my $diffurl = $config{'diffurl'};
+ my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
$diffurl =~ s/\[\[file\]\]/$filename/go;
$diffurl =~ s/\[\[file-id\]\]/$fileid/go;
$diffurl =~ s/\[\[r2\]\]/$info->{revno}/go;
my @now=localtime($time);
sub import { #{{{
- hook(type => "needsbuild", id => "version", call => \&needsbuild);
+ hook(type => "getsetup", id => "calendar", call => \&getsetup);
+ hook(type => "needsbuild", id => "calendar", call => \&needsbuild);
hook(type => "preprocess", id => "calendar", call => \&preprocess);
} #}}}
+sub getsetup () { #{{{
+ return
+ archivebase => {
+ type => "string",
+ example => "archives",
+ description => "base of the archives hierarchy",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub is_leap_year (@) { #{{{
my %params=@_;
return ($params{year} % 4 == 0 && (($params{year} % 100 != 0) || $params{year} % 400 == 0));
#!/usr/bin/perl
-
-package IkiWiki;
+package IkiWiki::Plugin::git;
use warnings;
use strict;
my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes
-sub _safe_git (&@) { #{{{
+sub import { #{{{
+ hook(type => "checkconfig", id => "git", call => \&checkconfig);
+ hook(type => "getsetup", id => "git", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
+ if (! defined $config{gitorigin_branch}) {
+ $config{gitorigin_branch}="origin";
+ }
+ if (! defined $config{gitmaster_branch}) {
+ $config{gitmaster_branch}="master";
+ }
+ if (defined $config{git_wrapper} && length $config{git_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{git_wrapper},
+ wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"),
+ };
+ }
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ git_wrapper => {
+ type => "string",
+ example => "/git/wiki.git/hooks/post-update",
+ description => "git post-update executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ git_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for git_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=history;f=[[file]]",
+ description => "gitweb url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=blobdiff;h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_parent]];f=[[file]]",
+ description => "gitweb url to show a diff ([[sha1_to]], [[sha1_from]], [[sha1_parent]], and [[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ gitorigin_branch => {
+ type => "string",
+ example => "origin",
+ description => "where to pull and push changes (set to empty string to disable)",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ gitmaster_branch => {
+ type => "string",
+ example => "master",
+ description => "branch that the wiki is stored in",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+} #}}}
+
+sub safe_git (&@) { #{{{
# Start a child process safely without resorting /bin/sh.
# Return command output or success state (in scalar context).
return wantarray ? @lines : ($? == 0);
}
# Convenient wrappers.
-sub run_or_die ($@) { _safe_git(\&error, @_) }
-sub run_or_cry ($@) { _safe_git(sub { warn @_ }, @_) }
-sub run_or_non ($@) { _safe_git(undef, @_) }
+sub run_or_die ($@) { safe_git(\&error, @_) }
+sub run_or_cry ($@) { safe_git(sub { warn @_ }, @_) }
+sub run_or_non ($@) { safe_git(undef, @_) }
#}}}
-sub _merge_past ($$$) { #{{{
+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
return $conflict;
} #}}}
-sub _parse_diff_tree ($@) { #{{{
+sub parse_diff_tree ($@) { #{{{
# Parse the raw diff tree chunk and return the info hash.
# See git-diff-tree(1) for the syntax.
my ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix');
my @ci;
- while (my $parsed = _parse_diff_tree(($prefix or ""), \@raw_lines)) {
+ while (my $parsed = parse_diff_tree(($prefix or ""), \@raw_lines)) {
push @ci, $parsed;
}
my ($prev) = $rcstoken =~ /^($sha1_pattern)$/; # untaint
if (defined $cur && defined $prev && $cur ne $prev) {
- my $conflict = _merge_past($prev, $file, $dummy_commit_msg);
+ my $conflict = merge_past($prev, $file, $dummy_commit_msg);
return $conflict if defined $conflict;
}
# git commit returns non-zero if file has not been really changed.
# so we should ignore its exit status (hence run_or_non).
- $message = possibly_foolish_untaint($message);
+ $message = IkiWiki::possibly_foolish_untaint($message);
if (run_or_non('git', 'commit', '--cleanup=verbatim',
'-q', '-m', $message)) {
if (length $config{gitorigin_branch}) {
foreach my $detail (@{ $ci->{'details'} }) {
my $file = $detail->{'file'};
- my $diffurl = $config{'diffurl'};
+ my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
$diffurl =~ s/\[\[file\]\]/$file/go;
$diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
$diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go;
use IPC::Open2;
sub import { #{{{
- hook(type => "preprocess", id => "graph", call => \&graph);
+ hook(type => "preprocess", id => "graphviz", call => \&graph);
} # }}}
my %graphviz_programs = (
sub import { #{{{
hook(type => "getopt", id => "inline", call => \&getopt);
+ hook(type => "getsetup", id => "inline", call => \&getsetup);
hook(type => "checkconfig", id => "inline", call => \&checkconfig);
hook(type => "sessioncgi", id => "inline", call => \&sessioncgi);
hook(type => "preprocess", id => "inline",
# pings interrupting page builds.
hook(type => "change", id => "inline",
call => \&IkiWiki::pingurl);
-
} # }}}
sub getopt () { #{{{
"atom!" => \$config{atom},
"allowrss!" => \$config{allowrss},
"allowatom!" => \$config{allowatom},
+ "pingurl=s" => sub {
+ push @{$config{pingurl}}, $_[1];
+ },
);
-}
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ rss => {
+ type => "boolean",
+ example => 0,
+ description => "enable rss feeds by default?",
+ safe => 1,
+ rebuild => 1,
+ },
+ atom => {
+ type => "boolean",
+ example => 0,
+ description => "enable atom feeds by default?",
+ safe => 1,
+ rebuild => 1,
+ },
+ allowrss => {
+ type => "boolean",
+ example => 0,
+ description => "allow rss feeds to be used?",
+ safe => 1,
+ rebuild => 1,
+ },
+ allowatom => {
+ type => "boolean",
+ example => 0,
+ description => "allow atom feeds to be used?",
+ safe => 1,
+ rebuild => 1,
+ },
+ pingurl => {
+ type => "string",
+ example => "http://rpc.technorati.com/rpc/ping",
+ description => "urls to ping (using XML-RPC) on feed update",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
sub checkconfig () { #{{{
if (($config{rss} || $config{atom}) && ! length $config{url}) {
if ($config{atom}) {
push @{$config{wiki_file_prune_regexps}}, qr/\.atom$/;
}
+ if (! exists $config{pingurl}) {
+ $config{pingurl}=[];
+ }
} #}}}
sub format (@) { #{{{
my $atomurl=basename(atompage($params{destpage}).$feednum) if $feeds && $atom;
my $ret="";
- if ($config{cgiurl} && ! $params{preview} && (exists $params{rootpage} ||
+ if (length $config{cgiurl} && ! $params{preview} && (exists $params{rootpage} ||
(exists $params{postform} && yesno($params{postform})))) {
# Add a blog post form, with feed buttons.
my $formtemplate=template("blogpost.tmpl", blind_cache => 1);
use IkiWiki 2.00;
sub import { #{{{
+ hook(type => "getsetup", id => "mdwn", call => \&getsetup);
hook(type => "htmlize", id => "mdwn", call => \&htmlize);
} # }}}
+sub getsetup () { #{{{
+ return
+ multimarkdown => {
+ type => "boolean",
+ example => 0,
+ description => "enable multimarkdown features?",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
my $markdown_sub;
sub htmlize (@) { #{{{
my %params=@_;
if (exists $config{multimarkdown} && $config{multimarkdown}) {
eval q{use Text::MultiMarkdown};
if ($@) {
- error(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed"));
+ debug(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed"));
}
$markdown_sub=sub {
Text::MultiMarkdown::markdown(shift, {use_metadata => 0});
}
}
- else {
+ if (! defined $markdown_sub) {
eval q{use Text::Markdown};
if (! $@) {
if (Text::Markdown->can('markdown')) {
#!/usr/bin/perl
-
-package IkiWiki;
+package IkiWiki::Plugin::mercurial;
use warnings;
use strict;
use Encode;
use open qw{:utf8 :std};
-sub mercurial_log($) {
+sub import { #{{{
+ hook(type => "checkconfig", id => "mercurial", call => \&checkconfig);
+ hook(type => "getsetup", id => "mercurial", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
+ if (exists $config{mercurial_wrapper} && length $config{mercurial_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{mercurial_wrapper},
+ wrappermode => (defined $config{mercurial_wrappermode} ? $config{mercurial_wrappermode} : "06755"),
+ };
+ }
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ mercurial_wrapper => {
+ type => "string",
+ #example => # FIXME add example
+ description => "mercurial post-commit executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ mercurial_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for mercurial_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://example.com:8000/log/tip/[[file]]",
+ description => "url to hg serve'd repository, to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://localhost:8000/?fd=[[r2]];file=[[file]]",
+ description => "url to hg serve'd repository, to show diff ([[file]] and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
+sub mercurial_log ($) { #{{{
my $out = shift;
my @infos;
close $out;
return @infos;
-}
+} #}}}
sub rcs_update () { #{{{
my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update");
my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
if (defined $user) {
- $user = possibly_foolish_untaint($user);
+ $user = IkiWiki::possibly_foolish_untaint($user);
}
elsif (defined $ipaddr) {
- $user = "Anonymous from ".possibly_foolish_untaint($ipaddr);
+ $user = "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr);
}
else {
$user = "Anonymous";
}
- $message = possibly_foolish_untaint($message);
+ $message = IkiWiki::possibly_foolish_untaint($message);
if (! length $message) {
$message = "no message given";
}
}
foreach my $file (split / /,$info->{files}) {
- my $diffurl = $config{'diffurl'};
+ my $diffurl = defined $config{diffurl} ? $config{'diffurl'} : "";
$diffurl =~ s/\[\[file\]\]/$file/go;
$diffurl =~ s/\[\[r2\]\]/$info->{changeset}/go;
use IkiWiki 2.00;
sub import { #{{{
+ hook(type => "getsetup", id => "mirrorlist", call => \&getsetup);
hook(type => "pagetemplate", id => "mirrorlist", call => \&pagetemplate);
} # }}}
+sub getsetup () { #{{{
+ return
+ mirrorlist => {
+ type => "string",
+ example => {},
+ description => "list of mirrors",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub pagetemplate (@) { #{{{
my %params=@_;
my $template=$params{template};
#!/usr/bin/perl
-
-package IkiWiki;
+package IkiWiki::Plugin::monotone;
use warnings;
use strict;
my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate sha1sums
-sub check_config() { #{{{
+sub import { #{{{
+ hook(type => "checkconfig", id => "monotone", call => \&checkconfig);
+ hook(type => "getsetup", id => "monotone", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
if (!defined($config{mtnrootdir})) {
$config{mtnrootdir} = $config{srcdir};
}
error("Ikiwiki srcdir does not seem to be a Monotone workspace (or set the mtnrootdir)!");
}
- chdir $config{srcdir}
- or error("Cannot chdir to $config{srcdir}: $!");
-
my $child = open(MTN, "-|");
if (! $child) {
open STDERR, ">/dev/null";
if ($version < 0.38) {
error("Monotone version too old, is $version but required 0.38");
}
+
+ if (length $config{mtn_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{mtn_wrapper},
+ wrappermode => (defined $config{mtn_wrappermode} ? $config{mtn_wrappermode} : "06755"),
+ };
+ }
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ mtn_wrapper => {
+ type => "string",
+ example => "/srv/mtn/wiki/_MTN/ikiwiki-netsync-hook",
+ description => "monotone netsync hook executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ mtn_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for mtn_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ mtnkey => {
+ type => "string",
+ example => 'web@example.com',
+ description => "your monotone key",
+ safe => 1,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://viewmtn.example.com/branch/head/filechanges/com.example.branch/[[file]]",
+ description => "viewmtn url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://viewmtn.example.com/revision/diff/[[r1]]/with/[[r2]]/[[file]]",
+ description => "viewmtn url to show a diff ([[r1]], [[r2]], and [[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ mtnsync => {
+ type => "boolean",
+ example => 0,
+ description => "sync on update and commit?",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ mtnrootdir => {
+ type => "string",
+ description => "path to your workspace (defaults to the srcdir; specify if the srcdir is a subdirectory of the workspace)",
+ safe => 0, # path
+ rebuild => 0,
+ },
} #}}}
sub get_rev () { #{{{
return $mergeRev;
} #}}}
-sub commit_file_to_new_rev($$$$$$$$) { #{{{
+sub commit_file_to_new_rev ($$$$$$$$) { #{{{
my $automator=shift;
my $wsfilename=shift;
my $oldFileID=shift;
} #}}}
sub rcs_update () { #{{{
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
if (defined($config{mtnsync}) && $config{mtnsync}) {
if (system("mtn", "--root=$config{mtnrootdir}", "sync",
sub rcs_prepedit ($) { #{{{
my $file=shift;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
# For monotone, return the revision of the file when
# editing begins.
$author="Web: Anonymous";
}
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
my ($oldrev)= $rcstoken=~ m/^($sha1_pattern)$/; # untaint
my $rev = get_rev();
if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
"--author", $author, "--key", $config{mtnkey}, "-m",
- possibly_foolish_untaint($message), $file) != 0) {
+ IkiWiki::possibly_foolish_untaint($message), $file) != 0) {
debug("Traditional commit failed! Returning data as conflict.");
my $conflict=readfile("$config{srcdir}/$file");
if (system("mtn", "--root=$config{mtnrootdir}", "revert",
# Note - this will also commit any spurious changes that happen to be
# lying around in the working copy. There shouldn't be any, but...
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
my $author;
if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
"--author", $author, "--key", $config{mtnkey}, "-m",
- possibly_foolish_untaint($message)) != 0) {
+ IkiWiki::possibly_foolish_untaint($message)) != 0) {
error("Monotone commit failed");
}
}
sub rcs_add ($) { #{{{
my $file=shift;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
if (system("mtn", "--root=$config{mtnrootdir}", "add", "--quiet",
$file) != 0) {
sub rcs_remove ($) { # {{{
my $file = shift;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
# Note: it is difficult to undo a remove in Monotone at the moment.
# Until this is fixed, it might be better to make 'rm' move things
sub rcs_rename ($$) { # {{{
my ($src, $dest) = @_;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
if (system("mtn", "--root=$config{mtnrootdir}", "rename", "--quiet",
$src, $dest) != 0) {
my $num=shift;
my @ret;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
# use log --brief to get a list of revs, as this
# gives the results in a nice order
my $rev=shift;
my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
my $child = open(MTNDIFF, "-|");
if (! $child) {
sub rcs_getctime ($) { #{{{
my $file=shift;
- check_config();
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
my $child = open(MTNLOG, "-|");
if (! $child) {
--- /dev/null
+#!/usr/bin/perl
+# Stubs for no revision control.
+package IkiWiki::Plugin::norcs;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+sub import { #{{{
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub rcs_update () { #{{{
+} #}}}
+
+sub rcs_prepedit ($) { #{{{
+ return ""
+} #}}}
+
+sub rcs_commit ($$$;$$) { #{{{
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+ return undef # success
+} #}}}
+
+sub rcs_commit_staged ($$$) { #{{{
+ my ($message, $user, $ipaddr)=@_;
+ return undef # success
+} #}}}
+
+sub rcs_add ($) { #{{{
+} #}}}
+
+sub rcs_remove ($) { #{{{
+} #}}}
+
+sub rcs_rename ($$) { #{{{
+} #}}}
+
+sub rcs_recentchanges ($) { #{{{
+} #}}}
+
+sub rcs_diff ($) { #{{{
+} #}}}
+
+sub rcs_getctime ($) { #{{{
+ error gettext("getctime not implemented");
+} #}}}
+
+1
sub import { #{{{
hook(type => "getopt", id => "openid", call => \&getopt);
+ hook(type => "getsetup", id => "openid", call => \&getsetup);
hook(type => "auth", id => "openid", call => \&auth);
hook(type => "formbuilder_setup", id => "openid",
call => \&formbuilder_setup, last => 1);
GetOptions("openidsignup=s" => \$config{openidsignup});
} #}}}
+sub getsetup () { #{{{
+ return
+ openidsignup => {
+ type => "string",
+ example => "http://myopenid.com/",
+ description => "an url where users can signup for an OpenID",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
sub formbuilder_setup (@) { #{{{
my %params=@_;
use IkiWiki 2.00;
sub import { #{{{
- hook(type => "formbuilder_setup", id => "passwordauth",
- call => \&formbuilder_setup);
- hook(type => "formbuilder", id => "passwordauth",
- call => \&formbuilder);
+ hook(type => "getsetup", id => "passwordauth", "call" => \&getsetup);
+ hook(type => "formbuilder_setup", id => "passwordauth", call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "passwordauth", call => \&formbuilder);
hook(type => "sessioncgi", id => "passwordauth", call => \&sessioncgi);
} # }}}
+sub getsetup () { #{{{
+ return
+ account_creation_password => {
+ type => "string",
+ example => "s3cr1t",
+ description => "a password that must be entered when signing up for an account",
+ safe => 1,
+ rebuild => 0,
+ },
+ password_cost => {
+ type => "integer",
+ example => 8,
+ description => "cost of generating a password using Authen::Passphrase::BlowfishCrypt",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
# Checks if a string matches a user's password, and returns true or false.
sub checkpassword ($$;$) { #{{{
my $user=shift;
if ($form->submitted eq "Register" || $form->submitted eq "Create Account") {
$form->field(name => "confirm_password", type => "password");
- $form->field(name => "account_creation_password", type => "password") if (length $config{account_creation_password});
+ $form->field(name => "account_creation_password", type => "password")
+ if (defined $config{account_creation_password} &&
+ length $config{account_creation_password});
$form->field(name => "email", size => 50);
$form->title("register");
$form->text("");
shift eq $config{account_creation_password};
},
required => 1,
- ) if (length $config{account_creation_password});
+ ) if (defined $config{account_creation_password} &&
+ length $config{account_creation_password});
$form->field(
name => "email",
validate => "EMAIL",
error($@) if $@;
sendmail(
To => IkiWiki::userinfo_get($user_name, "email"),
- From => "$config{wikiname} admin <$config{adminemail}>",
+ From => "$config{wikiname} admin <".
+ (defined $config{adminemail} ? $config{adminemail} : "")
+ .">",
Subject => "$config{wikiname} information",
Message => $template->output,
) or error(gettext("Failed to send mail"));
my $pinged=0;
sub import { #{{{
+ hook(type => "getsetup", id => "pinger", call => \&getsetup);
hook(type => "needsbuild", id => "pinger", call => \&needsbuild);
hook(type => "preprocess", id => "ping", call => \&preprocess);
hook(type => "delete", id => "pinger", call => \&ping);
hook(type => "change", id => "pinger", call => \&ping);
} # }}}
+sub getsetup () { #{{{
+ return
+ pinger_timeout => {
+ type => "integer",
+ example => 15,
+ description => "how many seconds to try pinging before timing out",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
sub needsbuild (@) { #{{{
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
}
sub import { #{{{
+ hook(type => "getsetup", id => "prettydate", call => \&getsetup);
hook(type => "checkconfig", id => "prettydate", call => \&checkconfig);
} # }}}
+sub getsetup () { #{{{
+ return
+ prettydateformat => {
+ type => "string",
+ example => '%X, %B %o, %Y',
+ description => "format to use to display date",
+ safe => 1,
+ rebuild => 1,
+ },
+ timetable => {
+ type => "internal",
+ description => "array of time descriptions",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub checkconfig () { #{{{
if (! defined $config{prettydateformat} ||
$config{prettydateformat} eq '%c') {
use IkiWiki 2.00;
sub import { #{{{
+ hook(type => "getsetup", id => "recentchanges", call => \&getsetup);
hook(type => "checkconfig", id => "recentchanges", call => \&checkconfig);
hook(type => "refresh", id => "recentchanges", call => \&refresh);
hook(type => "pagetemplate", id => "recentchanges", call => \&pagetemplate);
hook(type => "cgi", id => "recentchanges", call => \&cgi);
} #}}}
+sub getsetup () { #{{{
+ return
+ recentchangespage => {
+ type => "string",
+ example => "recentchanges",
+ description => "name of the recentchanges page",
+ safe => 1,
+ rebuild => 1,
+ },
+ recentchangesnum => {
+ type => "integer",
+ example => 100,
+ description => "number of changes to track",
+ safe => 1,
+ rebuild => 0,
+ },
+} #}}}
+
sub checkconfig () { #{{{
$config{recentchangespage}='recentchanges' unless defined $config{recentchangespage};
$config{recentchangesnum}=100 unless defined $config{recentchangesnum};
use IkiWiki 2.00;
sub import { #{{{
+ hook(type => "getsetup", id => "search", call => \&getsetup);
hook(type => "checkconfig", id => "search", call => \&checkconfig);
hook(type => "pagetemplate", id => "search", call => \&pagetemplate);
hook(type => "postscan", id => "search", call => \&index);
hook(type => "cgi", id => "search", call => \&cgi);
} # }}}
+sub getsetup () { #{{{
+ return
+ omega_cgi => {
+ type => "string",
+ example => "/usr/lib/cgi-bin/omega/omega",
+ description => "path to the omega cgi program",
+ safe => 0, # external program
+ rebuild => 0,
+ },
+} #}}}
+
sub checkconfig () { #{{{
foreach my $required (qw(url cgiurl)) {
if (! length $config{$required}) {
}
}
- if (! exists $config{omega_cgi}) {
+ if (! defined $config{omega_cgi}) {
$config{omega_cgi}="/usr/lib/cgi-bin/omega/omega";
}
} #}}}
use IkiWiki 2.00;
sub import { #{{{
- hook(type => "checkconfig", id => "shortcut", call => \&checkconfig);
+ hook(type => "refresh", id => "shortcut", call => \&refresh);
hook(type => "preprocess", id => "shortcut", call => \&preprocess_shortcut);
} #}}}
-sub checkconfig () { #{{{
+sub refresh () { #{{{
# Preprocess the shortcuts page to get all the available shortcuts
# defined before other pages are rendered.
my $srcfile=srcfile("shortcuts.mdwn", 1);
sub import { #{{{
hook(type => "getopt", id => "skeleton", call => \&getopt);
+ hook(type => "getsetup", id => "skeleton", call => \&getsetup);
hook(type => "checkconfig", id => "skeleton", call => \&checkconfig);
hook(type => "refresh", id => "skeleton", call => \&refresh);
hook(type => "needsbuild", id => "skeleton", call => \&needsbuild);
debug("skeleton plugin getopt");
} #}}}
+sub getsetup () { #{{{
+ return
+ skeleton => {
+ type => "boolean",
+ example => 0,
+ description => "example option",
+ safe => 0,
+ rebuild => 0,
+ },
+} #}}}
+
sub checkconfig () { #{{{
debug("skeleton plugin checkconfig");
} #}}}
#!/usr/bin/perl
-
-package IkiWiki::Rcs::svn;
+package IkiWiki::Plugin::svn;
use warnings;
use strict;
use POSIX qw(setlocale LC_CTYPE);
sub import { #{{{
- if (exists $IkiWiki::config{svnpath}) {
+ hook(type => "checkconfig", id => "svn", call => \&checkconfig);
+ hook(type => "getsetup", id => "svn", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
+ if (! defined $config{svnpath}) {
+ $config{svnpath}="trunk";
+ }
+ if (exists $config{svnpath}) {
# code depends on the path not having extraneous slashes
- $IkiWiki::config{svnpath}=~tr#/#/#s;
- $IkiWiki::config{svnpath}=~s/\/$//;
- $IkiWiki::config{svnpath}=~s/^\///;
+ $config{svnpath}=~tr#/#/#s;
+ $config{svnpath}=~s/\/$//;
+ $config{svnpath}=~s/^\///;
+ }
+ if (defined $config{svn_wrapper} && length $config{svn_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{svn_wrapper},
+ wrappermode => (defined $config{svn_wrappermode} ? $config{svn_wrappermode} : "04755"),
+ };
}
} #}}}
-
-package IkiWiki;
+sub getsetup () { #{{{
+ return
+ svnrepo => {
+ type => "string",
+ example => "/svn/wiki",
+ description => "subversion repository location",
+ safe => 0, # path
+ rebuild => 0,
+ },
+ svnpath => {
+ type => "string",
+ example => "trunk",
+ description => "path inside repository where the wiki is located",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ svn_wrapper => {
+ type => "string",
+ example => "/svn/wikirepo/hooks/post-commit",
+ description => "svn post-commit executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ svn_wrappermode => {
+ type => "string",
+ example => '04755',
+ description => "mode for svn_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://svn.example.org/trunk/[[file]]",
+ description => "viewvc url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://svn.example.org/trunk/[[file]]?root=wiki&r1=[[r1]]&r2=[[r2]]",
+ description => "viewvc url to show a diff ([[file]], [[r1]], and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
# svn needs LC_CTYPE set to a UTF-8 locale, so try to find one. Any will do.
sub find_lc_ctype() {
if (system("svn", "commit", "--quiet",
"--encoding", "UTF-8", "-m",
- possibly_foolish_untaint($message),
+ IkiWiki::possibly_foolish_untaint($message),
$config{srcdir}) != 0) {
my $conflict=readfile("$config{srcdir}/$file");
if (system("svn", "revert", "--quiet", "$config{srcdir}/$file") != 0) {
if (system("svn", "commit", "--quiet",
"--encoding", "UTF-8", "-m",
- possibly_foolish_untaint($message),
+ IkiWiki::possibly_foolish_untaint($message),
$config{srcdir}) != 0) {
warn("svn commit failed\n");
return 1; # failure
my $file=shift;
if (-d "$config{srcdir}/.svn") {
- my $parent=dirname($file);
+ my $parent=IkiWiki::dirname($file);
while (! -d "$config{srcdir}/$parent/.svn") {
$file=$parent;
- $parent=dirname($file);
+ $parent=IkiWiki::dirname($file);
}
if (system("svn", "add", "--quiet", "$config{srcdir}/$file") != 0) {
$file=$1;
}
- my $diffurl=$config{diffurl};
+ my $diffurl=defined $config{diffurl} ? $config{diffurl} : "";
$diffurl=~s/\[\[file\]\]/$file/g;
$diffurl=~s/\[\[r1\]\]/$rev - 1/eg;
$diffurl=~s/\[\[r2\]\]/$rev/g;
} #}}}
sub rcs_diff ($) { #{{{
- my $rev=possibly_foolish_untaint(int(shift));
+ my $rev=IkiWiki::possibly_foolish_untaint(int(shift));
return `svnlook diff $config{svnrepo} -r$rev --no-diff-deleted`;
} #}}}
sub import { #{{{
hook(type => "getopt", id => "tag", call => \&getopt);
+ hook(type => "getsetup", id => "tag", call => \&getsetup);
hook(type => "preprocess", id => "tag", call => \&preprocess_tag, scan => 1);
hook(type => "preprocess", id => "taglink", call => \&preprocess_taglink, scan => 1);
hook(type => "pagetemplate", id => "tag", call => \&pagetemplate);
GetOptions("tagbase=s" => \$config{tagbase});
} #}}}
+sub getsetup () { #{{{
+ return
+ tagbase => {
+ type => "string",
+ example => "tag",
+ description => "parent page tags are located under",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub tagpage ($) { #{{{
my $tag=shift;
#!/usr/bin/perl
-
-package IkiWiki;
+package IkiWiki::Plugin::tla;
use warnings;
use strict;
use IkiWiki;
-sub quiet_system (@) {
+sub import { #{{{
+ hook(type => "checkconfig", id => "tla", call => \&checkconfig);
+ hook(type => "getsetup", id => "tla", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+} #}}}
+
+sub checkconfig () { #{{{
+ if (defined $config{tla_wrapper} && length $config{tla_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{tla_wrapper},
+ wrappermode => (defined $config{tla_wrappermode} ? $config{tla_wrappermode} : "06755"),
+ };
+ }
+} #}}}
+
+sub getsetup () { #{{{
+ return
+ tla_wrapper => {
+ type => "string",
+ #example => "", # TODO example
+ description => "tla post-commit executable to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ tla_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for tla_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ #example => "", # TODO example
+ description => "url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ #example => "", # TODO example
+ description => "url to show a diff ([[file]] and [[rev]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
+sub quiet_system (@) { #{{{
# See Debian bug #385939.
open (SAVEOUT, ">&STDOUT");
close STDOUT;
open (STDOUT, ">&SAVEOUT");
close SAVEOUT;
return $ret;
-}
+} #}}}
sub rcs_update () { #{{{
if (-d "$config{srcdir}/{arch}") {
}
if (quiet_system("tla", "commit",
- "-L".possibly_foolish_untaint($message),
+ "-L".IkiWiki::possibly_foolish_untaint($message),
'-d', $config{srcdir}) != 0) {
my $conflict=readfile("$config{srcdir}/$file");
if (system("tla", "undo", "-n", "--quiet", "-d", "$config{srcdir}") != 0) {
my @pages;
foreach my $file (@paths) {
- my $diffurl=$config{diffurl};
+ my $diffurl=defined $config{diffurl} ? $config{diffurl} : "";
$diffurl=~s/\[\[file\]\]/$file/g;
$diffurl=~s/\[\[rev\]\]/$change/g;
push @pages, {
sub import { #{{{
hook(type => "getopt", id => "typography", call => \&getopt);
+ hook(type => "getsetup", id => "typography", call => \&getsetup);
IkiWiki::hook(type => "sanitize", id => "typography", call => \&sanitize);
} # }}}
GetOptions("typographyattributes=s" => \$config{typographyattributes});
} #}}}
+sub getsetup () { #{{{
+ eval q{use Text::Typography};
+ error($@) if $@;
+
+ return
+ typographyattributes => {
+ type => "string",
+ example => "3",
+ description => "Text::Typography attributes value",
+ safe => 1,
+ rebuild => 1,
+ },
+} #}}}
+
sub sanitize (@) { #{{{
my %params=@_;
eval q{use Text::Typography};
- error($@) if $@;
+ return $params{content} if $@;
my $attributes=defined $config{typographyattributes} ? $config{typographyattributes} : '3';
return Text::Typography::typography($params{content}, $attributes);
+++ /dev/null
-#!/usr/bin/perl
-# Stubs for no revision control.
-
-package IkiWiki;
-
-use warnings;
-use strict;
-use IkiWiki;
-
-sub rcs_update () {
- # Update working directory to current version.
- # (May be more complex for distributed RCS.)
-}
-
-sub rcs_prepedit ($) {
- # Prepares to edit a file under revision control. Returns a token
- # that must be passed into rcs_commit when the file is ready
- # for committing.
- # The file is relative to the srcdir.
- return ""
-}
-
-sub rcs_commit ($$$;$$) {
- # Tries to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on failure.
- # The file is relative to the srcdir.
- my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
- return undef # success
-}
-
-sub rcs_commit_staged ($$$) {
- # Commits all staged changes. Changes can be staged using rcs_add,
- # rcs_remove, and rcs_rename.
- my ($message, $user, $ipaddr)=@_;
- return undef # success
-}
-
-sub rcs_add ($) {
- # Add a file. The filename is relative to the root of the srcdir.
- # Note that this should not check the new file in, it should only
- # prepare for it to be checked in when rcs_commit is called.
- # Note that the file may be in a new subdir that is not yet added
- # to version control; the subdir can be added if so.
-}
-
-sub rcs_remove ($) {
- # Remove a file. The filename is relative to the root of the srcdir.
- # Note that this should not check the removal in, it should only
- # prepare for it to be checked in when rcs_commit is called.
- # Note that the new file may be in a new subdir that is not yet added
- # to version control; the subdir can be added if so.
-}
-
-sub rcs_rename ($$) {
- # Rename a file. The filenames are relative to the root of the srcdir.
- # Note that this should not commit the rename, it should only
- # prepare it for when rcs_commit is called.
- # The new filename may be in a new subdir, that is not yet added to
- # version control. If so, the subdir will exist already, and should
- # be added to revision control.
-}
-
-sub rcs_recentchanges ($) {
- # Examine the RCS history and generate a list of recent changes.
- # The data structure returned for each change is:
- # {
- # rev => # the RCSs id for this commit
- # user => # name of user who made the change,
- # committype => # either "web" or the name of the rcs,
- # when => # time when the change was made,
- # message => [
- # { line => "commit message line" },
- # { line => "commit message line" },
- # # etc,
- # ],
- # pages => [
- # {
- # page => # name of page changed,
- # diffurl => # optional url to a diff showing
- # # the changes,
- # },
- # # repeat for each page changed in this commit,
- # ],
- # }
-}
-
-sub rcs_diff ($) {
- # Optional, used to get diffs for recentchanges.
- # The parameter is the rev from rcs_recentchanges.
- # Should return a list of lines of the diff (including \n) in list
- # context, and the whole diff in scalar context.
-}
-
-sub rcs_getctime ($) {
- # Optional, used to get the page creation time from the RCS.
- error gettext("getctime not implemented");
-}
-
-1
$actions++;
}
- if (length $config{historyurl}) {
+ if (defined $config{historyurl} && length $config{historyurl}) {
my $u=$config{historyurl};
$u=~s/\[\[file\]\]/$pagesources{$page}/g;
$template->param(historyurl => $u);
#!/usr/bin/perl
# Ikiwiki setup files are perl files that 'use IkiWiki::Setup::foo',
# passing it some sort of configuration data.
-#
-# There can be multiple modules, with different configuration styles.
-# The setup modules each convert the data into the hashes used by ikiwiki
-# internally (if it's not already in that format), and store it in
-# IkiWiki::Setup::$raw_setup, to pass it back to this module.
package IkiWiki::Setup;
use warnings;
use strict;
use IkiWiki;
-use IkiWiki::Wrapper;
use open qw{:utf8 :std};
-our $raw_setup;
-
sub load ($) { # {{{
my $setup=IkiWiki::possibly_foolish_untaint(shift);
delete $config{setup};
eval $code;
error("$setup: ".$@) if $@;
-
- my $ret=$raw_setup;
- $raw_setup=undef;
-
- return %$ret;
} #}}}
-package IkiWiki;
+sub merge ($) {
+ my %setup=%{shift()};
-sub setup () { #{{{
- my %setup=IkiWiki::Setup::load($config{setup});
-
- $setup{plugin}=$config{plugin};
+ # Merge setup into existing config and untaint.
if (exists $setup{add_plugins}) {
- push @{$setup{plugin}}, @{$setup{add_plugins}};
- delete $setup{add_plugins};
+ push @{$setup{add_plugins}}, @{$config{add_plugins}};
}
if (exists $setup{exclude}) {
push @{$config{wiki_file_prune_regexps}}, $setup{exclude};
}
-
- if (! $config{render} && (! $config{refresh} || $config{wrappers})) {
- debug(gettext("generating wrappers.."));
- my @wrappers=@{$setup{wrappers}};
- delete $setup{wrappers};
- my %startconfig=(%config);
- foreach my $wrapper (@wrappers) {
- %config=(%startconfig, rebuild => 0, verbose => 0, %setup, %{$wrapper});
- checkconfig();
- if (! $config{cgi} && ! $config{post_commit}) {
- $config{post_commit}=1;
- }
- gen_wrapper();
- }
- %config=(%startconfig);
- }
-
foreach my $c (keys %setup) {
- next if $c eq 'syslog';
if (defined $setup{$c}) {
- if (! ref $setup{$c}) {
- $config{$c}=possibly_foolish_untaint($setup{$c});
+ if (! ref $setup{$c} || ref $setup{$c} eq 'Regexp') {
+ $config{$c}=IkiWiki::possibly_foolish_untaint($setup{$c});
}
elsif (ref $setup{$c} eq 'ARRAY') {
- $config{$c}=[map { possibly_foolish_untaint($_) } @{$setup{$c}}]
+ if ($c eq 'wrappers') {
+ # backwards compatability code
+ $config{$c}=$setup{$c};
+ }
+ else {
+ $config{$c}=[map { IkiWiki::possibly_foolish_untaint($_) } @{$setup{$c}}]
+ }
}
elsif (ref $setup{$c} eq 'HASH') {
foreach my $key (keys %{$setup{$c}}) {
- $config{$c}{$key}=possibly_foolish_untaint($setup{$c}{$key});
+ $config{$c}{$key}=IkiWiki::possibly_foolish_untaint($setup{$c}{$key});
}
}
}
}
}
- if (! $config{refresh}) {
- $config{rebuild}=1;
- }
-
- loadplugins();
- checkconfig();
-
- require IkiWiki::Render;
-
- if ($config{render}) {
- commandline_render();
- }
-
- if (! $config{refresh}) {
- debug(gettext("rebuilding wiki.."));
- }
- else {
- debug(gettext("refreshing wiki.."));
+ if (length $config{cgi_wrapper}) {
+ push @{$config{wrappers}}, {
+ cgi => 1,
+ wrapper => $config{cgi_wrapper},
+ wrappermode => (defined $config{cgi_wrappermode} ? $config{cgi_wrappermode} : "06755"),
+ };
}
+} #}}}
- lockwiki();
- loadindex();
- refresh();
+sub dump ($) { #{{{
+ my $file=IkiWiki::possibly_foolish_untaint(shift);
+
+ require IkiWiki::Setup::Standard;
+ my @dump=IkiWiki::Setup::Standard::gendump("Setup file for ikiwiki.");
- debug(gettext("done"));
- saveindex();
-} #}}}
+ open (OUT, ">", $file) || die "$file: $!";
+ print OUT "$_\n" foreach @dump;
+ close OUT;
+}
1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki setup automator.
+
+package IkiWiki::Setup::Automator;
+
+use warnings;
+use strict;
+use IkiWiki;
+use IkiWiki::UserInfo;
+use Term::ReadLine;
+use File::Path;
+
+sub ask ($$) { #{{{
+ my ($question, $default)=@_;
+
+ my $r=Term::ReadLine->new("ikiwiki");
+ $r->readline($question." ", $default);
+} #}}}
+
+sub prettydir ($) { #{{{
+ my $dir=shift;
+ $dir=~s/^\Q$ENV{HOME}\E\//~\//;
+ return $dir;
+} #}}}
+
+sub import (@) { #{{{
+ my $this=shift;
+ IkiWiki::Setup::merge({@_});
+
+ # Sanitize this to avoid problimatic directory names.
+ $config{wikiname}=~s/[^-A-Za-z0-9_] //g;
+ if (! length $config{wikiname}) {
+ die "you must enter a wikiname\n";
+ }
+
+ # Avoid overwriting any existing files.
+ foreach my $key (qw{srcdir destdir repository dumpsetup}) {
+ next unless exists $config{$key};
+ my $add="";
+ while (-e $add.$config{$key}) {
+ $add=1 if ! $add;
+ $add++;
+ }
+ $config{$key}=$add.$config{$key};
+ }
+
+ IkiWiki::checkconfig();
+
+ print "\n\nSetting up $config{wikiname} ...\n";
+
+ # Set up the repository.
+ mkpath($config{srcdir}) || die "mkdir $config{srcdir}: $!";
+ delete $config{repository} if ! $config{rcs} || $config{rcs}=~/bzr|mercurial/;
+ if ($config{rcs}) {
+ my @params=($config{rcs}, $config{srcdir});
+ push @params, $config{repository} if exists $config{repository};
+ if (system("ikiwiki-makerepo", @params) != 0) {
+ die "failed: ikiwiki-makerepo @params";
+ }
+ }
+
+ # Generate setup file.
+ require IkiWiki::Setup;
+ if ($config{rcs}) {
+ if ($config{rcs} eq 'git') {
+ $config{git_wrapper}=$config{repository}."/hooks/post-update";
+ }
+ elsif ($config{rcs} eq 'svn') {
+ $config{svn_wrapper}=$config{repository}."/hooks/post-commit";
+ }
+ elsif ($config{rcs} eq 'bzr') {
+ # TODO
+ }
+ elsif ($config{rcs} eq 'mercurial') {
+ # TODO
+ }
+ }
+ IkiWiki::Setup::dump($config{dumpsetup});
+
+ # Build the wiki, but w/o wrappers, so it's not live yet.
+ mkpath($config{destdir}) || die "mkdir $config{destdir}: $!";
+ if (system("ikiwiki", "--refresh", "--setup", $config{dumpsetup}) != 0) {
+ die "ikiwiki --refresh --setup $config{dumpsetup} failed";
+ }
+
+ # Create admin user(s).
+ foreach my $admin (@{$config{adminuser}}) {
+ next if $admin=~/^http\?:\/\//; # openid
+
+ # Prompt for password w/o echo.
+ system('stty -echo 2>/dev/null');
+ local $|=1;
+ print "\n\nCreating wiki admin $admin ...\n";
+ print "Choose a password: ";
+ chomp(my $password=<STDIN>);
+ print "\n\n\n";
+ system('stty sane 2>/dev/null');
+
+ if (IkiWiki::userinfo_setall($admin, { regdate => time }) &&
+ IkiWiki::Plugin::passwordauth::setpassword($admin, $password)) {
+ IkiWiki::userinfo_set($admin, "email", $config{adminemail}) if defined $config{adminemail};
+ }
+ else {
+ error("problem setting up $admin user");
+ }
+ }
+
+ # Add wrappers, make live.
+ if (system("ikiwiki", "--wrappers", "--setup", $config{dumpsetup}) != 0) {
+ die "ikiwiki --wrappers --setup $config{dumpsetup} failed";
+ }
+
+ # Add it to the wikilist.
+ mkpath("$ENV{HOME}/.ikiwiki");
+ open (WIKILIST, ">>$ENV{HOME}/.ikiwiki/wikilist") || die "$ENV{HOME}/.ikiwiki/wikilist: $!";
+ print WIKILIST "$ENV{USER} $config{dumpsetup}\n";
+ close WIKILIST;
+ if (system("ikiwiki-update-wikilist") != 0) {
+ print STDERR "** Failed to add you to the system wikilist file.\n";
+ print STDERR "** (Probably ikiwiki-update-wikilist is not SUID root.)\n";
+ print STDERR "** Your wiki will not be automatically updated when ikiwiki is upgraded.\n";
+ }
+
+ # Done!
+ print "\n\nSuccessfully set up $config{wikiname}:\n";
+ foreach my $key (qw{url srcdir destdir repository}) {
+ next unless exists $config{$key};
+ print "\t$key: ".(" " x (10 - length($key)))." ".
+ prettydir($config{$key})."\n";
+ }
+ print "To modify settings, edit ".prettydir($config{dumpsetup})." and then run:\n";
+ print " ikiwiki -setup ".prettydir($config{dumpsetup})."\n";
+ exit 0;
+} #}}}
+
+1
use warnings;
use strict;
+use IkiWiki;
-sub import {
- $IkiWiki::Setup::raw_setup=$_[1];
-}
+sub import { #{{{
+ IkiWiki::Setup::merge($_[1]);
+} #}}}
+
+sub dumpline ($$$$) { #{{{
+ my $key=shift;
+ my $value=shift;
+ my $type=shift;
+ my $prefix=shift;
+
+ eval q{use Data::Dumper};
+ error($@) if $@;
+ local $Data::Dumper::Terse=1;
+ local $Data::Dumper::Indent=1;
+ local $Data::Dumper::Pad="\t";
+ local $Data::Dumper::Sortkeys=1;
+ local $Data::Dumper::Quotekeys=0;
+
+ my $dumpedvalue;
+ if ($type eq 'boolean' || $type eq 'integer') {
+ # avoid quotes
+ $dumpedvalue=$value;
+ }
+ elsif ($type eq 'string' && ref $value eq 'ARRAY' && @$value &&
+ ! grep { /[^-A-Za-z0-9_]/ } @$value) {
+ # dump simple array as qw{}
+ $dumpedvalue="[qw{ ".join(" ", @$value)." }]";
+ }
+ else {
+ $dumpedvalue=Dumper($value);
+ chomp $dumpedvalue;
+ if (length $prefix) {
+ # add to second and subsequent lines
+ my @lines=split(/\n/, $dumpedvalue);
+ $dumpedvalue="";
+ for (my $x=0; $x <= $#lines; $x++) {
+ $lines[$x] =~ s/^\t//;
+ $dumpedvalue.="\t".($x ? $prefix : "").$lines[$x]."\n";
+ }
+ }
+ $dumpedvalue=~s/^\t//;
+ chomp $dumpedvalue;
+ }
+
+ return "\t$prefix$key => $dumpedvalue,";
+} #}}}
+
+sub dumpvalues ($@) { #{{{
+ my $setup=shift;
+ my @ret;
+ while (@_) {
+ my $key=shift;
+ my %info=%{shift()};
+
+ next if $info{type} eq "internal";
+
+ push @ret, "\t# ".$info{description} if exists $info{description};
+
+ if (exists $setup->{$key} && defined $setup->{$key}) {
+ push @ret, dumpline($key, $setup->{$key}, $info{type}, "");
+ delete $setup->{$key};
+ }
+ elsif (exists $info{example}) {
+ push @ret, dumpline($key, $info{example}, $info{type}, "#");
+ }
+ else {
+ push @ret, dumpline($key, "", $info{type}, "#");
+ }
+ }
+ return @ret;
+} #}}}
+
+sub gendump ($) { #{{{
+ my $description=shift;
+ my %setup=(%config);
+ my @ret;
+
+ # disable logging to syslog while dumping
+ $config{syslog}=0;
+
+ push @ret, "\t# basic setup";
+ push @ret, dumpvalues(\%setup, IkiWiki::getsetup());
+
+ # Load all plugins, so that all setup options are available.
+ # (But skip a few problematic external demo plugins.)
+ my @plugins=grep { ! /^(externaldemo|pythondemo|\Q$config{rcs}\E)$/ }
+ sort(IkiWiki::listplugins());
+ unshift @plugins, $config{rcs} if $config{rcs}; # rcs plugin 1st
+ foreach my $plugin (@plugins) {
+ eval { IkiWiki::loadplugin($plugin) };
+ if (exists $IkiWiki::hooks{checkconfig}{$plugin}{call}) {
+ my @s=eval { $IkiWiki::hooks{checkconfig}{$plugin}{call}->() };
+ }
+ }
+
+ foreach my $id (@plugins) {
+ if (exists $IkiWiki::hooks{getsetup}{$id}{call}) {
+ # use an array rather than a hash, to preserve order
+ my @s=eval { $IkiWiki::hooks{getsetup}{$id}{call}->() };
+ next unless @s;
+ push @ret, "", "\t# $id plugin";
+ push @ret, dumpvalues(\%setup, @s);
+ }
+ }
+
+ unshift @ret,
+ "#!/usr/bin/perl",
+ "# $description",
+ "#",
+ "# Passing this to ikiwiki --setup will make ikiwiki generate",
+ "# wrappers and build the wiki.",
+ "#",
+ "# Remember to re-run ikiwiki --setup any time you edit this file.",
+ "use IkiWiki::Setup::Standard {";
+ push @ret, "}";
+
+ return @ret;
+} #}}}
1
./pm_filter $(PREFIX) $(VER) $(PROBABLE_INST_LIB) < ikiwiki.in > ikiwiki.out
chmod +x ikiwiki.out
-extra_build: ikiwiki.out
+ikiwiki.setup: ikiwiki.out
+ HOME=/home/me $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -dumpsetup ikiwiki.setup
+
+extra_build: ikiwiki.out ikiwiki.setup
$(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -setup docwiki.setup -refresh
./mdwn2man ikiwiki 1 doc/usage.mdwn > ikiwiki.man
./mdwn2man ikiwiki-mass-rebuild 8 doc/ikiwiki-mass-rebuild.mdwn > ikiwiki-mass-rebuild.man
extra_clean:
rm -rf html doc/.ikiwiki
- rm -f *.man ikiwiki.out
- rm -f plugins/*.pyc
+ rm -f *.man ikiwiki.out ikiwiki.setup plugins/*.pyc
$(MAKE) -C po clean
extra_install:
+ install -d $(DESTDIR)/etc/ikiwiki
+ install -m 0644 wikilist $(DESTDIR)/etc/ikiwiki
+ install -m 0644 auto.setup $(DESTDIR)/etc/ikiwiki
+
install -d $(DESTDIR)$(PREFIX)/share/ikiwiki
for dir in `cd underlays && find . -follow -type d ! -regex '.*\.svn.*'`; do \
install -d $(DESTDIR)$(PREFIX)/share/ikiwiki/$$dir; \
install -d $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins
for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\*`; do \
- install -m 755 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ cp -a $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
done; \
install -d $(DESTDIR)$(PREFIX)/share/man/man1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki setup automator.
+#
+# This setup file causes ikiwiki to create a wiki, check it into revision
+# control, generate a setup file for the new wiki, and set everything up.
+#
+# Just run: ikiwiki -setup /etc/ikiwiki/auto.setup
+#
+# By default, it asks a few questions, and confines itself to the user's home
+# directory. You can edit it to change what it asks questions about, or to
+# modify the values to use site-specific settings.
+
+require IkiWiki::Setup::Automator;
+
+our $wikiname=IkiWiki::Setup::Automator::ask(
+ "What will the wiki be named?", "wiki");
+our $rcs=IkiWiki::Setup::Automator::ask(
+ "What revision control system to use?", "git");
+our $admin=IkiWiki::Setup::Automator::ask(
+ "What wiki user (or openid) will be wiki admin?", $ENV{USER});
+our $hostname=`hostname -f`; chomp $hostname;
+
+IkiWiki::Setup::Automator->import(
+ wikiname => $wikiname,
+ adminuser => [$admin],
+ rcs => $rcs,
+ srcdir => "$ENV{HOME}/$wikiname",
+ destdir => "$ENV{HOME}/public_html/$wikiname",
+ repository => "$ENV{HOME}/$wikiname.$rcs",
+ dumpsetup => "$ENV{HOME}/$wikiname.setup",
+ url => "http://$hostname/~$ENV{USER}/$wikiname",
+ cgiurl => "http://$hostname/~$ENV{USER}/$wikiname/ikiwiki.cgi",
+ cgi_wrapper => "$ENV{HOME}/public_html/$wikiname/ikiwiki.cgi",
+ adminemail => "$ENV{USER}\@$hostname",
+ add_plugins => [qw{ goodstuff }],
+ disable_plugins => [qw{ }],
+ libdir => "$ENV{HOME}/.ikiwiki",
+ rss => 1,
+ atom => 1,
+ syslog => 1,
+ prefix_directives => 1,
+ hardlink => 1,
+)
+ikiwiki (2.60) UNRELEASED; urgency=low
+
+ * Starting with this version, "ikiwiki -setup /etc/ikiwiki/auto.setup"
+ can be used set up a new wiki in seconds.
+ * Add getsetup hook, all plugins that add fields to %config should use it.
+ * ikiwiki --dumpsetup can generate a nice setup file snapshotting ikiwiki's
+ current configuration.
+ * Large amounts of internal config data reorg.
+ * The way wrappers are defined in the setup file has changed. Old setup
+ files will continue to work, for now.
+ * Version control backends promoted to first-class plugins.
+ * ikiwiki-update-wikilist: Add -r switch to remove. Default behavior is now
+ always to add.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 21 Jul 2008 11:35:46 -0400
+
ikiwiki (2.56) UNRELEASED; urgency=low
* autoindex: New plugin that generates missing index pages.
-doc/ikiwiki.setup
+ikiwiki.setup
dh_testroot
dh_clean -k
$(MAKE) pure_install DESTDIR=$(shell pwd)/debian/ikiwiki
- dh_install wikilist etc/ikiwiki
dh_installdocs html
dh_installexamples doc/examples/*
dh_link usr/share/common-licenses/GPL-2 usr/share/doc/ikiwiki/html/GPL
In setting up my wiki I followed the [[setup]] instruction which point
-to an [[ikiwiki.setup]] file that contains "verbose => 0".
+to an ikiwiki.setup file that contains "verbose => 0".
I hadn't noticed that setting in there, but later when I changed my
standard command of:
# SYNOPSIS
-ikiwiki-update-wikilist
+ikiwiki-update-wikilist [-r]
# DESCRIPTION
-`ikiwiki-update-wikilist` is designed to be made suid root, but not installed
+`ikiwiki-update-wikilist` is designed to be made suid root, but is not installed
suid by default. If made suid, it allows users to add or remove their names
-from the `/etc/ikiwiki/wikilist` file. If a user's name is not in the file,
-it will be added; if the name is already present, it will be removed.
+from the `/etc/ikiwiki/wikilist` file.
+
+By default, the user's name will be added.
+The `-r` switch causes the user's name to be removed.
If your name is in `/etc/ikiwiki/wikilist`, the [[ikiwiki-mass-rebuild]](8)
command will look for a ~/.ikiwiki/wikilist file, and rebuild the wikis listed
+++ /dev/null
-#!/usr/bin/perl
-# Configuration file for ikiwiki.
-# Passing this to ikiwiki --setup will make ikiwiki generate wrappers and
-# build the wiki.
-#
-# Remember to re-run ikiwiki --setup any time you edit this file.
-
-use IkiWiki::Setup::Standard {
- wikiname => "MyWiki",
- #adminuser => ["yourname", ],
- adminemail => 'me@example.org',
-
- # Be sure to customise these..
- srcdir => "/path/to/source",
- destdir => "/var/www/wiki",
-
- url => "http://example.org/wiki",
- cgiurl => "http://example.org/wiki/ikiwiki.cgi",
- #templatedir => "/usr/share/ikiwiki/templates",
- #underlaydir => "/usr/share/ikiwiki/basewiki",
-
- # Subversion stuff.
- #rcs => "svn",
- #historyurl => "http://svn.example.org/trunk/[[file]]",
- #diffurl => "http://svn.example.org/trunk/[[file]]?root=wiki&r1=[[r1]]&r2=[[r2]]",
- #svnrepo => "/svn/wiki",
- #svnpath => "trunk",
-
- # Git stuff.
- #rcs => "git",
- #historyurl => "http://git.example.org/gitweb.cgi?p=wiki.git;a=history;f=[[file]]",
- #diffurl => "http://git.example.org/gitweb.cgi?p=wiki.git;a=blobdiff;h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_parent]];f=[[file]]",
- #gitorigin_branch => "origin",
- #gitmaster_branch => "master",
-
- # Tla stuff.
- #rcs => "tla"
- #historyurl => ??,
- #diffurl => ??,
-
- # Mercurial stuff.
- #rcs => "mercurial",
- #historyurl => "http://localhost:8000/log/tip/[[file]]", # hg serve'd local repository
- #diffurl => "http://localhost:8000/?fd=[[r2]];file=[[file]]",
-
- # Bazaar stuff.
- #rcs => "bzr",
- #historyurl => "",
- #diffurl => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s", # using loggerhead
-
- # Monotone stuff
- #rcs => "monotone",
- #mtnkey => "web\@machine.company.com",
- #historyurl => "http://viewmtn.example.com/branch/head/filechanges/com.example.branch/[[file]]",
- #diffurl => "http://viewmtn.example.com/revision/diff/[[r1]]/with/[[r2]]/[[file]]",
- # Set if you want the wiki to sync on update and commit.
- #mtnsync => 0,
- # The path to your workspace (defaults to the srcdir itself)
- # e.g. use if your srcdir is a subdirectory of the workspace.
- #mtnrootdir => "path/to/root/of/workspace",
-
- wrappers => [
- #{
- # # The cgi wrapper.
- # cgi => 1,
- # wrapper => "/var/www/wiki/ikiwiki.cgi",
- # wrappermode => "06755",
- #},
- #{
- # # The svn post-commit wrapper.
- # # Note that this will overwrite any existing
- # # post-commit hook script, which may not be
- # # what you want.
- # wrapper => "/svn/wikirepo/hooks/post-commit",
- # wrappermode => "04755",
- # # Log to syslog since svn post-commit hooks
- # # hide output and errors.
- # syslog => 1,
- #},
- #{
- # # The git post-update wrapper.
- # # Note that this will overwrite any existing
- # # post-update hook script, which may not be
- # # what you want.
- # wrapper => "/git/wiki.git/hooks/post-update",
- # wrappermode => "06755",
- #},
- #{
- # # The monotone netsync hook.
- # wrapper => "path/to/root/of/workspace/_MTN/ikiwiki-netsync-hook",
- # wrappermode => "06755",
- #},
- ],
-
- # Default to generating rss feeds for pages with feeds?
- #rss => 1,
- # Default to generating atom feeds for pages with feeds?
- #atom => 1,
- # Allow generating feeds even if not generated by default?
- #allowrss => 1,
- #allowatom => 1,
- # Urls to ping with XML-RPC when feeds are updated
- #pingurl => [qw{http://rpc.technorati.com/rpc/ping}],
- # Include discussion links on all pages?
- discussion => 1,
- # To exclude files matching a regexp from processing. This adds to
- # the default exclude list.
- #exclude => qr/\.wav$/,
- # To change the extension used for generated html files.
- #htmlext => 'htm',
- # Time format (for strftime)
- #timeformat => '%c',
- # Locale to use. Must be a UTF-8 locale.
- #locale => 'en_US.UTF-8',
- # Only send cookies over SSL connections.
- #sslcookie => 1,
- # Logging settings:
- #verbose => 1,
- syslog => 0,
- # To link to user pages in a subdirectory of the wiki.
- #userdir => "users",
- # To create output files named page.html rather than page/index.html.
- #usedirs => 0,
- # Simple spam prevention: require an account-creation password.
- #account_creation_password => "example",
- # Cost of generating a password using Authen::Passphrase::BlowfishCrypt
- #password_cost => 8,
- # Uncomment to force ikiwiki to run with a particular umask.
- #umask => 022,
- # Default settings for the recentchanges page.
- #recentchangespage => "recentchanges",
- #recentchangesnum => 100,
- # Use new '!'-prefixed preprocessor directive syntax
- #prefix_directives => 1,
- # Attempt to make hardlinks to source files instead of copying them.
- # Useful if the wiki contains large media files.
- #hardlink => 1,
- # Enable use of multimarkdown features in .mdwn files.
- #multimarkdown => 1,
-
- # To add plugins, list them here.
- #add_plugins => [qw{goodstuff search wikitext camelcase
- # htmltidy fortune sidebar map rst anonok}],
- # If you want to disable any of the default plugins, list them here.
- #disable_plugins => [qw{inline htmlscrubber passwordauth openid}],
- # To add a directory to the perl search path, use this.
- #libdir => "/home/me/.ikiwiki/",
-
- # To override environment variable settings, you can list values here.
- #ENV => {
- # TZ => "America/New_York",
- # PATH => "/home/me/bin:/usr/local/bin:/usr/bin:/bin",
- #},
-
- # For use with the tag plugin, make all tags be located under a
- # base page.
- #tagbase => "tag",
-
- # For use with the search plugin if the omega cgi is located
- # somewhere else.
- #omega_cgi => "/usr/lib/cgi-bin/omega/omega",
-
- # For use with the openid plugin, to give an url to a page users
- # can use to signup for an OpenID.
- #openidsignup => "http://myopenid.com/",
-
- # For use with the mirrorlist plugin, a list of mirrors.
- #mirrorlist => {
- # mirror1 => "http://hostname1",
- # mirror2 => "http://hostname2/mirror",
- #},
-
- # For use with the anonok plugin, a PageSpec specifying what
- # pages anonymous users can edit
- #anonok_pagespec => "*",
-
- # For use with the aggregate plugin.
- # Enable aggregation to internal pages. New wikis should set this to 1,
- # but if you use aggregate already, read the aggregate plugin docs
- # before enabling it.
- #aggregateinternal => 1,
- # Allow aggregation to be triggered via the web.
- #aggregate_webtrigger => 1,
-
- # For use with the pinger plugin, how many seconds to wait before
- # timing out.
- #pinger_timeout => 15.
-
- # For use with the amazon S3 plugin, your public access key id.
- #amazon_s3_key_id => 'XXXXXXXXXXXXXXXXXXXX',
- # And a file holding your secret key. This file *must* not be
- # readable by others!
- #amazon_s3_key_file => "/home/me/.hide/.s3_key
- # The globally unique name of the bucket to use to store the wiki.
- #amazon_s3_bucket => "mywiki",
- # A prefix to prepend to each page name.
- #amazon_s3_prefix => "wiki/",
- # Uncomment to use the S3 European datacenter.
- #amazon_s3_location => "EU",
- # Uncomment if you need to store each index file twice.
- #amazon_s3_dupindex => 1,
-
- # For use with the attachment plugin, a program that returns
- # nonzero if its standard input contains an virus.
- #virus_checker => "clamdscan -",
-}
[[install]] plugins [[contributed|contrib]] by others.
To enable a plugin, use the `--plugin` switch described in
-[[usage]], or the equivalent `add_plugins` line in [[ikiwiki.setup]].
+[[usage]], or the equivalent `add_plugins` line in ikiwiki.setup.
Enable the [[goodstuff]] plugin to get a nice selection of plugins that
will fit most uses of ikiwiki.
This plugin allows adding links a list of mirrors to each page in the
wiki. For each mirror, a name and an url should be specified. Pages are
assumed to exist in the same location under the specified url on each
-mirror. The [[ikiwiki.setup]] file has an example of configuring a list of
-mirrors.
+mirror.
`newpage`, and `content`, and should try to modify the content to reflect
the name change. For example, by converting links to point to the new page.
+### getsetup
+
+ hook(type => "getsetup", id => "foo", call => \&getsetup);
+
+This hooks is not called during normal operation, but only when setting up
+the wiki, or generating a setup file. Plugins can use this hook to add
+configuration options.
+
+The hook is passed no parameters. It returns data about the configuration
+options added by the plugin. It can also check if the plugin is usable, and
+die if not, which will cause the plugin to not be offered in the configuration
+interface.
+
+The data returned is a list of `%config` options, followed by a hash
+describing the option. For example:
+
+ return
+ option_foo => {
+ type => "boolean",
+ description => "enable foo",
+ safe => 1,
+ rebuild => 1,
+ },
+ option_bar => {
+ type => "string",
+ example => "hello",
+ description => "what to say",
+ safe => 1,
+ rebuild => 0,
+ },
+
+* `type` can be "boolean", "string", "integer", "pagespec", or "internal"
+ (used for values that are not user-visible). The type is the type of
+ the leaf values; the `%config` option may be an array or hash of these.
+* `example` can be set to an example value.
+* `description` is a short description of the option.
+* `safe` should be false if the option should not be displayed in unsafe
+ configuration methods, such as the web interface. Anything that specifies
+ a command to run, a path on disk, or a regexp should be marked as unsafe.
+* `rebuild` should be true if changing the option will require a wiki rebuild.
+
## Plugin interface
To import the ikiwiki plugin interface:
A plugin can access the wiki's configuration via the `%config`
hash. The best way to understand the contents of the hash is to look at
-[[ikiwiki.setup]], which sets the hash content to configure the wiki.
+your ikiwiki setup file, which sets the hash content to configure the wiki.
### %pagestate
### RCS plugins
-ikiwiki's support for [[revision_control_systems|rcs]] also uses pluggable
-perl modules. These are in the `IkiWiki::RCS` namespace, for example
-`IkiWiki::RCS::svn`.
+ikiwiki's support for [[revision_control_systems|rcs]] is also done via
+plugins. See [[RCS_details|rcs/details]] for some more info.
+
+RCS plugins must register a number of hooks. Each hook has type 'rcs',
+and the 'id' field is set to the name of the hook. For example:
+
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+
+#### `rcs_update()`
+
+Updates the working directory with any remote changes.
+
+#### `rcs_prepedit($)`
+
+Is passed a file to prepare to edit. It can generate and return an arbitrary
+token, that will be passed into `rcs_commit` when committing. For example,
+it might return the current revision ID of the file, and use that
+information later when merging changes.
+
+#### `rcs_commit($$$;$$)`
+
+Passed a file, message, token (from `rcs_prepedit`), user, and ip address.
+Should try to commit the file. Returns `undef` on *success* and a version
+of the page with the rcs's conflict markers on failure.
+
+#### `rcs_commit_staged($$$)`
+
+Passed a message, user, and ip address. Should commit all staged changes.
+Returns undef on success, and an error message on failure.
+
+Changes can be staged by calls to `rcs_add, `rcs_remove`, and
+`rcs_rename`.
+
+#### `rcs_add($)`
+
+Adds the passed file to the archive. The filename is relative to the root
+of the srcdir.
+
+Note that this should not check the new file in, it should only
+prepare for it to be checked in when rcs_commit (or `rcs_commit_staged`) is
+called. Note that the file may be in a new subdir that is not yet in
+to version control; the subdir can be added if so.
+
+#### `rcs_remove($)`
+
+Remove a file. The filename is relative to the root of the srcdir.
+
+Note that this should not check the removal in, it should only prepare for it
+to be checked in when `rcs_commit` (or `rcs_commit_staged`) is called. Note
+that the new file may be in a new subdir that is not yet inversion
+control; the subdir can be added if so.
+
+#### `rcs_rename($$)`
+
+Rename a file. The filenames are relative to the root of the srcdir.
+
+Note that this should not commit the rename, it should only
+prepare it for when `rcs_commit` (or `rcs_commit_staged`) is called.
+The new filename may be in a new subdir, that is not yet added to
+version control. If so, the subdir will exist already, and should
+be added to revision control.
+
+#### `rcs_recentchanges($)`
+
+Examine the RCS history and generate a list of recent changes.
+The parameter is how many changes to return.
+
+The data structure returned for each change is:
+
+ {
+ rev => # the RCSs id for this commit
+ user => # name of user who made the change,
+ committype => # either "web" or the name of the rcs,
+ when => # time when the change was made,
+ message => [
+ { line => "commit message line 1" },
+ { line => "commit message line 2" },
+ # etc,
+ ],
+ pages => [
+ {
+ page => # name of page changed,
+ diffurl => # optional url to a diff of changes
+ },
+ # repeat for each page changed in this commit,
+ ],
+ }
+
+#### `rcs_diff($)`
+
+The parameter is the rev from `rcs_recentchanges`.
+Should return a list of lines of the diff (including \n) in list
+context, and the whole diff in scalar context.
+
+#### `rcs_getctime($)`
-Each RCS plugin must support all the `IkiWiki::rcs_*` functions.
-See IkiWiki::RCS::Stub for the full list of functions. It's ok if
-`rcs_getctime` does nothing except for throwing an error.
+This is used to get the page creation time for a file from the RCS, by looking
+it up in the history.
-See [[RCS_details|rcs/details]] for some more info.
+It's ok if this is not implemented, and throws an error.
### PageSpec plugins
### Setup plugins
-The ikiwiki setup file is loaded using a pluggable mechanism. If you
-look at the top of [[ikiwiki.setup]], it starts with
-'use IkiWiki::Setup::Standard', and the rest of the file is passed to
-that module's import method.
+The ikiwiki setup file is loaded using a pluggable mechanism. If you look
+at the top of a setup file, it starts with 'use IkiWiki::Setup::Standard',
+and the rest of the file is passed to that module's import method.
It's possible to write other modules in the `IkiWiki::Setup::` namespace that
can be used to configure ikiwiki in different ways. These modules should,
when imported, populate `$IkiWiki::Setup::raw_setup` with a reference
-to a hash containing all the config items.
+to a hash containing all the config items. They should also implement a
+`gendump` function.
By the way, to parse a ikiwiki setup file, a program just needs to
do something like:
command to save disk space.
Note that, as a rule of thumb, you should always put the rcs wrapper (`post-update`)
-into the master repository (`.git/hooks/`) as can be noticed in the Git wrappers of
-the sample [[ikiwiki.setup]].
+into the master repository (`.git/hooks/`).
Here is how a web edit works with ikiwiki and git:
## setup files
Setup files are not safe to keep in the same revision control repository
-with the rest of the wiki. Just don't do it. [[ikiwiki.setup]] is *not*
-used as the setup file for this wiki, BTW.
+with the rest of the wiki. Just don't do it.
## page locking can be bypassed via direct commits
If you're using Debian or Ubuntu, ikiwiki is an `apt-get install ikiwiki` away.
If you're not, see the [[download]] and [[install]] pages.
+## Quick start
+
+If you'd like to set up a wiki now, and learn more later, just run this command
+and answer a couple of questions.
+
+ % ikiwiki -setup /etc/ikiwiki/auto.setup
+ What will the wiki be named? mywiki
+ What revision control system to use? git
+ What wiki user (or openid) will be wiki admin? joey
+
+Wait for it to tell you an url for your new wiki.. Done!
+
+(If the CGI doesn't seem to let you edit pages, you might need to
+[[configure_apache|apache_cgi]]).)
+
## Decide where your wiki's files will go.
As a wiki compiler, ikiwiki builds a wiki from files in a source directory,
By now you should be getting tired of typing in all the command line
options each time you change something in your wiki's setup. Time to
introduce setup files.
-
-A sample setup file is [[ikiwiki.setup]]. Download it (or copy it from
-`doc/ikiwiki.setup` in the ikiwiki sources), and edit it. Note that this
-file should *not* be put in your wiki's directory with the rest of the
-files. A good place to put it is in a ~/.ikiwiki/ subdirectory.
+
+To generate a setup file, use `ikiwiki --dumpsetup`. You can pass
+all the options have you been including at the command line, and they
+will be stored in the setup file.
+
+ ikiwiki $SRCDIR $DESTDIR --url=http://example.org/~you/wiki/ --dumpsetup ikiwiki.setup
+
+Note that this file should *not* be put in your wiki's directory with
+the rest of the files. A good place to put it is in a ~/.ikiwiki/
+subdirectory.
Most of the options, like `wikiname` in the setup file are the same as
ikiwiki's command line options (documented in [[usage]]. `srcdir` and
## Turn on additional features.
-Now you have a basic wiki with a configuration file. Time to experiment
+Now you have a basic wiki with a setup file. Time to experiment
with ikiwiki's many features.
Let's first enable a key wiki feature and set up [[CGI]] to allow
editing the wiki from the web. Just edit ikiwiki.setup, uncomment the
-block for the cgi wrapper, make sure the filename for the cgi wrapper
+settings for the `cgi_wrapper`, make sure the filename for the cgi wrapper
is ok, run `ikiwiki --setup ikiwiki.setup`, and you're done!
There are lots of other configuration options in ikiwiki.setup that you
Note that the .ikiwiki subdirectory is where ikiwiki keeps its state, and
should be preserved, but not checked into revision control.
-The new [[ikiwiki-makerepo]] command automates setting up a wiki in
+The [[ikiwiki-makerepo]] command automates setting up a wiki in
revision control.
[[!toggle id=subversion text="Subversion"]]
# remember the password you use in the next step and
# substitute it for 'wikiKeyPass' in the get_passphrase() hook below
# note the you should never generate two monotone keys with the same name
- mtn genkey web@machine.company.com
+ mtn genkey web@example.com
mtn db init --db=$REPOSITORY
mv $SRCDIR $SRCDIR-old
cd $SRCDIR-old
Once your wiki is checked in to the revision control system,
you should configure ikiwiki to use revision control. Edit your
-ikiwiki.setup, and uncomment the lines for the revision control system
+ikiwiki.setup, set `rcs` to the the revision control system
you chose to use. Be sure to set `svnrepo` to $REPOSITORY, if using
-subversion. Uncomment the block for the wrapper for your revision
-control system, and configure the wrapper path in that block
-appropriately (for Git, it should be `$REPOSITORY/hooks/post-update`).
+subversion. Uncomment the configuration for the wrapper for your revision
+control system, and configure the wrapper path appropriately
+(for Git, it should be `$REPOSITORY/hooks/post-update`).
Once it's all set up, run `ikiwiki --setup ikiwiki.setup` once more.
Now you should be able to edit files in $SRCDIR, and use your revision
mkdir ~/wiki
cd ~/wiki
- cp ~/ikiwiki/doc/ikiwiki.setup .
cp -r ~/ikiwiki/doc/examples/blog/* .
+ ikiwiki -dumpsetup ikiwiki.setup
nano ikiwiki.setup
# Set destdir to /home/htdocs
# Set srcdir to /home/private/wiki
# Set url to http://yoursite.nfshost.com/ , set cgiurl likewise
- # Uncomment the `rcs => "git"` line, and the cgi and git
- # post-update wrapper blocks.
- # Set the cgi wrapper path to /home/htdocs/ikiwiki.cgi
- # Set the git wrapper path to /home/private/wiki.git/hooks/post-update
+ # Uncomment the `rcs => "git"` line.
+ # Set the cgi_wrapper path to /home/htdocs/ikiwiki.cgi
+ # Set the git_wrapper path to /home/private/wiki.git/hooks/post-update
# Configure the rest to your liking and save the file.
ikiwiki-makerepo git . ../wiki.git
ikiwiki -setup ikiwiki.setup
-The current example [[ikiwiki.setup]] file has a number of options included, but commented out. This is standard. Unfortunately there are two standards for the settings of those commented out options:
+The current example ikiwiki.setup file has a number of options included, but commented out. This is standard. Unfortunately there are two standards for the settings of those commented out options:
- Have the commented out options showing the default setting, or
- Have the commented out options showing the most common alternate setting.
> I may not work on it myself, since I have some
> [[interesting_ideas|online_configuration]] that would let ikiwiki
> generate a setup file for you, rather than having to keep maintain the
-> current example. --[[Joey]]
+> current example.
+>
+> And.. [[done]].. setup files are now generated with `--dumpsetup`, based on
+> the built-in defaults, and commented options show an example
+> setting, not a default. --[[Joey]]
+`/etc/ssl/certs/ca-certificates.crt` is sufficient).
> It would be good to add commented-out examples of these to
-> [[ikiwiki.setup]] as well.
+> ikiwiki.setup as well.
+This plugin is not enabled by default. It can not be used with other
+authentication plugin, such as [[passwordauth]] or [[openid]].
+ \[[!color background=#ff0000 text="Default color text on red background"]]
+
+Foreground is missing, so the text has default color.
- +
- +This plugin is not enabled by default. You can do that in [[ikiwiki.setup]]
- +file (hint: `add_plugins` variable).
--- style.css-orig 2008-07-27 15:12:39.000000000 +0200
+++ style.css 2008-07-27 15:15:06.000000000 +0200
@@ -333,3 +333,7 @@
[[conditional_text_based_on_ikiwiki_features]] available, ikiwiki could
parse a page like conditionalpages.mdwn, which could contain a set of
conditional-wrapped page names; that seems like the most elegant and
-ikiwiki-like approach. Alternatively, [[/ikiwiki.setup]] could contain a
+ikiwiki-like approach. Alternatively, ikiwiki.setup could contain a
Perl-generated exclude option by default; that would work, but it seems
hackish.
That seems like a bad choice in the context of this idea. Instead, admin
setup should be configured on a separate page than the regular user prefs
page, and should be shared amoung all admins, and the ideal storage would be
-another ikiwiki setup file, which could be loaded in, and written back out.
+a ikiwiki setup file, which could be loaded in, and written back out.
-If `ikiwiki-makerepo` were extended a little bit to generate the stub setup
-file that's enough to get `ikiwiki.cgi` working, and that sets values for
-all the dangerous options, leaving only safe ones 'undef', then users could
-set up ikiwiki using it, and configure the rest with the web interface,
-without ever needing to edit a setup file.
+The underlying work has been done to privide metadata about all options via
+getsetup hooks, so it's just a matter of writing a web interface plugin.
-The setup page could `require` every available plugin, and then call a
-`getsetup` function, which would look something like:
+The plugin could have these config options:
- sub getsetup () {
- eval q{use Some::Thing};
- die $@ if $@;
+ # list of options to include in web setup (safe = all things with safe = 1)
+ websetup_include => [qw{safe}],
+ # list of options to exclude from web setup
+ websetup_exclude => [qw{option_baz}],
- return option_foo => {
- safe => 1,
- rebuild => 1,
- type => "boolean",
- default => 0,
- description => gettext("Enable foo."),
- },
- option_bar => {
- safe => 0,
- rebuild => 0,
- type => "password",
- default => "",
- description => gettext("Password for bar."),
- };
- }
-
-The types would be: boolean, string, password, filename, other.
-This would be the type of the leaf fields; if a value in `%config` is an
-array or hash, the type specifies the type of values that go into it.
-
-From this info, a form can be built, that has core setup values at the
-top, followed by each plugin whose `getsetup` succeeded, with a check box
-to enable/disable that plugin, and all of its setup options listed after
-it.
-
-The main setup file could control what options are read from the
-online setup file:
-
- online_setup_include => 'safe', # all things with safe = 1
- online_setup_exclude => [qw{option_baz}],
-
-Note that posting the setup form would sometimes need to cause a rebuild
-of the whole wiki. This could be done with output streamed to the admin in
-the web browser. The `rebuild` fields would be set to 1 for values that
-require a wiki rebuild when changed, and to 0 for values that only need the
-wrappers to be refreshed.
+Leaning toward just making it write out to the same setup file, rather than
+writing to a subsidiary setup file. However, this would mean that any
+comments in the file would be lost, and that it couldn't be used if the
+setup file had weird stuff (perl code, etc).
[[!tag wishlist]]
In setup mode, ikiwiki reads the config file, which is really a perl
program that can call ikiwiki internal functions.
- [[ikiwiki.setup]] is an example of such a config file.
-
The default action when --setup is specified is to automatically generate
wrappers for a wiki based on data in a config file, and rebuild the wiki.
If you only want to build any changed pages, you can use --refresh with
--setup.
+* --dumpsetup configfile
+
+ Causes ikiwiki to write to the specified config file, dumping out
+ its current configuration.
+
* --wrappers
If used with --setup --refresh, this makes it also update any configured
cgiurl => 'ikiwiki.cgi',
rcs => "",
- wrappers => [
- {
- # The cgi wrapper.
- cgi => 1,
- # The wrapper must be put in ~/.ikiwiki/wrappers/, since
- # ikiwiki-w3m.cgi only looks in this one location.
- # The wrapper can be given any name as long as it's
- # in that directory.
- wrapper => "$ENV{HOME}/.ikiwiki/wrappers/ikiwiki.cgi",
- wrappermode => "0755",
- },
- ],
-
+ # The wrapper must be put in ~/.ikiwiki/wrappers/, since
+ # ikiwiki-w3m.cgi only looks in this one location.
+ # The wrapper can be given any name as long as it's
+ # in that directory.
+ cgi_wrapper => "$ENV{HOME}/.ikiwiki/wrappers/ikiwiki.cgi",
+ cgi_wrappermode => "0755",
+
add_plugins => [qw{anonok}],
rss => 1,
atom => 1,
destdir => "html",
templatedir => "templates",
underlaydir => "underlays/basewiki",
- wrappers => [],
discussion => 0,
exclude => qr/\/discussion|bugs\/*|todo\/*/,
locale => '',
use strict;
use English;
+my $remove=(@ARGV && $ARGV[0] eq '-r');
+
my $username=getpwuid($REAL_USER_ID);
if (! defined $username || ! length $username) {
die "unable to determine user name for UID $REAL_USER_ID\n";
die "$wikilist does not exist\n";
}
-my $removed=0;
+my $changed=0;
+my $seen=0;
my @lines;
open (my $list, "<$wikilist") || die "read $wikilist: $!";
while (<$list>) {
if (/^\s*([^\s]+)\s*$/) {
my $user=$1;
if ($user eq $username) {
- $removed=1;
+ if (! $remove) {
+ $seen=1;
+ push @lines, $_;
+ }
}
else {
push @lines, $_;
push @lines, $_;
}
}
-close $list || die "error reading $list: $!";
-open ($list, ">$wikilist") || die "write $wikilist: $!";
-foreach (@lines) {
- print $list "$_\n";
+if (! $seen && ! $remove) {
+ push @lines, $username;
+ $changed=1;
}
-if ($removed) {
- print "removed user $username from $wikilist\n";
+if ($changed) {
+ close $list || die "ikiwiki-update-wikilist: error reading $list: $!\n";
+ open ($list, ">$wikilist") || die "ikiwiki-update-wikilist: cannot write to $wikilist\n";
+ foreach (@lines) {
+ print $list "$_\n";
+ }
+ if ($remove) {
+ print "ikiwiki-update-wikilist: removed user $username from $wikilist\n";
+ }
+ else {
+ print "ikiwiki-update-wikilist: added user $username to $wikilist\n";
+ }
+ close $list || die "ikiwiki-update-wikilist: error writing $wikilist: $!\n";
}
else {
- print $list "$username\n";
- print "added user $username to $wikilist\n";
+ print "ikiwiki-update-wikilist: no changes need to be made\n";
}
-close $list || die "error writing $list: $!";
Getopt::Long::Configure('pass_through');
GetOptions(
"setup|s=s" => \$config{setup},
+ "dumpsetup|s=s" => \$config{dumpsetup},
"wikiname=s" => \$config{wikiname},
"verbose|v!" => \$config{verbose},
"syslog!" => \$config{syslog},
"refresh!" => \$config{refresh},
"post-commit" => \$config{post_commit},
"render=s" => \$config{render},
- "wrappers!" => \$config{wrappers},
+ "wrappers!" => \$config{genwrappers},
"usedirs!" => \$config{usedirs},
"prefix-directives!" => \$config{prefix_directives},
"getctime" => \$config{getctime},
"adminemail=s" => \$config{adminemail},
"timeformat=s" => \$config{timeformat},
"sslcookie!" => \$config{sslcookie},
- "httpauth!" => \$config{httpauth},
"userdir=s" => \$config{userdir},
"htmlext=s" => \$config{htmlext},
"libdir=s" => \$config{libdir},
$config{wrappermode}=possibly_foolish_untaint($_[1])
},
"plugin=s@" => sub {
- push @{$config{plugin}}, $_[1];
+ push @{$config{add_plugins}}, $_[1];
},
"disable-plugin=s@" => sub {
push @{$config{disable_plugins}}, $_[1];
},
- "pingurl=s" => sub {
- push @{$config{pingurl}}, $_[1];
- },
"set=s" => sub {
my ($var, $val)=split('=', $_[1], 2);
if (! defined $var || ! defined $val) {
if (! $config{setup} && ! $config{render}) {
loadplugins();
- usage() unless @ARGV == 2;
- $config{srcdir} = possibly_foolish_untaint(shift @ARGV);
- $config{destdir} = possibly_foolish_untaint(shift @ARGV);
- checkconfig();
+ if (@ARGV == 2) {
+ $config{srcdir} = possibly_foolish_untaint(shift @ARGV);
+ $config{destdir} = possibly_foolish_untaint(shift @ARGV);
+ checkconfig();
+ }
+ else {
+ usage() unless $config{dumpsetup};
+ }
}
}
else {
if ($config{setup}) {
require IkiWiki::Setup;
- setup();
+ IkiWiki::Setup::load($config{setup});
+
+ loadplugins();
+ checkconfig();
+
+ if (@{$config{wrappers}} &&
+ ! $config{render} && ! $config{dumpsetup} &&
+ (! $config{refresh} || $config{genwrappers})) {
+ debug(gettext("generating wrappers.."));
+ require IkiWiki::Wrapper;
+ my %origconfig=(%config);
+ my @wrappers=@{$config{wrappers}};
+ delete $config{wrappers};
+ delete $config{genwrappers};
+ foreach my $wrapper (@wrappers) {
+ %config=(%origconfig,
+ rebuild => 0,
+ verbose => 0,
+ %{$wrapper},
+ );
+ checkconfig();
+ if (! $config{cgi} && ! $config{post_commit}) {
+ $config{post_commit}=1;
+ }
+ gen_wrapper();
+ }
+ %config=(%origconfig);
+ }
+
+ # setup implies a wiki rebuild by default
+ if (! $config{refresh}) {
+ $config{rebuild}=1;
+ }
+
+ # ignore syslog setting from setup file
+ # while doing initial setup
+ $config{syslog}=0 unless $config{dumpsetup};
+ }
+
+ if ($config{dumpsetup}) {
+ require IkiWiki::Setup;
+ IkiWiki::Setup::dump($config{dumpsetup});
}
elsif ($config{wrapper}) {
lockwiki();
# do nothing
}
else {
+ if (! $config{refresh}) {
+ debug(gettext("rebuilding wiki.."));
+ }
+ else {
+ debug(gettext("refreshing wiki.."));
+ }
lockwiki();
loadindex();
require IkiWiki::Render;
rcs_update();
refresh();
saveindex();
+ debug(gettext("done"));
}
} #}}}
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-07-25 16:16-0400\n"
+"POT-Creation-Date: 2008-07-27 01:52-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgstr ""
#: ../IkiWiki/CGI.pm:437 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:261 ../IkiWiki/Plugin/opendiscussion.pm:17
+#: ../IkiWiki/Plugin/inline.pm:306 ../IkiWiki/Plugin/opendiscussion.pm:17
#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:78
#: ../IkiWiki/Render.pm:148
msgid "discussion"
msgid "You are banned."
msgstr ""
-#: ../IkiWiki/CGI.pm:758 ../IkiWiki/CGI.pm:759 ../IkiWiki.pm:788
+#: ../IkiWiki/CGI.pm:758 ../IkiWiki/CGI.pm:759 ../IkiWiki.pm:1086
msgid "Error"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:57
+#: ../IkiWiki/Plugin/aggregate.pm:76
msgid "Aggregation triggered via web."
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:66
+#: ../IkiWiki/Plugin/aggregate.pm:85
msgid "Nothing to do right now, all feeds are up-to-date!"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:193
+#: ../IkiWiki/Plugin/aggregate.pm:212
#, perl-format
msgid "missing %s parameter"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:227
+#: ../IkiWiki/Plugin/aggregate.pm:246
msgid "new feed"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:241
+#: ../IkiWiki/Plugin/aggregate.pm:260
msgid "posts"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:243
+#: ../IkiWiki/Plugin/aggregate.pm:262
msgid "new"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:406
+#: ../IkiWiki/Plugin/aggregate.pm:425
#, perl-format
msgid "expiring %s (%s days old)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:413
+#: ../IkiWiki/Plugin/aggregate.pm:432
#, perl-format
msgid "expiring %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:440
+#: ../IkiWiki/Plugin/aggregate.pm:459
#, perl-format
msgid "processed ok at %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:444
+#: ../IkiWiki/Plugin/aggregate.pm:463
#, perl-format
msgid "checking feed %s ..."
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:449
+#: ../IkiWiki/Plugin/aggregate.pm:468
#, perl-format
msgid "could not find feed at %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:464
+#: ../IkiWiki/Plugin/aggregate.pm:483
msgid "feed not found"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:475
+#: ../IkiWiki/Plugin/aggregate.pm:494
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:481
+#: ../IkiWiki/Plugin/aggregate.pm:500
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:487
+#: ../IkiWiki/Plugin/aggregate.pm:506
msgid "feed crashed XML::Feed!"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:561
+#: ../IkiWiki/Plugin/aggregate.pm:580
#, perl-format
msgid "creating new page %s"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:30
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
msgid "deleting bucket.."
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:37 ../IkiWiki/Setup.pm:117
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:193
msgid "done"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:46
+#: ../IkiWiki/Plugin/amazon_s3.pm:93
#, perl-format
msgid "Must specify %s"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:85
+#: ../IkiWiki/Plugin/amazon_s3.pm:132
msgid "Failed to create bucket in S3: "
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:170
+#: ../IkiWiki/Plugin/amazon_s3.pm:217
msgid "Failed to save file to S3: "
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:192
+#: ../IkiWiki/Plugin/amazon_s3.pm:239
msgid "Failed to delete file from S3: "
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:22
+#: ../IkiWiki/Plugin/attachment.pm:34
#, perl-format
msgid "there is already a page named %s"
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:41
+#: ../IkiWiki/Plugin/attachment.pm:53
msgid "prohibited by allowed_attachments"
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:144
+#: ../IkiWiki/Plugin/attachment.pm:156
msgid "bad attachment filename"
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:186
+#: ../IkiWiki/Plugin/attachment.pm:198
msgid "attachment upload"
msgstr ""
msgid "There are no broken links!"
msgstr ""
-#: ../IkiWiki/Plugin/conditional.pm:18 ../IkiWiki/Plugin/testpagespec.pm:17
+#: ../IkiWiki/Plugin/conditional.pm:18 ../IkiWiki/Plugin/cutpaste.pm:22
+#: ../IkiWiki/Plugin/cutpaste.pm:37 ../IkiWiki/Plugin/cutpaste.pm:53
+#: ../IkiWiki/Plugin/testpagespec.pm:17
#, perl-format
msgid "%s parameter is required"
msgstr ""
+#: ../IkiWiki/Plugin/cutpaste.pm:58
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:61
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
#: ../IkiWiki/Plugin/edittemplate.pm:41
msgid "template not specified"
msgstr ""
msgid "failed to determine size of image %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:47
+#: ../IkiWiki/Plugin/inline.pm:89
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:101
+#: ../IkiWiki/Plugin/inline.pm:146
msgid "missing pages parameter"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:149
+#: ../IkiWiki/Plugin/inline.pm:194
#, perl-format
msgid "unknown sort type %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:220
+#: ../IkiWiki/Plugin/inline.pm:265
msgid "Add a new post titled:"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:236
+#: ../IkiWiki/Plugin/inline.pm:281
#, perl-format
msgid "nonexistant template %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:269 ../IkiWiki/Render.pm:82
+#: ../IkiWiki/Plugin/inline.pm:314 ../IkiWiki/Render.pm:82
msgid "Discussion"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:506
+#: ../IkiWiki/Plugin/inline.pm:551
msgid "RPC::XML::Client not found, not pinging"
msgstr ""
msgid "%s is locked by %s and cannot be edited"
msgstr ""
-#: ../IkiWiki/Plugin/mdwn.pm:28
+#: ../IkiWiki/Plugin/mdwn.pm:40
msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
msgstr ""
-#: ../IkiWiki/Plugin/mdwn.pm:51
+#: ../IkiWiki/Plugin/mdwn.pm:63
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
msgid "redir cycle is not allowed"
msgstr ""
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:35
msgid "Mirrors"
msgstr ""
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:35
msgid "Mirror"
msgstr ""
msgid "more"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:55
+msgid "getctime not implemented"
+msgstr ""
+
+#: ../IkiWiki/Plugin/openid.pm:57
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:60
msgid "Get an OpenID"
msgstr ""
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:223
+#: ../IkiWiki/Plugin/passwordauth.pm:243
msgid "Account creation successful. Now you can Login."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:226
+#: ../IkiWiki/Plugin/passwordauth.pm:246
msgid "Error creating account."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:233
+#: ../IkiWiki/Plugin/passwordauth.pm:253
msgid "No email address, so cannot email password reset instructions."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:265
+#: ../IkiWiki/Plugin/passwordauth.pm:287
msgid "Failed to send mail"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:267
+#: ../IkiWiki/Plugin/passwordauth.pm:289
msgid "You have been mailed password reset instructions."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:302
+#: ../IkiWiki/Plugin/passwordauth.pm:324
msgid "incorrect password reset url"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:305
+#: ../IkiWiki/Plugin/passwordauth.pm:327
msgid "password reset denied"
msgstr ""
msgid "Ping received."
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:37
+#: ../IkiWiki/Plugin/pinger.pm:49
msgid "requires 'from' and 'to' parameters"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:42
+#: ../IkiWiki/Plugin/pinger.pm:54
#, perl-format
msgid "Will ping %s"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:45
+#: ../IkiWiki/Plugin/pinger.pm:57
#, perl-format
msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:61
+#: ../IkiWiki/Plugin/pinger.pm:73
msgid "LWP not found, not pinging"
msgstr ""
msgid "%A night"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:96
msgid "at teatime on %A"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:100
msgid "at midnight"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:103
msgid "at noon on %A"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/recentchanges.pm:95
msgid "missing page"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:78
+#: ../IkiWiki/Plugin/recentchanges.pm:97
#, perl-format
msgid "The page %s does not exist."
msgstr ""
msgid "update for rename of %s to %s"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:20
+#: ../IkiWiki/Plugin/search.pm:32
#, perl-format
msgid "Must specify %s when using the search plugin"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:166
+#: ../IkiWiki/Plugin/search.pm:178
#, perl-format
msgid "need Digest::SHA1 to index %s"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:201
+#: ../IkiWiki/Plugin/search.pm:213
msgid "search"
msgstr ""
msgid "failed to generate image from code"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:96
-msgid "getctime not implemented"
-msgstr ""
-
#: ../IkiWiki/Render.pm:276 ../IkiWiki/Render.pm:297
#, perl-format
msgid "skipping bad filename %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:25
+#: ../IkiWiki/Setup.pm:23
#, perl-format
msgid "cannot read %s: %s"
msgstr ""
-#: ../IkiWiki/Setup.pm:58
-msgid "generating wrappers.."
-msgstr ""
-
-#: ../IkiWiki/Setup.pm:107
-msgid "rebuilding wiki.."
-msgstr ""
-
-#: ../IkiWiki/Setup.pm:110
-msgid "refreshing wiki.."
-msgstr ""
-
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "%s doesn't seem to be executable"
msgid "usage: ikiwiki [options] source dest"
msgstr ""
-#: ../ikiwiki.in:82
+#: ../ikiwiki.in:79
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:126
+#: ../ikiwiki.in:126
+msgid "generating wrappers.."
+msgstr ""
+
+#: ../ikiwiki.in:182
+msgid "rebuilding wiki.."
+msgstr ""
+
+#: ../ikiwiki.in:185
+msgid "refreshing wiki.."
+msgstr ""
+
+#: ../IkiWiki.pm:410
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:771
+#: ../IkiWiki.pm:1069
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "preprocessing loop detected on %s at depth %i"
msgstr ""
-#: ../IkiWiki.pm:1219
+#: ../IkiWiki.pm:1557
msgid "yes"
msgstr ""
my @progs="ikiwiki.in";
my @libs="IkiWiki.pm";
# monotone, external, amazon_s3 skipped since they need perl modules
-push @libs, map { chomp; $_ } `find IkiWiki -type f -name \\*.pm | grep -v IkiWiki/Rcs/monotone.pm | grep -v IkiWiki/Plugin/external.pm | grep -v IkiWiki/Plugin/amazon_s3.pm`;
+push @libs, map { chomp; $_ } `find IkiWiki -type f -name \\*.pm | grep -v monotone.pm | grep -v external.pm | grep -v amazon_s3.pm`;
plan(tests => (@progs + @libs));