ikiwiki/IkiWiki/Plugin/autoindex.pm

139 lines
3.3 KiB
Perl
Raw Normal View History

2008-07-29 21:39:01 +02:00
#!/usr/bin/perl
package IkiWiki::Plugin::autoindex;
use warnings;
use strict;
use IkiWiki 3.00;
2008-07-29 21:39:01 +02:00
use Encode;
sub import {
hook(type => "checkconfig", id => "autoindex", call => \&checkconfig);
hook(type => "getsetup", id => "autoindex", call => \&getsetup);
2008-07-29 21:39:01 +02:00
hook(type => "refresh", id => "autoindex", call => \&refresh);
IkiWiki::loadplugin("transient");
}
2008-07-29 21:39:01 +02:00
sub getsetup () {
return
plugin => {
safe => 1,
rebuild => 0,
},
autoindex_commit => {
type => "boolean",
example => 1,
default => 1,
description => "commit autocreated index pages",
safe => 1,
rebuild => 0,
},
}
sub checkconfig () {
if (! defined $config{autoindex_commit}) {
$config{autoindex_commit} = 1;
}
}
sub genindex ($) {
2008-07-29 21:39:01 +02:00
my $page=shift;
2008-09-30 01:08:12 +02:00
my $file=newpagefile($page, $config{default_pageext});
add_autofile($file, "autoindex", sub {
my $message = sprintf(gettext("creating index page %s"),
$page);
debug($message);
my $dir = $config{srcdir};
if (! $config{autoindex_commit}) {
$dir = $IkiWiki::Plugin::transient::transientdir;
}
my $template = template("autoindex.tmpl");
$template->param(page => $page);
writefile($file, $dir, $template->output);
if ($config{rcs} && $config{autoindex_commit}) {
IkiWiki::disable_commit_hook();
IkiWiki::rcs_add($file);
IkiWiki::rcs_commit_staged(message => $message);
IkiWiki::enable_commit_hook();
}
});
}
2008-07-29 21:39:01 +02:00
sub refresh () {
2008-07-29 21:39:01 +02:00
eval q{use File::Find};
error($@) if $@;
Fix issues with combining unicode srcdirs and source files. A short story: Once there was a unicode string, let's call him Srcdir. Along came a crufy old File::Find, who went through a tree and pasted each of the leaves in turn onto Srcdir. But this 90's relic didn't decode the leaves -- despite some of them using unicode! Poor Srcdir, with these leaves stuck on him, tainted them with his nice unicode-ness. They didn't look like leaves at all, but instead garbage. (In other words, perl's unicode support sucks mightily, and drives us all to drink and bad storytelling. But we knew that..) So, srcdir is not normally flagged as unicode, because typically it's pure ascii. And in that case, things work ok; File::Find finds filenames, which are not yet decoded to unicode, and appends them to the srcdir, and then decode_utf8 happily converts the whole thing. But, if the srcdir does contain utf8 characters, that breaks. Or, if a Yaml setup file is used, Yaml::Syck's implicitunicode sets the unicode flag of *all* strings, even those containing only ascii. In either case, srcdir has the unicode flag set; a non-decoded filename is appended, and the flag remains set; and decode_utf8 sees the flag and does *nothing*. The result is that the filename is not decoded, so looks valid and gets skipped. File::Find only sticks the directory and filenames together in no_chdir mode .. but we need that mode for security. In order to retain the security, and avoid the problem, I made it not pass srcdir to File::Find. Instead, chdir to the srcdir, and pass ".". Since "." is ascii, the problem is avoided. Note that chdir srcdir is safe because we check for symlinks in the srcdir path. Note that it takes care to chdir back to the starting location. Because the user may have specified relative paths and so staying in the srcdir might break. A relative path could even be specifed for an underlay dir, so it chdirs back after each.
2010-06-15 22:40:37 +02:00
eval q{use Cwd};
error($@) if $@;
my $origdir=getcwd();
2008-07-29 21:39:01 +02:00
my (%pages, %dirs);
foreach my $dir ($config{srcdir}, @{$config{underlaydirs}}, $config{underlaydir}) {
chdir($dir) || next;
find({
no_chdir => 1,
wanted => sub {
Fix issues with combining unicode srcdirs and source files. A short story: Once there was a unicode string, let's call him Srcdir. Along came a crufy old File::Find, who went through a tree and pasted each of the leaves in turn onto Srcdir. But this 90's relic didn't decode the leaves -- despite some of them using unicode! Poor Srcdir, with these leaves stuck on him, tainted them with his nice unicode-ness. They didn't look like leaves at all, but instead garbage. (In other words, perl's unicode support sucks mightily, and drives us all to drink and bad storytelling. But we knew that..) So, srcdir is not normally flagged as unicode, because typically it's pure ascii. And in that case, things work ok; File::Find finds filenames, which are not yet decoded to unicode, and appends them to the srcdir, and then decode_utf8 happily converts the whole thing. But, if the srcdir does contain utf8 characters, that breaks. Or, if a Yaml setup file is used, Yaml::Syck's implicitunicode sets the unicode flag of *all* strings, even those containing only ascii. In either case, srcdir has the unicode flag set; a non-decoded filename is appended, and the flag remains set; and decode_utf8 sees the flag and does *nothing*. The result is that the filename is not decoded, so looks valid and gets skipped. File::Find only sticks the directory and filenames together in no_chdir mode .. but we need that mode for security. In order to retain the security, and avoid the problem, I made it not pass srcdir to File::Find. Instead, chdir to the srcdir, and pass ".". Since "." is ascii, the problem is avoided. Note that chdir srcdir is safe because we check for symlinks in the srcdir path. Note that it takes care to chdir back to the starting location. Because the user may have specified relative paths and so staying in the srcdir might break. A relative path could even be specifed for an underlay dir, so it chdirs back after each.
2010-06-15 22:40:37 +02:00
my $file=decode_utf8($_);
$file=~s/^\.\/?//;
return unless length $file;
if (IkiWiki::file_pruned($file)) {
$File::Find::prune=1;
2008-07-29 21:39:01 +02:00
}
elsif (! -l $_) {
my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint
return unless defined $f;
return if $f =~ /\._([^.]+)$/; # skip internal page
if (! -d _) {
$pages{pagename($f)}=1;
}
elsif ($dir eq $config{srcdir} || ! $config{autoindex_commit}) {
$dirs{$f}=1;
}
2008-07-29 21:39:01 +02:00
}
}
Fix issues with combining unicode srcdirs and source files. A short story: Once there was a unicode string, let's call him Srcdir. Along came a crufy old File::Find, who went through a tree and pasted each of the leaves in turn onto Srcdir. But this 90's relic didn't decode the leaves -- despite some of them using unicode! Poor Srcdir, with these leaves stuck on him, tainted them with his nice unicode-ness. They didn't look like leaves at all, but instead garbage. (In other words, perl's unicode support sucks mightily, and drives us all to drink and bad storytelling. But we knew that..) So, srcdir is not normally flagged as unicode, because typically it's pure ascii. And in that case, things work ok; File::Find finds filenames, which are not yet decoded to unicode, and appends them to the srcdir, and then decode_utf8 happily converts the whole thing. But, if the srcdir does contain utf8 characters, that breaks. Or, if a Yaml setup file is used, Yaml::Syck's implicitunicode sets the unicode flag of *all* strings, even those containing only ascii. In either case, srcdir has the unicode flag set; a non-decoded filename is appended, and the flag remains set; and decode_utf8 sees the flag and does *nothing*. The result is that the filename is not decoded, so looks valid and gets skipped. File::Find only sticks the directory and filenames together in no_chdir mode .. but we need that mode for security. In order to retain the security, and avoid the problem, I made it not pass srcdir to File::Find. Instead, chdir to the srcdir, and pass ".". Since "." is ascii, the problem is avoided. Note that chdir srcdir is safe because we check for symlinks in the srcdir path. Note that it takes care to chdir back to the starting location. Because the user may have specified relative paths and so staying in the srcdir might break. A relative path could even be specifed for an underlay dir, so it chdirs back after each.
2010-06-15 22:40:37 +02:00
}, '.');
chdir($origdir) || die "chdir $origdir: $!";
}
# Compatibility code.
#
# {deleted} contains pages that have been deleted at some point.
# This plugin used to delete from the hash sometimes, but no longer
# does; in [[todo/autoindex_should_use_add__95__autofile]] Joey
# thought the old behaviour was probably a bug.
#
# The effect of listing a page in {deleted} was to avoid re-creating
# it; we migrate these pages to {autofile} which has the same effect.
# However, {autofile} contains source filenames whereas {deleted}
# contains page names.
my %deleted;
if (ref $wikistate{autoindex}{deleted}) {
%deleted=%{$wikistate{autoindex}{deleted}};
delete $wikistate{autoindex}{deleted};
}
elsif (ref $pagestate{index}{autoindex}{deleted}) {
# an even older version
%deleted=%{$pagestate{index}{autoindex}{deleted}};
delete $pagestate{index}{autoindex};
}
if (keys %deleted) {
foreach my $dir (keys %deleted) {
my $file=newpagefile($dir, $config{default_pageext});
$wikistate{autoindex}{autofile}{$file} = 1;
}
}
2008-07-29 21:39:01 +02:00
foreach my $dir (keys %dirs) {
if (! exists $pages{$dir} && grep /^$dir\/.*/, keys %pages) {
genindex($dir);
}
2008-07-29 21:39:01 +02:00
}
}
2008-07-29 21:39:01 +02:00
1