]> sipb.mit.edu Git - ikiwiki.git/commitdiff
Merge branch 'master' into autoconfig
authorJoey Hess <joey@kodama.kitenet.net>
Sun, 27 Jul 2008 01:16:16 +0000 (21:16 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Sun, 27 Jul 2008 01:16:16 +0000 (21:16 -0400)
34 files changed:
IkiWiki.pm
IkiWiki/Plugin/aggregate.pm
IkiWiki/Plugin/amazon_s3.pm
IkiWiki/Plugin/anonok.pm
IkiWiki/Plugin/attachment.pm
IkiWiki/Plugin/calendar.pm
IkiWiki/Plugin/graphviz.pm
IkiWiki/Plugin/inline.pm
IkiWiki/Plugin/mdwn.pm
IkiWiki/Plugin/mirrorlist.pm
IkiWiki/Plugin/openid.pm
IkiWiki/Plugin/passwordauth.pm
IkiWiki/Plugin/pinger.pm
IkiWiki/Plugin/prettydate.pm
IkiWiki/Plugin/recentchanges.pm
IkiWiki/Plugin/search.pm
IkiWiki/Plugin/skeleton.pm.example
IkiWiki/Plugin/tag.pm
IkiWiki/Plugin/typography.pm
IkiWiki/Rcs/bzr.pm
IkiWiki/Rcs/git.pm
IkiWiki/Rcs/mercurial.pm
IkiWiki/Rcs/monotone.pm
IkiWiki/Rcs/svn.pm
IkiWiki/Rcs/tla.pm
IkiWiki/Render.pm
IkiWiki/Setup.pm
IkiWiki/Setup/Standard.pm
Makefile.PL
debian/changelog
doc/plugins/write.mdwn
doc/setup.mdwn
doc/usage.mdwn
ikiwiki.in

index 3f8a4bca334debb8a5728b25b258dac50c112f89..4ad19a49931bc9ea0a9018c82c1a3aad792377f3 100644 (file)
@@ -32,65 +32,349 @@ memoize("abs2rel");
 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 () { #{{{
@@ -139,7 +423,7 @@ sub checkconfig () { #{{{
                require IkiWiki::Rcs::Stub;
        }
 
-       if (exists $config{umask}) {
+       if (defined $config{umask}) {
                umask(possibly_foolish_untaint($config{umask}));
        }
 
@@ -148,12 +432,32 @@ sub checkconfig () { #{{{
        return 1;
 } #}}}
 
+sub listplugins () { #{{{
+       my %ret;
+
+       foreach my $dir (@INC, $config{libdir}) {
+               next unless defined $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;
+               foreach my $file (glob("$dir/plugins/*")) {
+                       $ret{basename($file)}=1 if -x $file;
+               }
+       }
+
+       return keys %ret;
+} #}}}
+
 sub loadplugins () { #{{{
        if (defined $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) {
index e000bc8648a39f33cea5aef932286255f343f4a2..673668c0ee02cf049740144dbe442d610a7068d2 100644 (file)
@@ -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())) {
index 187700f30d911dee95009a7d2515ef3aca61e176..e181a84da04c6c152b74397fcf5d304a46d1344c 100644 (file)
@@ -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}) {
index 1880516d568b35e2b96463676d23c04c62f103f2..7b966f845338775cb07cc317af7c1b27ca6e811c 100644 (file)
@@ -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;
index 720078be15cfcd51399f375815b4d22e1a2e8d7b..47e165251376ffa817b014fc041ae1a9cc9aa9d3 100644 (file)
@@ -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
index aed087eed58248d5da153543dba03abba17b5ef0..6f1f9bd0729d5ccc539fc83a8bd32cb58274a2c0 100644 (file)
@@ -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));
index b13d15fa6350aadd237494350dd1c8949bf72700..021aa6b230c2a61b0a2289d2bbccc4e83abe4ae6 100644 (file)
@@ -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 = (
index 2f09019431b44fd4c5ab458f44fe90026367d996..cdd0ab0dc2b7cf86ae3b5c7367bd24fe980d2462 100644 (file)
@@ -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 (@) { #{{{
index 11f3f0137627643fe285e0464b59b2e0086b3f88..332325adc814134520381b088e7524b335342921 100644 (file)
@@ -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')) {
index 3997e6fefcd31c15a8fa6df7e559a6ffdf84e863..f7c78fdee33769584278b131955b8eac28291716 100644 (file)
@@ -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};
index 10a8fa22f46aa8116f10e13a48ac01678b8ba997..de7f7280e91ce304e91dac1fa2165f5c4326be32 100644 (file)
@@ -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=@_;
 
index f3f1aa4bf2b7b5f761859d7a75a2c0d68f8b4eb7..82afeef989e517171a416749d27194a1e435b672 100644 (file)
@@ -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"));
index 614d428853c7d0d2efbaa74987edc97e6643a452..e72833b8f45353c2fc79c4008412adf813a50e20 100644 (file)
@@ -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) {
index 745e6a1de436e2db15b97ebe897858f891de2a51..db5a94f413b567de7c73f2cb93ac90e1d9697461 100644 (file)
@@ -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') {
index 8383fb72a12e19c8d92627956efc154855ff57e5..d534d0cd96f6a92416a507b34ff3d38c1ac1b7b0 100644 (file)
@@ -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};
index eedfa69244a166092b543b51e61a360b486a00f5..cb12d9500d95a31545426fd3c984e3297286d457 100644 (file)
@@ -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";
        }
 } #}}}
