Merge branch 'master' of ssh://git.ikiwiki.info/srv/git/ikiwiki.info
authorJoey Hess <joey@kodama.kitenet.net>
Sun, 3 Aug 2008 18:23:38 +0000 (14:23 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Sun, 3 Aug 2008 18:23:38 +0000 (14:23 -0400)
13 files changed:
IkiWiki.pm
IkiWiki/Plugin/bzr.pm
IkiWiki/Plugin/git.pm
IkiWiki/Plugin/mercurial.pm
IkiWiki/Plugin/monotone.pm
IkiWiki/Plugin/svn.pm
IkiWiki/Plugin/tla.pm
IkiWiki/Plugin/websetup.pm
IkiWiki/Setup.pm
IkiWiki/Setup/Standard.pm
doc/plugins/websetup.mdwn [new file with mode: 0644]
doc/setup.mdwn
websetup.pm [new symlink]

index 241a7c036f41f73ebd5e7374f2b00afd9344464e..51e683bb48af411b9430681c5e3041873a63fb0f 100644 (file)
@@ -92,7 +92,7 @@ sub getsetup () { #{{{
                type => "string",
                default => '',
                example => "/var/www/wiki/ikiwiki.cgi",
-               description => "cgi executable to generate",
+               description => "cgi wrapper to generate",
                safe => 0, # file
                rebuild => 0,
        },
@@ -288,7 +288,7 @@ sub getsetup () { #{{{
        banned_users => {
                type => "string",
                default => [],
-               description => "users who cannot use the wiki",
+               description => "users who are banned from the wiki",
                safe => 1,
                rebuild => 0,
        },
index 99025a973db235605cf64448e9ccdd04e1fc687b..0b50592924915b0040fa530095fd575985da08ea 100644 (file)
@@ -36,7 +36,7 @@ sub getsetup () { #{{{
                bzr_wrapper => {
                        type => "string",
                        #example => "", # FIXME add example
-                       description => "bzr post-commit executable to generate",
+                       description => "bzr post-commit hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index d1c1165e03c25528d1cb10d4f03e54ed890c547b..b6ad43167eff6d77c3d06f5c8c0e5c548005b7b0 100644 (file)
@@ -45,7 +45,7 @@ sub getsetup () { #{{{
                git_wrapper => {
                        type => "string",
                        example => "/git/wiki.git/hooks/post-update",
-                       description => "git post-update executable to generate",
+                       description => "git post-update hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index d2c34fa6a5810c43ac999fb23184a08dab1abc76..23bebaaadfd5e09798718523f24d61b6fa1f79f6 100644 (file)
@@ -36,7 +36,7 @@ sub getsetup () { #{{{
                mercurial_wrapper => {
                        type => "string",
                        #example => # FIXME add example
-                       description => "mercurial post-commit executable to generate",
+                       description => "mercurial post-commit hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index 4b9be316a4e602f5aaa075c8c62f2e8ade8e3ed2..bdc6ee786e18bad7e4d9b2662df5938ebe2b7131 100644 (file)
@@ -68,7 +68,7 @@ sub getsetup () { #{{{
                mtn_wrapper => {
                        type => "string",
                        example => "/srv/mtn/wiki/_MTN/ikiwiki-netsync-hook",
-                       description => "monotone netsync hook executable to generate",
+                       description => "monotone netsync hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index 51683704c5928d6e5577a3e1f92b62adbb41849f..c51b0f1811a0e528ae962686cb68daff2e92922f 100644 (file)
@@ -58,7 +58,7 @@ sub getsetup () { #{{{
                svn_wrapper => {
                        type => "string",
                        example => "/svn/wikirepo/hooks/post-commit",
-                       description => "svn post-commit executable to generate",
+                       description => "svn post-commit hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index 6faaecccc5d7a48a1f44e3fd40aa6376c8d8cf48..1c2763359c35766b8cd42dfb323fbb13ee6e0e11 100644 (file)
@@ -34,7 +34,7 @@ sub getsetup () { #{{{
                tla_wrapper => {
                        type => "string",
                        #example => "", # TODO example
-                       description => "tla post-commit executable to generate",
+                       description => "tla post-commit hook to generate",
                        safe => 0, # file
                        rebuild => 0,
                },
index 2b9240a29dd50269cc08b9a6b985fbe9a016fc8a..c22516eec5a19463b9fb2673896f1f093d7a7be6 100644 (file)
@@ -9,11 +9,11 @@ my @rcs_plugins=(qw{git svn bzr mercurial monotone tla norcs});
 
 # amazon_s3 is not something that should be enabled via the web.
 # external is not a standalone plugin.
-my @default_force_plugins=(qw{amazon_s3 external});
+my @force_plugins=(qw{amazon_s3 external});
 
 sub import { #{{{
-       hook(type => "checkconfig", id => "websetup", call => \&checkconfig);
        hook(type => "getsetup", id => "websetup", call => \&getsetup);
+       hook(type => "checkconfig", id => "websetup", call => \&checkconfig);
        hook(type => "sessioncgi", id => "websetup", call => \&sessioncgi);
        hook(type => "formbuilder_setup", id => "websetup", 
             call => \&formbuilder_setup);
@@ -23,23 +23,34 @@ sub getsetup () { #{{{
        return
                websetup_force_plugins => {
                        type => "string",
-                       example => \@default_force_plugins,
+                       example => [],
                        description => "list of plugins that cannot be enabled/disabled via the web interface",
                        safe => 0,
                        rebuild => 0,
                },
+               websetup_show_unsafe => {
+                       type => "boolean",
+                       example => 1,
+                       description => "show unsafe settings, read-only, in web interface?",
+                       safe => 0,
+                       rebuild => 0,
+               },
 } #}}}
 
 sub checkconfig () { #{{{
-       if (! exists $config{websetup_force_plugins}) {
-               $config{websetup_force_plugins}=\@default_force_plugins;
+       if (! exists $config{websetup_show_unsafe}) {
+               $config{websetup_show_unsafe}=1;
        }
 } #}}}
 
-sub formatexample ($) { #{{{
+sub formatexample ($$) { #{{{
        my $example=shift;
+       my $value=shift;
 
-       if (defined $example && ! ref $example && length $example) {
+       if (defined $value && length $value) {
+               return "";
+       }
+       elsif (defined $example && ! ref $example && length $example) {
                return "<br/ ><small>Example: <tt>$example</tt></small>";
        }
        else {
@@ -57,23 +68,31 @@ sub showfields ($$$@) { #{{{
                my $key=shift;
                my %info=%{shift()};
 
-               # skip complex, unsafe, or internal settings
-               next if ref $config{$key} || ! $info{safe} || $info{type} eq "internal";
+               # skip internal settings
+               next if $info{type} eq "internal";
+               # XXX hashes not handled yet
+               next if ref $config{$key} && ref $config{$key} eq 'HASH' || ref $info{example} eq 'HASH';
+               # maybe skip unsafe settings
+               next if ! $info{safe} && ! $config{websetup_show_unsafe};
                # these are handled specially, so don't show
                next if $key eq 'add_plugins' || $key eq 'disable_plugins';
                
                push @show, $key, \%info;
        }
 
-       return unless @show;
+       return unless @show;
 
        my $section=defined $plugin ? $plugin." ".gettext("plugin") : gettext("main");
 
+       my %shownfields;
        if (defined $plugin) {
-               if (! showplugintoggle($form, $plugin, $enabled, $section) && ! $enabled) {
+               if (showplugintoggle($form, $plugin, $enabled, $section)) {
+                       $shownfields{"enable.$plugin"}=[$plugin];
+               }
+               elsif (! $enabled) {
                    # plugin not enabled and cannot be, so skip showing
                    # its configuration
-                   return 0;
+                   return;
                }
        }
 
@@ -85,12 +104,23 @@ sub showfields ($$$@) { #{{{
                my $value=$config{$key};
                # multiple plugins can have the same field
                my $name=defined $plugin ? $plugin.".".$key : $key;
-               
-               if ($info{type} eq "string") {
+
+               if (ref $config{$key} eq 'ARRAY' || ref $info{example} eq 'ARRAY') {
+                       $form->field(
+                               name => $name,
+                               label => $description,
+                               comment => formatexample($info{example}, $value),
+                               type => "text",
+                               value => [ref $value eq 'ARRAY' ? @{$value} : "", , "", ""],
+                               size => 60,
+                               fieldset => $section,
+                       );
+               }
+               elsif ($info{type} eq "string") {
                        $form->field(
                                name => $name,
                                label => $description,
-                               comment => defined $value && length $value ? "" : formatexample($info{example}),
+                               comment => formatexample($info{example}, $value),
                                type => "text",
                                value => $value,
                                size => 60,
@@ -101,7 +131,7 @@ sub showfields ($$$@) { #{{{
                        $form->field(
                                name => $name,
                                label => $description,
-                               comment => formatexample($info{example}),
+                               comment => formatexample($info{example}, $value),
                                type => "text",
                                value => $value,
                                size => 60,
@@ -113,6 +143,7 @@ sub showfields ($$$@) { #{{{
                        $form->field(
                                name => $name,
                                label => $description,
+                               comment => formatexample($info{example}, $value),
                                type => "text",
                                value => $value,
                                size => 5,
@@ -130,9 +161,17 @@ sub showfields ($$$@) { #{{{
                                fieldset => $section,
                        );
                }
+               
+               if (! $info{safe}) {
+                       $form->field(name => $name, disabled => 1);
+                       $form->text(gettext("Note: Disabled options cannot be configured here, but only by editing the setup file."));
+               }
+               else {
+                       $shownfields{$name}=[$key, \%info];
+               }
        }
 
-       return 1;
+       return %shownfields;
 } #}}}
 
 sub showplugintoggle ($$$$) { #{{{
@@ -141,7 +180,13 @@ sub showplugintoggle ($$$$) { #{{{
        my $enabled=shift;
        my $section=shift;
 
-       return 0 if (grep { $_ eq $plugin } @{$config{websetup_force_plugins}}, @rcs_plugins);
+       if (exists $config{websetup_force_plugins} &&
+           grep { $_ eq $plugin } @{$config{websetup_force_plugins}}) {
+               return 0;
+       }
+       if (grep { $_ eq $plugin } @force_plugins, @rcs_plugins) {
+               return 0;
+       }
 
        $form->field(
                name => "enable.$plugin",
@@ -191,7 +236,7 @@ sub showform ($$) { #{{{
 
        $form->field(name => "do", type => "hidden", value => "setup",
                force => 1);
-       showfields($form, undef, undef, IkiWiki::getsetup());
+       my %fields=showfields($form, undef, undef, IkiWiki::getsetup());
        
        # record all currently enabled plugins before all are loaded
        my %enabled_plugins=%IkiWiki::loaded_plugins;
@@ -206,21 +251,84 @@ sub showform ($$) { #{{{
                # skip all rcs plugins except for the one in use
                next if $plugin ne $config{rcs} && grep { $_ eq $plugin } @rcs_plugins;
 
-               delete $plugins{$plugin} if showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
+               my %shown=showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
+               if (%shown) {
+                       delete $plugins{$plugin};
+                       $fields{$_}=$shown{$_} foreach keys %shown;
+               }
        }
 
        # list all remaining plugins (with no setup options) at the end
-       showplugintoggle($form, $_, $enabled_plugins{$_}, gettext("other plugins"))
-               foreach sort keys %plugins;
+       foreach (sort keys %plugins) {
+               if (showplugintoggle($form, $_, $enabled_plugins{$_}, gettext("other plugins"))) {
+                       $fields{"enable.$_"}=[$_];
+               }
+       }
        
        if ($form->submitted eq "Cancel") {
                IkiWiki::redirect($cgi, $config{url});
                return;
        }
-       elsif ($form->submitted eq 'Save Setup' && $form->validate) {
-               # TODO
+       elsif (($form->submitted eq 'Save Setup' || $form->submitted eq 'Rebuild Wiki') && $form->validate) {
+               my %rebuild;
+               foreach my $field (keys %fields) {
+                       if ($field=~/^enable\./) {
+                               # rebuild is overkill for many plugins,
+                               # but no good way to tell which
+                               $rebuild{$field}=1; # TODO only if state changed tho
+                               # TODO plugin enable/disable
+                               next;
+                       }
+                       
+                       my %info=%{$fields{$field}->[1]};
+                       my $key=$fields{$field}->[0];
+                       my @value=$form->field($field);
+                       
+                       if (! $info{safe}) {
+                               error("unsafe field $key"); # should never happen
+                       }
+
+                       next unless @value;
+                       # Avoid setting fields to empty strings,
+                       # if they were not set before.
+                       next if ! defined $config{$key} && ! grep { length $_ } @value;
+
+                       if (ref $config{$key} eq "ARRAY" || ref $info{example} eq "ARRAY") {
+                               if ($info{rebuild} && (! defined $config{$key} || (@{$config{$key}}) != (@value))) {
+                                       $rebuild{$field}=1;
+                               }
+                               $config{$key}=\@value;
+                       }
+                       elsif (ref $config{$key} || ref $info{example}) {
+                               error("complex field $key"); # should never happen
+                       }
+                       else {
+                               if ($info{rebuild} && (! defined $config{$key} || $config{$key} ne $value[0])) {
+                                       $rebuild{$field}=1;
+                               }
+                               $config{$key}=$value[0];
+                       }               
+               }
 
-               $form->text(gettext("Setup saved."));
+               if (%rebuild && $form->submitted eq 'Save Setup') {
+                       $form->text(gettext("The configuration changes shown below require a wiki rebuild to take effect."));
+                       foreach my $field ($form->field) {
+                               next if $rebuild{$field};
+                               $form->field(name => $field, type => "hidden",
+                                       force => 1);
+                       }
+                       $form->reset(0); # doesn't really make sense here
+                       $buttons=["Rebuild Wiki", "Cancel"];
+               }
+               else {
+                       # TODO save to real path
+                       IkiWiki::Setup::dump("/tmp/s");
+                       $form->text(gettext("Setup saved."));
+
+                       if (%rebuild) {
+                               # TODO rebuild
+                       }
+               }
        }
 
        IkiWiki::showform($form, $buttons, $session, $cgi);
index d14be879d5f1aab1f432d46bd42f9d824e95c14a..02a462082cc476530d16c9d6477122727f713bf6 100644 (file)
@@ -76,6 +76,10 @@ sub getsetup () { #{{{
        # [plugin, setup] pairs.
        my @ret;
 
+        # disable logging to syslog while dumping, broken plugins may whine when loaded
+       my $syslog=$config{syslog};
+        $config{syslog}=0;
+
        # Load all plugins, so that all setup options are available.
        my @plugins=grep { $_ ne $config{rcs} } sort(IkiWiki::listplugins());
        unshift @plugins, $config{rcs} if $config{rcs}; # rcs plugin 1st
@@ -94,6 +98,8 @@ sub getsetup () { #{{{
                        push @ret, [ $plugin, \@s ],
                }
        }
+       
+        $config{syslog}=$syslog;
 
        return @ret;
 } #}}}
index 0e640f8ac85b4b1ae9b21df12b9a574090785f94..dd613fd035d3fc57267497e9840deecad59bebc0 100644 (file)
@@ -28,7 +28,7 @@ sub dumpline ($$$$) { #{{{
        local $Data::Dumper::Quotekeys=0;
        
        my $dumpedvalue;
-       if ($type eq 'boolean' || $type eq 'integer') {
+       if (($type eq 'boolean' || $type eq 'integer') && $value=~/^[0-9]+$/) {
                # avoid quotes
                $dumpedvalue=$value;
        }
diff --git a/doc/plugins/websetup.mdwn b/doc/plugins/websetup.mdwn
new file mode 100644 (file)
index 0000000..1e4ed4d
--- /dev/null
@@ -0,0 +1,19 @@
+[[!template id=plugin name=websetup core=0 author="[[Joey]]"]]
+[[!tag type/useful]]
+
+This plugin allows wiki admins to configure the wiki using a web interface,
+rather than editing the setup file directly. A "Wiki Setup" button is added to the
+admins' preferences page.
+
+Most settings can be modified using the web interface. Some settings are
+not considered safe enough to be manipulated over the web; these are still
+shown, by default, but cannot be modified. To hide them, set `websetup_show_unsafe` 
+to false in the setup file. A few settings have too complex a data type
+to be configured via the web.
+
+The web interface can also be used to enable and disable plugins, with
+limitations. The plugin for the [[revision_control_system|rcs]] being used
+cannot be enabled/disabled, and no other rcs plugins can be enabled. A few
+problematic/unsafe plugins are also blacklisted from being enabled. Other
+plugins that should not be enabled/disabled via the web interface can be
+listed in `websetup_force_plugins` in the setup file.
index 2989485f9af926d6c91688a91e6612dec214dc97..2d39421242cb3d8c7df9316bfc2b682fc4e675d4 100644 (file)
@@ -9,8 +9,9 @@ If you're not, see the [[download]] and [[install]] pages.
 
 ## Quick start
 
-If you'd like to set up a wiki now, and learn more later, just run this command
-and answer a couple of questions.
+If you'd like to set up a wiki now, and learn more later, and you have
+ikiwiki 2.60 or better installed, just run this command and answer a couple
+of questions.
 
        % ikiwiki -setup /etc/ikiwiki/auto.setup
        What will the wiki be named? mywiki
diff --git a/websetup.pm b/websetup.pm
new file mode 120000 (symlink)
index 0000000..8ca7a8a
--- /dev/null
@@ -0,0 +1 @@
+/home/joey/src/ikiwiki/IkiWiki/Plugin/websetup.pm
\ No newline at end of file