diff options
Diffstat (limited to 'IkiWiki')
27 files changed, 810 insertions, 110 deletions
diff --git a/IkiWiki/Plugin/aggregate.pm b/IkiWiki/Plugin/aggregate.pm index e000bc864..673668c0e 100644 --- a/IkiWiki/Plugin/aggregate.pm +++ b/IkiWiki/Plugin/aggregate.pm @@ -16,6 +16,7 @@ my %guids; 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); @@ -37,6 +38,24 @@ sub getopt () { #{{{ ); } #}}} +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())) { diff --git a/IkiWiki/Plugin/amazon_s3.pm b/IkiWiki/Plugin/amazon_s3.pm index 187700f30..e181a84da 100644 --- a/IkiWiki/Plugin/amazon_s3.pm +++ b/IkiWiki/Plugin/amazon_s3.pm @@ -18,6 +18,7 @@ BEGIN { 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); } # }}} @@ -39,6 +40,52 @@ sub getopt () { #{{{ }); } #}}} +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}) { diff --git a/IkiWiki/Plugin/anonok.pm b/IkiWiki/Plugin/anonok.pm index 1880516d5..7b966f845 100644 --- a/IkiWiki/Plugin/anonok.pm +++ b/IkiWiki/Plugin/anonok.pm @@ -6,9 +6,21 @@ use strict; 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; diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm index 720078be1..47e165251 100644 --- a/IkiWiki/Plugin/attachment.pm +++ b/IkiWiki/Plugin/attachment.pm @@ -6,11 +6,23 @@ use strict; 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 diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index aed087eed..6f1f9bd07 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -30,10 +30,22 @@ my $time=time; 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)); diff --git a/IkiWiki/Plugin/graphviz.pm b/IkiWiki/Plugin/graphviz.pm index b13d15fa6..021aa6b23 100644 --- a/IkiWiki/Plugin/graphviz.pm +++ b/IkiWiki/Plugin/graphviz.pm @@ -9,7 +9,7 @@ use IkiWiki 2.00; use IPC::Open2; sub import { #{{{ - hook(type => "preprocess", id => "graph", call => \&graph); + hook(type => "preprocess", id => "graphviz", call => \&graph); } # }}} my %graphviz_programs = ( diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index 2f0901943..cdd0ab0dc 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -15,6 +15,7 @@ my $nested=0; 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", @@ -27,7 +28,6 @@ sub import { #{{{ # pings interrupting page builds. hook(type => "change", id => "inline", call => \&IkiWiki::pingurl); - } # }}} sub getopt () { #{{{ @@ -39,8 +39,50 @@ 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}) { @@ -52,6 +94,9 @@ sub checkconfig () { #{{{ if ($config{atom}) { push @{$config{wiki_file_prune_regexps}}, qr/\.atom$/; } + if (! exists $config{pingurl}) { + $config{pingurl}=[]; + } } #}}} sub format (@) { #{{{ diff --git a/IkiWiki/Plugin/mdwn.pm b/IkiWiki/Plugin/mdwn.pm index 11f3f0137..332325adc 100644 --- a/IkiWiki/Plugin/mdwn.pm +++ b/IkiWiki/Plugin/mdwn.pm @@ -7,9 +7,21 @@ use strict; 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=@_; @@ -25,13 +37,13 @@ sub htmlize (@) { #{{{ 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')) { diff --git a/IkiWiki/Plugin/mirrorlist.pm b/IkiWiki/Plugin/mirrorlist.pm index 3997e6fef..f7c78fdee 100644 --- a/IkiWiki/Plugin/mirrorlist.pm +++ b/IkiWiki/Plugin/mirrorlist.pm @@ -6,9 +6,21 @@ use strict; 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}; diff --git a/IkiWiki/Plugin/openid.pm b/IkiWiki/Plugin/openid.pm index 10a8fa22f..de7f7280e 100644 --- a/IkiWiki/Plugin/openid.pm +++ b/IkiWiki/Plugin/openid.pm @@ -8,6 +8,7 @@ use IkiWiki 2.00; 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); @@ -20,6 +21,17 @@ sub getopt () { #{{{ 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=@_; diff --git a/IkiWiki/Plugin/passwordauth.pm b/IkiWiki/Plugin/passwordauth.pm index f3f1aa4bf..82afeef98 100644 --- a/IkiWiki/Plugin/passwordauth.pm +++ b/IkiWiki/Plugin/passwordauth.pm @@ -7,13 +7,30 @@ use strict; 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; @@ -88,7 +105,9 @@ sub formbuilder_setup (@) { #{{{ 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(""); @@ -125,7 +144,8 @@ sub formbuilder_setup (@) { #{{{ 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", @@ -259,7 +279,9 @@ sub formbuilder (@) { #{{{ 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")); diff --git a/IkiWiki/Plugin/pinger.pm b/IkiWiki/Plugin/pinger.pm index 614d42885..e72833b8f 100644 --- a/IkiWiki/Plugin/pinger.pm +++ b/IkiWiki/Plugin/pinger.pm @@ -9,12 +9,24 @@ my %pages; 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) { diff --git a/IkiWiki/Plugin/prettydate.pm b/IkiWiki/Plugin/prettydate.pm index 745e6a1de..db5a94f41 100644 --- a/IkiWiki/Plugin/prettydate.pm +++ b/IkiWiki/Plugin/prettydate.pm @@ -40,9 +40,27 @@ sub default_timetable { } 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') { diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 8383fb72a..d534d0cd9 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -6,6 +6,7 @@ use strict; 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); @@ -13,6 +14,24 @@ sub import { #{{{ 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}; diff --git a/IkiWiki/Plugin/search.pm b/IkiWiki/Plugin/search.pm index eedfa6924..cb12d9500 100644 --- a/IkiWiki/Plugin/search.pm +++ b/IkiWiki/Plugin/search.pm @@ -7,6 +7,7 @@ use strict; 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); @@ -14,6 +15,17 @@ sub import { #{{{ 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}) { @@ -21,7 +33,7 @@ sub checkconfig () { #{{{ } } - if (! exists $config{omega_cgi}) { + if (! defined $config{omega_cgi}) { $config{omega_cgi}="/usr/lib/cgi-bin/omega/omega"; } } #}}} diff --git a/IkiWiki/Plugin/skeleton.pm.example b/IkiWiki/Plugin/skeleton.pm.example index 1af8e4e9d..49c4d88f2 100644 --- a/IkiWiki/Plugin/skeleton.pm.example +++ b/IkiWiki/Plugin/skeleton.pm.example @@ -10,6 +10,7 @@ use IkiWiki 2.00; 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 => "needsbuild", id => "skeleton", call => \&needsbuild); hook(type => "preprocess", id => "skeleton", call => \&preprocess); @@ -38,6 +39,17 @@ sub getopt () { #{{{ 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"); } #}}} diff --git a/IkiWiki/Plugin/tag.pm b/IkiWiki/Plugin/tag.pm index b0a0e53be..36b434f67 100644 --- a/IkiWiki/Plugin/tag.pm +++ b/IkiWiki/Plugin/tag.pm @@ -10,6 +10,7 @@ my %tags; 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); @@ -22,6 +23,17 @@ sub getopt () { #{{{ 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; diff --git a/IkiWiki/Plugin/typography.pm b/IkiWiki/Plugin/typography.pm index fe6996898..6229e6c33 100644 --- a/IkiWiki/Plugin/typography.pm +++ b/IkiWiki/Plugin/typography.pm @@ -8,6 +8,7 @@ use IkiWiki 2.00; sub import { #{{{ hook(type => "getopt", id => "typography", call => \&getopt); + hook(type => "getsetup", id => "typography", call => \&getsetup); IkiWiki::hook(type => "sanitize", id => "typography", call => \&sanitize); } # }}} @@ -18,11 +19,25 @@ sub getopt () { #{{{ 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); diff --git a/IkiWiki/Rcs/bzr.pm b/IkiWiki/Rcs/bzr.pm index c80356159..5df522f6e 100644 --- a/IkiWiki/Rcs/bzr.pm +++ b/IkiWiki/Rcs/bzr.pm @@ -8,6 +8,50 @@ use IkiWiki; use Encode; use open qw{:utf8 :std}; +hook(type => "checkconfig", id => "bzr", call => sub { #{{{ + if (! defined $config{diffurl}) { + $config{diffurl}=""; + } + if (length $config{bzr_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{bzr_wrapper}, + wrappermode => (defined $config{bzr_wrappermode} ? $config{bzr_wrappermode} : "06755"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "bzr", call => sub { #{{{ + 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 = (); diff --git a/IkiWiki/Rcs/git.pm b/IkiWiki/Rcs/git.pm index ecf560d0b..6c9aca650 100644 --- a/IkiWiki/Rcs/git.pm +++ b/IkiWiki/Rcs/git.pm @@ -11,6 +11,70 @@ use open qw{:utf8 :std}; 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 +hook(type => "checkconfig", id => "git", call => sub { #{{{ + if (! defined $config{diffurl}) { + $config{diffurl}=""; + } + if (! defined $config{gitorigin_branch}) { + $config{gitorigin_branch}="origin"; + } + if (! defined $config{gitmaster_branch}) { + $config{gitmaster_branch}="master"; + } + if (length $config{git_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{git_wrapper}, + wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "git", call => sub { #{{{ + 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). diff --git a/IkiWiki/Rcs/mercurial.pm b/IkiWiki/Rcs/mercurial.pm index 8c3f03e07..3a98e09d8 100644 --- a/IkiWiki/Rcs/mercurial.pm +++ b/IkiWiki/Rcs/mercurial.pm @@ -8,7 +8,51 @@ use IkiWiki; use Encode; use open qw{:utf8 :std}; -sub mercurial_log($) { +hook(type => "checkconfig", id => "mercurial", call => sub { #{{{ + if (! defined $config{diffurl}) { + $config{diffurl}=""; + } + if (length $config{mercurial_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{mercurial_wrapper}, + wrappermode => (defined $config{mercurial_wrappermode} ? $config{mercurial_wrappermode} : "06755"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "mercurial", call => sub { #{{{ + 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; @@ -52,7 +96,7 @@ sub mercurial_log($) { close $out; return @infos; -} +} #}}} sub rcs_update () { #{{{ my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update"); diff --git a/IkiWiki/Rcs/monotone.pm b/IkiWiki/Rcs/monotone.pm index 500af5c58..d7e8f296a 100644 --- a/IkiWiki/Rcs/monotone.pm +++ b/IkiWiki/Rcs/monotone.pm @@ -11,7 +11,7 @@ use Date::Format qw(time2str); my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate sha1sums -sub check_config() { #{{{ +hook(type => "checkconfig", id => "monotone", call => sub { #{{{ if (!defined($config{mtnrootdir})) { $config{mtnrootdir} = $config{srcdir}; } @@ -19,9 +19,6 @@ sub check_config() { #{{{ 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"; @@ -43,7 +40,66 @@ sub check_config() { #{{{ 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"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "monotone", call => sub { #{{{ + 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 () { #{{{ my $sha1 = `mtn --root=$config{mtnrootdir} automate get_base_revision_id`; @@ -190,7 +246,8 @@ sub get_changed_files ($$) { #{{{ } #}}} 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", @@ -208,7 +265,8 @@ sub rcs_update () { #{{{ 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. @@ -236,7 +294,8 @@ sub rcs_commit ($$$;$$) { #{{{ $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(); @@ -367,7 +426,8 @@ sub rcs_commit_staged ($$$) { # 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; @@ -391,7 +451,8 @@ sub rcs_commit_staged ($$$) { 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) { @@ -402,7 +463,8 @@ sub rcs_add ($) { #{{{ 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 @@ -420,7 +482,8 @@ sub rcs_remove ($) { # {{{ 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) { @@ -432,7 +495,8 @@ sub rcs_recentchanges ($) { #{{{ 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 @@ -539,7 +603,8 @@ sub rcs_diff ($) { #{{{ 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) { @@ -561,7 +626,8 @@ sub rcs_diff ($) { #{{{ sub rcs_getctime ($) { #{{{ my $file=shift; - check_config(); + chdir $config{srcdir} + or error("Cannot chdir to $config{srcdir}: $!"); my $child = open(MTNLOG, "-|"); if (! $child) { diff --git a/IkiWiki/Rcs/svn.pm b/IkiWiki/Rcs/svn.pm index 9081c3902..0e7df3659 100644 --- a/IkiWiki/Rcs/svn.pm +++ b/IkiWiki/Rcs/svn.pm @@ -1,23 +1,78 @@ #!/usr/bin/perl -package IkiWiki::Rcs::svn; +package IkiWiki; use warnings; use strict; use IkiWiki; use POSIX qw(setlocale LC_CTYPE); -sub import { #{{{ - if (exists $IkiWiki::config{svnpath}) { +hook(type => "checkconfig", id => "svn", call => sub { #{{{ + if (! defined $config{diffurl}) { + $config{diffurl}=""; + } + 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/^\///; } -} #}}} - - -package IkiWiki; + if (length $config{svn_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{svn_wrapper}, + wrappermode => (defined $config{svn_wrappermode} ? $config{svn_wrappermode} : "04755"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "svn", call => sub { #{{{ + 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() { diff --git a/IkiWiki/Rcs/tla.pm b/IkiWiki/Rcs/tla.pm index 4232e1fe8..e1389a346 100644 --- a/IkiWiki/Rcs/tla.pm +++ b/IkiWiki/Rcs/tla.pm @@ -6,6 +6,50 @@ use warnings; use strict; use IkiWiki; +hook(type => "checkconfig", id => "tla", call => sub { #{{{ + if (! defined $config{diffurl}) { + $config{diffurl}=""; + } + if (length $config{tla_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{tla_wrapper}, + wrappermode => (defined $config{tla_wrappermode} ? $config{tla_wrappermode} : "06755"), + }; + } +}); #}}} + +hook(type => "getsetup", id => "tla", call => sub { #{{{ + 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"); diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 90058199c..cb92d1ade 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -68,7 +68,7 @@ sub genpage ($$) { #{{{ $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); diff --git a/IkiWiki/Setup.pm b/IkiWiki/Setup.pm index 3b7a11253..38b715202 100644 --- a/IkiWiki/Setup.pm +++ b/IkiWiki/Setup.pm @@ -1,20 +1,18 @@ #!/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}; +# 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. our $raw_setup; sub load ($) { # {{{ @@ -34,54 +32,33 @@ sub load ($) { # {{{ eval $code; error("$setup: ".$@) if $@; - my $ret=$raw_setup; + my %setup=%{$raw_setup}; $raw_setup=undef; - return %$ret; -} #}}} - -package IkiWiki; - -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}); } } } @@ -90,32 +67,24 @@ sub setup () { #{{{ } } - 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 diff --git a/IkiWiki/Setup/Standard.pm b/IkiWiki/Setup/Standard.pm index f67c3829b..d96964a23 100644 --- a/IkiWiki/Setup/Standard.pm +++ b/IkiWiki/Setup/Standard.pm @@ -7,9 +7,118 @@ package IkiWiki::Setup::Standard; use warnings; use strict; +use IkiWiki; -sub import { +sub import { #{{{ $IkiWiki::Setup::raw_setup=$_[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}, "#"); + } + } + return @ret; +} #}}} + +sub gendump ($) { #{{{ + my $description=shift; + my %setup=(%config); + my @ret; + + push @ret, "\t# basic setup"; + push @ret, dumpvalues(\%setup, IkiWiki::getsetup()); + + # Load all plugins, so that all setup options are available. + my @plugins=grep { ! /externaldemo|pythondemo/ } sort(IkiWiki::listplugins()); + foreach my $plugin (@plugins) { + eval { IkiWiki::loadplugin($plugin) }; + if (exists $IkiWiki::hooks{checkconfig}{$plugin}{call}) { + my @s=eval { $IkiWiki::hooks{checkconfig}{$plugin}{call}->() }; + } + } + unshift @plugins, $config{rcs} if $config{rcs}; + + foreach my $id (@plugins) { + my $title="\t# $id".($id ne $config{rcs} ? " plugin" : ""); + 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, "", $title; + 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 |