Merge branch 'autotag'

master
Joey Hess 2010-04-22 00:34:03 -04:00
commit 3ee571390e
12 changed files with 215 additions and 78 deletions

View File

@ -12,19 +12,20 @@ use Storable;
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
@ -1887,7 +1888,7 @@ sub define_gettext () {
return shift;
}
};
*ngettext=sub {
*ngettext=sub {
$getobj->() if $getobj;
if ($gettext_obj) {
$gettext_obj->nget(@_);
@ -1952,6 +1953,15 @@ sub add_link ($$;$) {
}
}
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;

View File

@ -34,9 +34,16 @@ sub getsetup () {
safe => 1,
rebuild => 1,
},
tag_autocreate => {
type => "boolean",
example => 1,
description => "autocreate new tag pages?",
safe => 1,
rebuild => undef,
},
}
sub tagpage ($) {
sub taglink ($) {
my $tag=shift;
if ($tag !~ m{^/} &&
@ -48,13 +55,46 @@ sub tagpage ($) {
return $tag;
}
sub taglink ($$$;@) {
sub htmllink_tag ($$$;@) {
my $page=shift;
my $destpage=shift;
my $tag=shift;
my %opts=@_;
return htmllink($page, $destpage, tagpage($tag), %opts);
return htmllink($page, $destpage, taglink($tag), %opts);
}
sub gentag ($) {
my $tag=shift;
if ($config{tag_autocreate} ||
($config{tagbase} && ! defined $config{tag_autocreate})) {
my $tagpage=taglink($tag);
if ($tagpage=~/^\.\/(.*)/) {
$tagpage=$1;
}
else {
$tagpage=~s/^\///;
}
my $tagfile = newpagefile($tagpage, $config{default_pageext});
add_autofile($tagfile, "tag", sub {
my $message=sprintf(gettext("creating tag page %s"), $tagpage);
debug($message);
my $template=template("autotag.tmpl");
$template->param(tagname => IkiWiki::basename($tag));
$template->param(tag => $tag);
writefile($tagfile, $config{srcdir}, $template->output);
if ($config{rcs}) {
IkiWiki::disable_commit_hook();
IkiWiki::rcs_add($tagfile);
IkiWiki::rcs_commit_staged($message, undef, undef);
IkiWiki::enable_commit_hook();
}
});
}
}
sub preprocess_tag (@) {
@ -69,8 +109,11 @@ sub preprocess_tag (@) {
foreach my $tag (keys %params) {
$tag=linkpage($tag);
# hidden WikiLink
add_link($page, tagpage($tag), 'tag');
add_link($page, taglink($tag), 'tag');
gentag($tag);
}
return "";
@ -84,14 +127,16 @@ sub preprocess_taglink (@) {
return join(" ", map {
if (/(.*)\|(.*)/) {
my $tag=linkpage($2);
add_link($params{page}, tagpage($tag), 'tag');
return taglink($params{page}, $params{destpage}, $tag,
add_link($params{page}, taglink($tag), 'tag');
gentag($tag);
return htmllink_tag($params{page}, $params{destpage}, $tag,
linktext => pagetitle($1));
}
else {
my $tag=linkpage($_);
add_link($params{page}, tagpage($tag), 'tag');
return taglink($params{page}, $params{destpage}, $tag);
add_link($params{page}, taglink($tag), 'tag');
gentag($tag);
return htmllink_tag($params{page}, $params{destpage}, $tag);
}
}
grep {
@ -109,7 +154,7 @@ sub pagetemplate (@) {
$template->param(tags => [
map {
link => taglink($page, $destpage, $_, rel => "tag")
link => htmllink_tag($page, $destpage, $_, rel => "tag")
}, sort keys %$tags
]) if defined $tags && %$tags && $template->query(name => "tags");
@ -126,8 +171,8 @@ package IkiWiki::PageSpec;
sub match_tagged ($$;@) {
my $page=shift;
my $glob=shift;
return match_link($page, IkiWiki::Plugin::tag::tagpage($glob), linktype => 'tag', @_);
my $glob=IkiWiki::Plugin::tag::taglink(shift);
return match_link($page, $glob, linktype => 'tag', @_);
}
1

View File

@ -286,63 +286,54 @@ sub find_src_files () {
my %pages;
eval q{use File::Find};
error($@) if $@;
my ($page, $dir, $underlay);
my $helper=sub {
my $file=decode_utf8($_);
return if -l $file || -d _;
$file=~s/^\Q$dir\E\/?//;
return if ! length $file;
$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");
}
if ($underlay) {
# avoid underlaydir override attacks; see security.mdwn
if (! -l "$config{srcdir}/$f" && ! -e _) {
if (! $pages{$page}) {
push @files, $f;
$pages{$page}=1;
}
}
}
else {
push @files, $f;
if ($pages{$page}) {
debug(sprintf(gettext("%s has multiple possible source pages"), $page));
}
$pages{$page}=1;
}
};
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;
if ($pages{$page}) {
debug(sprintf(gettext("%s has multiple possible source pages"), $page));
}
$pages{$page}=1;
}
},
}, $config{srcdir});
foreach my $dir (@{$config{underlaydirs}}, $config{underlaydir}) {
wanted => $helper,
}, $dir=$config{srcdir});
$underlay=1;
foreach (@{$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 {
# avoid underlaydir override
# attacks; see security.mdwn
if (! -l "$config{srcdir}/$f" &&
! -e _) {
if (! $pages{$page}) {
push @files, $f;
$pages{$page}=1;
}
}
}
},
}, $dir);
wanted => $helper,
}, $dir=$_);
};
return \@files, \%pages;
}
@ -686,6 +677,49 @@ sub render_backlinks ($) {
}
}
sub gen_autofile ($$$) {
my $autofile=shift;
my $pages=shift;
my $del=shift;
if (file_pruned($autofile)) {
return;
}
my ($file)="$config{srcdir}/$autofile" =~ /$config{wiki_file_regexp}/; # untaint
if (! defined $file) {
return;
}
# Remember autofiles that were tried, and never try them again later.
if (exists $wikistate{$autofiles{$autofile}{plugin}}{autofile}{$autofile}) {
return;
}
$wikistate{$autofiles{$autofile}{plugin}}{autofile}{$autofile}=1;
if (srcfile($autofile, 1) || file_pruned($autofile)) {
return;
}
if (-l $file || -d _ || -e _) {
return;
}
my $page = pagename($file);
if ($pages->{$page}) {
return;
}
if (grep { $_ eq $autofile } @$del) {
return;
}
$autofiles{$autofile}{generator}->();
$pages->{$page}=1;
return 1;
}
sub refresh () {
srcdir_check();
run_hooks(refresh => sub { shift->() });
@ -700,6 +734,16 @@ sub refresh () {
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);

4
debian/NEWS vendored
View File

@ -11,6 +11,10 @@ ikiwiki (3.20100422) unstable; urgency=low
not regular wikilinks. If your wiki accidentially relied on the old,
buggy behavior, you might need to change pagespecs to use `link()`.
Tag pages can automatically be created as new tags are used. This
feature is enabled by default if you have configured a tagbase. It
can be turned on or off using the `tag_autocreate` setting.
The title_natural sort method (as used by the inline directive, etc)
have been moved to the new sortnaturally plugin, which is not enabled
by default since it requires the Sort::Naturally perl module.

2
debian/changelog vendored
View File

@ -1,6 +1,8 @@
ikiwiki (3.20100422) UNRELEASED; urgency=low
[ Joey Hess ]
* tag: Automatic creation of tag pages can now be enabled using
the tag_autocreate setting. (David Riebenbauer)
* bzr: Fix bzr log parsing to work with bzr 2.0. (liw)
* comments: Fix missing entity encoding in title.
* txt: Add a special case for robots.txt.

View File

@ -19,7 +19,8 @@ instead:
Note that if the wiki is configured to use a tagbase, then the tags will be
located under a base directory, such as "tags/". This is a useful way to
avoid having to write the full path to tags, if you want to keep them
grouped together out of the way.
grouped together out of the way. Also, since ikiwiki then knows where to put
tags, it will automatically create tag pages when new tags are used.
Bear in mind that specifying a tagbase means you will need to incorporate it
into the `link()` [[ikiwiki/PageSpec]] you use: e.g., if your tagbase is

View File

@ -8,6 +8,13 @@ These directives allow tagging pages.
It also provides the `tagged()` [[ikiwiki/PageSpec]], which can be used to
match pages that are tagged with a specific tag.
The `tagbase` setting can be used to make tags default to being put in a
particular subdirectory.
The `tag_autocreate` setting can be used to control whether new tag pages
are created as needed. It defaults to being done only if a `tagbase` is
set.
[[!if test="enabled(tag)" then="""
This wiki has the tag plugin enabled, so you'll see a note below that this
page is tagged with the "tags" tag.

View File

@ -28,3 +28,4 @@ See [[todo/auto-create tag pages according to a template]]
-- Jeremy Schultz <jeremy.schultz@uleth.ca>
`tag_autocreate` can now enable this. --[[Joey]]

View File

@ -966,6 +966,23 @@ added. Pass it the page that contains the link, and the link text.
An optional third parameter sets the link type. If not specified,
it is an ordinary [[ikiwiki/WikiLink]].
### `add_autofile($$$)`
Sometimes you may want to add a file to the `srcdir` as a result of content
of other pages. For example, [[plugins/tag]] pages can be automatically
created as needed. This function can be used to do that.
The three parameters are the filename to create (relative to the `srcdir`),
the name of the plugin, and a callback function. The callback will be
called if it is appropriate to automatically add the file, and should then
take care of creating it, and doing anything else it needs to (such as
checking it into revision control). Note that the callback may not always
be called. For example, if an automatically added file is deleted by the
user, ikiwiki will avoid re-adding it again.
This function needs to be called during the scan hook, or earlier in the
build process, in order to add the file early enough for it to be built.
## Miscellaneous
### Internal use pages

View File

@ -78,6 +78,7 @@ Probably incomplete list:
* Make pagespecs match relative by default? (see [[discussion]])
* Flip wikilinks? (see [[todo/link_plugin_perhaps_too_general?]])
* YADA format setup files per default?
* Enable `tag_autocreate` by default.
In general, we try to use [[ikiwiki-transition]] or forced rebuilds on
upgrade to deal with changes that break compatability. Some things that

View File

@ -247,3 +247,5 @@ I've tested it fairly thouroughly. --[[Joey]]
[da5d29f95f6e693e8c14be1b896cf25cf4fdb3c0]: http://git.liegesta.at/?p=ikiwiki.git;a=commitdiff;h=da5d29f95f6e693e8c14be1b896cf25cf4fdb3c0 (commitdiff for da5d29f95f6e693e8c14be1b896cf25cf4fdb3c0)
[a358d74bef51dae31332ff27e897fe04834571e6]: http://git.liegesta.at/?p=ikiwiki.git;a=commitdiff;h=a358d74bef51dae31332ff27e897fe04834571e6 (commitdiff for a358d74bef51dae31332ff27e897fe04834571e6)
[981400177d68a279f485727be3f013e68f0bf691]: http://git.liegesta.at/?p=ikiwiki.git;a=commitdiff;h=981400177d68a279f485727be3f013e68f0bf691 (commitdiff for 981400177d68a279f485727be3f013e68f0bf691)
[[!tag done]]

View File

@ -0,0 +1,3 @@
## Pages tagged <TMPL_VAR TAGNAME> ##
[[!inline pages="tagged(<TMPL_VAR TAG>)" actions="no" archive="yes"]]