From 9e0cbb73fe550d05e668d3584ef6f7981e781c8e Mon Sep 17 00:00:00 2001
From: Joey Hess <joey@kodama.kitenet.net>
Date: Sun, 3 Aug 2008 16:23:41 -0400
Subject: [PATCH 1/1] plugin safe/rebuild controls

---
 IkiWiki/Plugin/websetup.pm | 95 +++++++++++++++-----------------------
 IkiWiki/Setup.pm           |  7 +--
 IkiWiki/Setup/Standard.pm  |  2 +-
 doc/plugins/websetup.mdwn  | 21 ++++-----
 doc/plugins/write.mdwn     | 19 ++++++--
 5 files changed, 67 insertions(+), 77 deletions(-)

diff --git a/IkiWiki/Plugin/websetup.pm b/IkiWiki/Plugin/websetup.pm
index 061ce0873..aed2ddf64 100644
--- a/IkiWiki/Plugin/websetup.pm
+++ b/IkiWiki/Plugin/websetup.pm
@@ -5,12 +5,6 @@ use warnings;
 use strict;
 use IkiWiki 2.00;
 
-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 @force_plugins=(qw{amazon_s3 external});
-
 sub import { #{{{
 	hook(type => "getsetup", id => "websetup", call => \&getsetup);
 	hook(type => "checkconfig", id => "websetup", call => \&checkconfig);
@@ -64,12 +58,13 @@ sub showfields ($$$@) { #{{{
 	my $enabled=shift;
 
 	my @show;
+	my %plugininfo;
 	while (@_) {
 		my $key=shift;
 		my %info=%{shift()};
 
 		# skip internal settings
-		next if $info{type} eq "internal";
+		next if defined $info{type} && $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
@@ -78,26 +73,26 @@ sub showfields ($$$@) { #{{{
 		next if $info{advanced} && ! $config{websetup_advanced};
 		# these are handled specially, so don't show
 		next if $key eq 'add_plugins' || $key eq 'disable_plugins';
+
+		if ($key eq 'plugin') {
+			%plugininfo=%info;
+			next;
+		}
 		
 		push @show, $key, \%info;
 	}
 
-	return unless @show;
-
-	my $section=defined $plugin ? $plugin." ".gettext("plugin") : gettext("main");
-
-	my %shownfields;
-	if (defined $plugin) {
-		if (showplugintoggle($form, $plugin, $enabled, $section)) {
-			$shownfields{"enable.$plugin"}=[$plugin];
-		}
-		elsif (! $enabled) {
-		    # plugin not enabled and cannot be, so skip showing
-		    # its configuration
-		    return;
-		}
+	my $plugin_forced=defined $plugin && (! $plugininfo{safe} ||
+		(exists $config{websetup_force_plugins} && grep { $_ eq $plugin } @{$config{websetup_force_plugins}}));
+	if ($plugin_forced && ! $enabled) {
+		# plugin is disabled and cannot be turned on,
+		# so skip its configuration
+		return;
 	}
 
+	my %shownfields;
+	my $section=defined $plugin ? $plugin." ".gettext("plugin") : "main";
+	
 	while (@show) {
 		my $key=shift @show;
 		my %info=%{shift @show};
@@ -169,40 +164,32 @@ sub showfields ($$$@) { #{{{
 		
 		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 %shownfields;
-} #}}}
-
-sub showplugintoggle ($$$$) { #{{{
-	my $form=shift;
-	my $plugin=shift;
-	my $enabled=shift;
-	my $section=shift;
-
-	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;
+	if (defined $plugin && (! $plugin_forced || $config{websetup_advanced})) {
+		my $name="enable.$plugin";
+		$section="plugins" unless %shownfields;
+		$form->field(
+			name => $name,
+			label => "",
+			type => "checkbox",
+			options => [ [ 1 => sprintf(gettext("enable %s?"), $plugin) ] ],
+			value => $enabled,
+			fieldset => $section,
+		);
+		if ($plugin_forced) {
+			$form->field(name => $name, disabled => 1);
+		}
+		else {
+			$shownfields{$name}=[$name, \%plugininfo];
+		}
 	}
 
-	$form->field(
-		name => "enable.$plugin",
-		label => "",
-		type => "checkbox",
-		options => [ [ 1 => sprintf(gettext("enable %s?"), $plugin) ] ],
-		value => $enabled,
-		fieldset => $section,
-	);
-
-	return 1;
+	return %shownfields;
 } #}}}
 
 sub showform ($$) { #{{{
@@ -226,6 +213,10 @@ sub showform ($$) { #{{{
 		javascript => 0,
 		reset => 1,
 		params => $cgi,
+		fieldsets => [
+			[main => gettext("main")], 
+			[plugins => gettext("plugins")]
+		],
 		action => $config{cgiurl},
 		template => {type => 'div'},
 		stylesheet => IkiWiki::baseurl()."style.css",
@@ -271,9 +262,6 @@ sub showform ($$) { #{{{
 	foreach my $pair (IkiWiki::Setup::getsetup()) {
 		my $plugin=$pair->[0];
 		my $setup=$pair->[1];
-		
-		# skip all rcs plugins except for the one in use
-		next if $plugin ne $config{rcs} && grep { $_ eq $plugin } @rcs_plugins;
 
 		my %shown=showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
 		if (%shown) {
@@ -281,13 +269,6 @@ sub showform ($$) { #{{{
 			$fields{$_}=$shown{$_} foreach keys %shown;
 		}
 	}
-
-	# list all remaining plugins (with no setup options) at the end
-	foreach (sort keys %plugins) {
-		if (showplugintoggle($form, $_, $enabled_plugins{$_}, gettext("other plugins"))) {
-			$fields{"enable.$_"}=[$_];
-		}
-	}
 	
 	if ($form->submitted eq "Cancel") {
 		IkiWiki::redirect($cgi, $config{url});
diff --git a/IkiWiki/Setup.pm b/IkiWiki/Setup.pm
index 02a462082..d2d1e4b8e 100644
--- a/IkiWiki/Setup.pm
+++ b/IkiWiki/Setup.pm
@@ -72,11 +72,12 @@ sub merge ($) {
 } #}}}
 
 sub getsetup () { #{{{
-	# Gets all available setup data from all plugins. Returns an ordered list of
-	# [plugin, setup] pairs.
+	# Gets all available setup data from all plugins. Returns an
+	# ordered list of [plugin, setup] pairs.
 	my @ret;
 
-        # disable logging to syslog while dumping, broken plugins may whine when loaded
+        # disable logging to syslog while dumping, broken plugins may
+	# whine when loaded
 	my $syslog=$config{syslog};
         $config{syslog}=0;
 
diff --git a/IkiWiki/Setup/Standard.pm b/IkiWiki/Setup/Standard.pm
index dd613fd03..c87fb80f5 100644
--- a/IkiWiki/Setup/Standard.pm
+++ b/IkiWiki/Setup/Standard.pm
@@ -62,7 +62,7 @@ sub dumpvalues ($@) { #{{{
 		my $key=shift;
 		my %info=%{shift()};
 
-		next if $info{type} eq "internal";
+		next if $info{type} eq "internal" || $key eq "plugin";
 		
 		push @ret, "\t# ".$info{description} if exists $info{description};
 		
diff --git a/doc/plugins/websetup.mdwn b/doc/plugins/websetup.mdwn
index 1e4ed4d0c..11cc6ad1e 100644
--- a/doc/plugins/websetup.mdwn
+++ b/doc/plugins/websetup.mdwn
@@ -2,18 +2,15 @@
 [[!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.
+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.
+Most settings can be modified using the web interface. Plugins can be
+enabled and disabled using it too. 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
+Plugins that should not be enabled/disabled via the web interface can be
 listed in `websetup_force_plugins` in the setup file.
diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn
index fc4b778db..67f1cf2ba 100644
--- a/doc/plugins/write.mdwn
+++ b/doc/plugins/write.mdwn
@@ -379,12 +379,13 @@ die if not, which will cause the plugin to not be offered in the configuration
 interface.
 
 The data returned is a list of `%config` options, followed by a hash
-describing the option. For example:
+describing the option. There can also be an item named "plugin", which
+describes the plugin as a whole. For example:
 
                 return
 			option_foo => {
 				type => "boolean",
-				description => "enable foo",
+				description => "enable foo?",
 				advanced => 1,
 				safe => 1,
 				rebuild => 1,
@@ -392,10 +393,15 @@ describing the option. For example:
 			option_bar => {
 				type => "string",
 				example => "hello",
-				description => "what to say",
+				description => "option bar",
 				safe => 1,
 				rebuild => 0,
 			},
+			plugin => {
+				description => "description of this plugin",
+				safe => 1,
+				rebuild => 1,
+			},
 
 * `type` can be "boolean", "string", "integer", "pagespec",
   or "internal" (used for values that are not user-visible). The type is
@@ -410,7 +416,12 @@ describing the option. For example:
 * `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.
+  If a plugin is marked as unsafe, that prevents it from being
+  enabled/disabled.
+* `rebuild` should be true if changing the option (or enabling/disabling
+  the plugin) will require a wiki rebuild, false if no rebuild is needed,
+  and undef if a rebuild could be needed in some circumstances, but is not
+  strictly required.
 
 ## Plugin interface
 
-- 
2.39.5