X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/246db0f234f16f57d28a8639be36f7e5dfc598ad..7a2a235fa45d84e4a5f3f6bb3b5059d08939cddc:/IkiWiki.pm?ds=inline

diff --git a/IkiWiki.pm b/IkiWiki.pm
index 063cef8e0..0746ef24b 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -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 () { #{{{
@@ -130,16 +414,13 @@ sub checkconfig () { #{{{
 		unless exists $config{wikistatedir};
 	
 	if ($config{rcs}) {
-		eval qq{use IkiWiki::Rcs::$config{rcs}};
-		if ($@) {
-			error("Failed to load RCS module IkiWiki::Rcs::$config{rcs}: $@");
-		}
+		loadplugin($config{rcs});
 	}
 	else {
-		require IkiWiki::Rcs::Stub;
+		loadplugin("norcs");
 	}
 
-	if (exists $config{umask}) {
+	if (defined $config{umask}) {
 		umask(possibly_foolish_untaint($config{umask}));
 	}
 
@@ -148,12 +429,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) {
@@ -538,17 +839,18 @@ sub beautify_urlpath ($) { #{{{
 
 	# Ensure url is not an empty link, and
 	# if it's relative, make that explicit to avoid colon confusion.
-	if ($url !~ /\//) {
+	if ($url !~ /^\//) {
 		$url="./$url";
 	}
 
 	return $url;
 } #}}}
 
-sub urlto ($$) { #{{{
+sub urlto ($$;$) { #{{{
 	my $to=shift;
 	my $from=shift;
-
+	my $absolute=shift;
+	
 	if (! length $to) {
 		return beautify_urlpath(baseurl($from)."index.$config{htmlext}");
 	}
@@ -557,6 +859,10 @@ sub urlto ($$) { #{{{
 		$to=htmlpage($to);
 	}
 
+	if ($absolute) {
+		return $config{url}.beautify_urlpath("/".$to);
+	}
+
 	my $link = abs2rel($to, dirname(htmlpage($from)));
 
 	return beautify_urlpath($link);
@@ -759,13 +1065,10 @@ sub preprocess ($$$;$$) { #{{{
 			if ($preprocessing{$page}++ > 3) {
 				# Avoid loops of preprocessed pages preprocessing
 				# other pages that preprocess them, etc.
-				#translators: The first parameter is a
-				#translators: preprocessor directive name,
-				#translators: the second a page name, the
-				#translators: third a number.
-				return "[[".sprintf(gettext("%s preprocessing loop detected on %s at depth %i"),
-					$command, $page, $preprocessing{$page}).
-				"]]";
+				return "[[!$command <span class=\"error\">".
+					sprintf(gettext("preprocessing loop detected on %s at depth %i"),
+						$page, $preprocessing{$page}).
+					"</span>]]";
 			}
 			my $ret;
 			if (! $scan) {
@@ -1122,6 +1425,46 @@ sub run_hooks ($$) { # {{{
 	return 1;
 } #}}}
 
+sub rcs_update () { #{{{
+	$hooks{rcs}{rcs_update}{call}->(@_);
+} #}}}
+
+sub rcs_prepedit ($) { #{{{
+	$hooks{rcs}{rcs_prepedit}{call}->(@_);
+} #}}}
+
+sub rcs_commit ($$$;$$) { #{{{
+	$hooks{rcs}{rcs_commit}{call}->(@_);
+} #}}}
+
+sub rcs_commit_staged ($$$) { #{{{
+	$hooks{rcs}{rcs_commit_staged}{call}->(@_);
+} #}}}
+
+sub rcs_add ($) { #{{{
+	$hooks{rcs}{rcs_add}{call}->(@_);
+} #}}}
+
+sub rcs_remove ($) { #{{{
+	$hooks{rcs}{rcs_remove}{call}->(@_);
+} #}}}
+
+sub rcs_rename ($$) { #{{{
+	$hooks{rcs}{rcs_rename}{call}->(@_);
+} #}}}
+
+sub rcs_recentchanges ($) { #{{{
+	$hooks{rcs}{rcs_recentchanges}{call}->(@_);
+} #}}}
+
+sub rcs_diff ($) { #{{{
+	$hooks{rcs}{rcs_diff}{call}->(@_);
+} #}}}
+
+sub rcs_getctime ($) { #{{{
+	$hooks{rcs}{rcs_getctime}{call}->(@_);
+} #}}}
+
 sub globlist_to_pagespec ($) { #{{{
 	my @globlist=split(' ', shift);