use open qw{:utf8 :std};
use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
- %pagestate %wikistate %renderedfiles %oldrenderedfiles
- %pagesources %destsources %depends %depends_simple %hooks
- %forcerebuild %loaded_plugins %typedlinks %oldtypedlinks};
+ %pagestate %wikistate %renderedfiles %oldrenderedfiles
+ %pagesources %destsources %depends %depends_simple %hooks
+ %forcerebuild %loaded_plugins %typedlinks %oldtypedlinks
+ %autofiles};
use Exporter q{import};
our @EXPORT = qw(hook debug error template htmlpage deptype
- add_depends pagespec_match pagespec_match_list bestlink
- htmllink readfile writefile pagetype srcfile pagename
- displaytime will_render gettext ngettext urlto targetpage
- add_underlay pagetitle titlepage linkpage newpagefile
- inject add_link
- %config %links %pagestate %wikistate %renderedfiles
- %pagesources %destsources %typedlinks);
+ add_depends pagespec_match pagespec_match_list bestlink
+ htmllink readfile writefile pagetype srcfile pagename
+ displaytime will_render gettext ngettext urlto targetpage
+ add_underlay pagetitle titlepage linkpage newpagefile
+ inject add_link add_autofile
+ %config %links %pagestate %wikistate %renderedfiles
+ %pagesources %destsources %typedlinks);
our $VERSION = 3.00; # plugin interface version, next is ikiwiki version
our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE
our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE
},
wiki_file_prune_regexps => {
type => "internal",
- default => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./,
+ default => [qr/(^|\/)\.\.(\/|$)/, qr/^\//, qr/^\./, qr/\/\./,
qr/\.x?html?$/, qr/\.ikiwiki-new$/,
qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
qr/(^|\/)_MTN\//, qr/(^|\/)_darcs\//,
}
my $file_prune_regexp;
- sub file_pruned ($;$) {
+ sub file_pruned ($) {
my $file=shift;
- if (@_) {
- require File::Spec;
- $file=File::Spec->canonpath($file);
- my $base=File::Spec->canonpath(shift);
- return if $file eq $base;
- $file =~ s#^\Q$base\E/+##;
- }
if (defined $config{include} && length $config{include}) {
return 0 if $file =~ m/$config{include}/;
return shift;
}
};
- *ngettext=sub {
+ *ngettext=sub {
$getobj->() if $getobj;
if ($gettext_obj) {
$gettext_obj->nget(@_);
}
}
+sub add_autofile ($$$) {
+ my $file=shift;
+ my $plugin=shift;
+ my $generator=shift;
+
+ $autofiles{$file}{plugin}=$plugin;
+ $autofiles{$file}{generator}=$generator;
+}
+
sub sortspec_translate ($$) {
my $spec = shift;
my $reverse = shift;
my @links;
foreach my $p (backlink_pages($page)) {
my $href=urlto($p, $page);
-
+
# Trim common dir prefixes from both pages.
my $p_trimmed=$p;
my $page_trimmed=$page;
}
+sub verify_src_file ($$) {
+ my $file=shift;
+ my $dir=shift;
+
+ return if -l $file || -d _;
+ $file=~s/^\Q$dir\E\/?//;
+ return if ! length $file;
+ my $page = pagename($file);
+ if (! exists $pagesources{$page} &&
+ file_pruned($file)) {
+ return;
+ }
+
+ my ($file_untainted) = $file =~ /$config{wiki_file_regexp}/; # untaint
+ if (! defined $file_untainted) {
+ warn(sprintf(gettext("skipping bad filename %s"), $file)."\n");
+ }
+ return ($file_untainted, $page);
+}
+
sub find_src_files () {
my @files;
my %pages;
find({
no_chdir => 1,
wanted => sub {
- my $file=decode_utf8($_);
- $file=~s/^\Q$config{srcdir}\E\/?//;
- return if -l $_ || -d _ || ! length $file;
- my $page = pagename($file);
- if (! exists $pagesources{$page} &&
- file_pruned($file)) {
- $File::Find::prune=1;
- return;
- }
-
- my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint
- if (! defined $f) {
- warn(sprintf(gettext("skipping bad filename %s"), $file)."\n");
- }
- else {
- push @files, $f;
+ my ($file, $page) = verify_src_file(decode_utf8($_), $config{srcdir});
+ if (defined $file) {
+ push @files, $file;
if ($pages{$page}) {
debug(sprintf(gettext("%s has multiple possible source pages"), $page));
}
$pages{$page}=1;
}
+ else {
+ $File::Find::prune=1;
+ }
},
}, $config{srcdir});
foreach my $dir (@{$config{underlaydirs}}, $config{underlaydir}) {
find({
no_chdir => 1,
wanted => sub {
- my $file=decode_utf8($_);
- $file=~s/^\Q$dir\E\/?//;
- return if -l $_ || -d _ || ! length $file;
- my $page=pagename($file);
- if (! exists $pagesources{$page} &&
- file_pruned($file)) {
- $File::Find::prune=1;
- return;
- }
-
- my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint
- if (! defined $f) {
- warn(sprintf(gettext("skipping bad filename %s"), $file)."\n");
- }
- else {
+ my ($file, $page) = verify_src_file(decode_utf8($_), $dir);
+ if (defined $file) {
# avoid underlaydir override
# attacks; see security.mdwn
- if (! -l "$config{srcdir}/$f" &&
+ if (! -l "$config{srcdir}/$file" &&
! -e _) {
if (! $pages{$page}) {
- push @files, $f;
+ push @files, $file;
$pages{$page}=1;
}
}
}
+ else {
+ $File::Find::prune=1;
+ }
},
}, $dir);
};
push @internal_new, $file;
}
elsif ($config{rcs}) {
- if (! $times_noted) {
- debug(sprintf(gettext("querying %s for file creation and modification times.."), $config{rcs}));
- $times_noted=1;
- }
-
push @new, $file;
if ($config{gettime} && -e "$config{srcdir}/$file") {
+ if (! $times_noted) {
+ debug(sprintf(gettext("querying %s for file creation and modification times.."), $config{rcs}));
+ $times_noted=1;
+ }
+
eval {
my $ctime=rcs_getctime("$config{srcdir}/$file");
if ($ctime > 0) {
foreach my $file (@_) {
my $page=pagename($file);
if (! isinternal($page)) {
- debug(sprintf(gettext("removing old page %s"), $page));
+ debug(sprintf(gettext("removing obsolete %s"), $page));
}
foreach my $old (@{$oldrenderedfiles{$page}}) {
if ($type == $IkiWiki::DEPEND_LINKS) {
next unless $linkchangers->{lc($page)};
}
- return $page;
+ $reason=$page;
+ return 1;
}
}
return undef;
};
if ($depends{$p}{$dep} & $IkiWiki::DEPEND_CONTENT) {
- last if $reason =
- $in->(\@changed, $IkiWiki::DEPEND_CONTENT);
- last if $internal_dep && ($reason =
+ last if $in->(\@changed, $IkiWiki::DEPEND_CONTENT);
+ last if $internal_dep && (
$in->($internal_new, $IkiWiki::DEPEND_CONTENT) ||
$in->($internal_del, $IkiWiki::DEPEND_CONTENT) ||
- $in->($internal_changed, $IkiWiki::DEPEND_CONTENT));
+ $in->($internal_changed, $IkiWiki::DEPEND_CONTENT)
+ );
}
if ($depends{$p}{$dep} & $IkiWiki::DEPEND_PRESENCE) {
- last if $reason =
- $in->(\@exists_changed, $IkiWiki::DEPEND_PRESENCE);
- last if $internal_dep && ($reason =
+ last if $in->(\@exists_changed, $IkiWiki::DEPEND_PRESENCE);
+ last if $internal_dep && (
$in->($internal_new, $IkiWiki::DEPEND_PRESENCE) ||
- $in->($internal_del, $IkiWiki::DEPEND_PRESENCE));
+ $in->($internal_del, $IkiWiki::DEPEND_PRESENCE)
+ );
}
if ($depends{$p}{$dep} & $IkiWiki::DEPEND_LINKS) {
- last if $reason =
- $in->(\@changed, $IkiWiki::DEPEND_LINKS);
- last if $internal_dep && ($reason =
+ last if $in->(\@changed, $IkiWiki::DEPEND_LINKS);
+ last if $internal_dep && (
$in->($internal_new, $IkiWiki::DEPEND_LINKS) ||
$in->($internal_del, $IkiWiki::DEPEND_LINKS) ||
- $in->($internal_changed, $IkiWiki::DEPEND_LINKS));
+ $in->($internal_changed, $IkiWiki::DEPEND_LINKS)
+ );
}
}
}
}
}
+sub gen_autofile ($$$) {
+ my $autofile=shift;
+ my $pages=shift;
+ my $del=shift;
+
+ if (srcfile($autofile, 1)) {
+ return 0;
+ }
+
+ my ($file, $page) = verify_src_file("$config{srcdir}/$autofile", $config{srcdir});
+
+ if ((!defined $file) ||
+ (exists $wikistate{$autofiles{$autofile}{plugin}}{autofile_deleted})) {
+ return 0;
+ }
+
+ if ($pages->{$page}) {
+ return 0;
+ }
+
+ if (grep { $_ eq $file } @$del) {
+ $wikistate{$autofiles{$autofile}{generator}}{autofile_deleted}=1;
+ return 0;
+ }
+
+ $autofiles{$autofile}{generator}->();
+ $pages->{$page}=1;
+ return 1;
+}
+
+
sub refresh () {
srcdir_check();
run_hooks(refresh => sub { shift->() });
scan($file);
}
+ foreach my $autofile (keys %autofiles) {
+ if (gen_autofile($autofile, $pages, $del)) {
+ push @{$files}, $autofile;
+ push @{$new}, $autofile if find_new_files([$autofile]);
+ push @{$changed}, $autofile if find_changed([$autofile]);
+
+ scan($autofile);
+ }
+ }
+
calculate_links();
remove_del(@$del, @$internal_del);