summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/autoindex.pm
blob: 11595e217cdccf6d7bb571a3bb9f6c79ef4ddd7f (plain)
  1. #!/usr/bin/perl
  2. package IkiWiki::Plugin::autoindex;
  3. use warnings;
  4. use strict;
  5. use IkiWiki 3.00;
  6. use Encode;
  7. sub import {
  8. hook(type => "getsetup", id => "autoindex", call => \&getsetup);
  9. hook(type => "refresh", id => "autoindex", call => \&refresh);
  10. }
  11. sub getsetup () {
  12. return
  13. plugin => {
  14. safe => 1,
  15. rebuild => 0,
  16. },
  17. }
  18. sub genindex ($) {
  19. my $page=shift;
  20. my $file=newpagefile($page, $config{default_pageext});
  21. my $template=template("autoindex.tmpl");
  22. $template->param(page => $page);
  23. writefile($file, $config{srcdir}, $template->output);
  24. if ($config{rcs}) {
  25. IkiWiki::rcs_add($file);
  26. }
  27. }
  28. sub refresh () {
  29. eval q{use File::Find};
  30. error($@) if $@;
  31. eval q{use Cwd};
  32. error($@) if $@;
  33. my $origdir=getcwd();
  34. my (%pages, %dirs);
  35. foreach my $dir ($config{srcdir}, @{$config{underlaydirs}}, $config{underlaydir}) {
  36. chdir($dir) || next;
  37. find({
  38. no_chdir => 1,
  39. wanted => sub {
  40. my $file=decode_utf8($_);
  41. $file=~s/^\.\/?//;
  42. return unless length $file;
  43. if (IkiWiki::file_pruned($file)) {
  44. $File::Find::prune=1;
  45. }
  46. elsif (! -l $_) {
  47. my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint
  48. return unless defined $f;
  49. return if $f =~ /\._([^.]+)$/; # skip internal page
  50. if (! -d _) {
  51. $pages{pagename($f)}=1;
  52. }
  53. elsif ($dir eq $config{srcdir}) {
  54. $dirs{$f}=1;
  55. }
  56. }
  57. }
  58. }, '.');
  59. chdir($origdir) || die "chdir $origdir: $!";
  60. }
  61. my %deleted;
  62. if (ref $wikistate{autoindex}{deleted}) {
  63. %deleted=%{$wikistate{autoindex}{deleted}};
  64. }
  65. elsif (ref $pagestate{index}{autoindex}{deleted}) {
  66. # compatability code
  67. %deleted=%{$pagestate{index}{autoindex}{deleted}};
  68. delete $pagestate{index}{autoindex};
  69. }
  70. if (keys %deleted) {
  71. foreach my $dir (keys %deleted) {
  72. # remove deleted page state if the deleted page is re-added,
  73. # or if all its subpages are deleted
  74. if ($deleted{$dir} && (exists $pages{$dir} ||
  75. ! grep /^$dir\/.*/, keys %pages)) {
  76. delete $deleted{$dir};
  77. }
  78. }
  79. $wikistate{autoindex}{deleted}=\%deleted;
  80. }
  81. my @needed;
  82. foreach my $dir (keys %dirs) {
  83. if (! exists $pages{$dir} && ! $deleted{$dir} &&
  84. grep /^$dir\/.*/, keys %pages) {
  85. if (exists $IkiWiki::pagemtime{$dir}) {
  86. # This page must have just been deleted, so
  87. # don't re-add it. And remember it was
  88. # deleted.
  89. if (! ref $wikistate{autoindex}{deleted}) {
  90. $wikistate{autoindex}{deleted}={};
  91. }
  92. ${$wikistate{autoindex}{deleted}}{$dir}=1;
  93. }
  94. else {
  95. push @needed, $dir;
  96. }
  97. }
  98. }
  99. if (@needed) {
  100. if ($config{rcs}) {
  101. IkiWiki::disable_commit_hook();
  102. }
  103. foreach my $page (@needed) {
  104. genindex($page);
  105. }
  106. if ($config{rcs}) {
  107. IkiWiki::rcs_commit_staged(
  108. message => gettext("automatic index generation"),
  109. );
  110. IkiWiki::enable_commit_hook();
  111. }
  112. }
  113. }
  114. 1