index 1af8e4e9df3b0903cd1341327f606fd4599afcde..49c4d88f288d024cfed3dd31b62392ea0b201fb4 100644 (file)
@@ -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");
 } #}}}
index b0a0e53be7cec3c73147ce61fe353aaa9b8a3d69..36b434f675c5d0303aa9bd4962bd7302e85afdd0 100644 (file)
@@ -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;
                        
index fe69968981029f07e0a60c2903bfb9e02fe6a4a6..6229e6c33258b9d6a12a43c8957cb5facbcb3739 100644 (file)
@@ -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);
index c80356159f6d97080063da5964bdb904f114e1e2..5df522f6ee69b4cd6bdec394fbd495957a8424d2 100644 (file)
@@ -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 = ();
index ecf560d0ba8dc09edf2c48da59eddd0cfe864143..6c9aca650ee3ab09751ef307aae2febd11a95280 100644 (file)
@@ -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).
index 8c3f03e07145a84f38e80f515b0918be26c9e382..3a98e09d8721c24030e988bdf6473a661e3cc695 100644 (file)
@@ -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");
index 500af5c587abba1816dd3144c840c54e1afad8a2..d7e8f296a69f6d80c205ebbcaa4e40f3dc49e8a3 100644 (file)
@@ -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) {
index 9081c39027b0d21e3cfb15b4e3716c7f1b0fcc3d..0e7df36595b10de27319efdd7a2ffd0c6e93ca62 100644 (file)
@@ -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&amp;r1=[[r1]]&amp;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() {
index 4232e1fe8372429902b7438f20e6c0c25189ce52..e1389a34677e5b4fa1f3ade6acc10891bd2d0d0b 100644 (file)
@@ -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");
index 90058199c128ebd68f7fa41c2e0f4d71c36e6d32..cb92d1ade947290edef6afd14636fd4d15c8ca63 100644 (file)
@@ -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);
index 3b7a112539acf794e855a6daffb192f657c49f11..38b7152029a851d0651943abd6ff772f76e6f364 100644 (file)
@@ -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
index f67c3829b71d437dc73ed7477196d9323247ece4..d96964a23b825970c61b7991334a398dfc64bcce 100644 (file)
@@ -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
index 8c7ac70190ad26eba142abe79bb3a703036dd27e..01a59eaf6b46cd73fc5013c9ec253a25369e63fc 100755 (executable)
@@ -62,7 +62,7 @@ extra_install:
        
        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
index 348d30997ef2843307211669d4ed18989021e888..205620508af01f04efbb445ef485c7473a7a3af5 100644 (file)
@@ -1,3 +1,13 @@
+ikiwiki (2.60) UNRELEASED; urgency=low
+  * 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.
+  * The way wrappers are defined in the setup file has changed. Old setup
+    files will continue to work, for now.
+ -- Joey Hess <joeyh@debian.org>  Mon, 21 Jul 2008 11:35:46 -0400
+
 ikiwiki (2.55) UNRELEASED; urgency=low
 
   * remove: New plugin that adds the ability to remove pages via the web.
index 7c28088ded55f9fce9b9012e9c31f9e72814145e..686f7e518850febee6b47acde5951027f63c1281 100644 (file)
@@ -357,6 +357,47 @@ something. The hook is passed named parameters: `page`, `oldpage`,
 `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 the plugin is not available, 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", "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:
index 174d6ceb972d8c38f17b021246244e05052a9317..9c67c2a6caccdb9c7cc0c714c498ee7318047c0d 100644 (file)
@@ -74,11 +74,16 @@ and `--rebuild` too. Get comfortable with its command line (see
 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
@@ -91,12 +96,12 @@ will set everything up.
 
 ## 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
@@ -113,7 +118,7 @@ on the revision control system you choose, the way this is done varies.
 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"]]
@@ -167,7 +172,7 @@ about using the git repositories.
        # 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
@@ -188,11 +193,11 @@ about using the git repositories.
 
 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
index 2b104bcdb5597659f08c734046ba89ddd711741c..473d1c9b10e37f467c7f66403948abeef0de9ce6 100644 (file)
@@ -62,6 +62,11 @@ These options control the mode that ikiwiki operates in.
   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
index 3bb881c4320f246b1edd4f9af80014149036d9e4..febc8ff56ed42ee876b85db2b235270961737963 100755 (executable)
@@ -20,6 +20,7 @@ sub getconfig () { #{{{
                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},
@@ -27,7 +28,7 @@ sub getconfig () { #{{{
                        "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},
@@ -45,7 +46,6 @@ sub getconfig () { #{{{
                        "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},
@@ -68,14 +68,11 @@ sub getconfig () { #{{{
                                $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) {
@@ -114,7 +111,47 @@ sub main () { #{{{
        
        if ($config{setup}) {
                require IkiWiki::Setup;
-               setup();
+               IkiWiki::Setup::load($config{setup});
+               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};
+               
+               loadplugins();
+               checkconfig();
+       }
+
+       if ($config{dumpsetup}) {
+               require IkiWiki::Setup;
+               IkiWiki::Setup::dump($config{dumpsetup});
        }
        elsif ($config{wrapper}) {
                lockwiki();
@@ -136,12 +173,19 @@ sub main () { #{{{
                # 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"));
        }
 } #}}}