]> sipb.mit.edu Git - ikiwiki.git/commitdiff
Merge remote-tracking branch 'schmonz/portability'
authorJoey Hess <joey@kitenet.net>
Mon, 30 Jan 2012 19:20:54 +0000 (15:20 -0400)
committerJoey Hess <joey@kitenet.net>
Mon, 30 Jan 2012 19:20:54 +0000 (15:20 -0400)
70 files changed:
Bundle/IkiWiki.pm
IkiWiki.pm
IkiWiki/Plugin/attachment.pm
IkiWiki/Plugin/calendar.pm
IkiWiki/Plugin/comments.pm
IkiWiki/Plugin/cvs.pm
IkiWiki/Plugin/mdwn.pm
IkiWiki/Plugin/prettydate.pm
IkiWiki/Plugin/recentchangesdiff.pm
IkiWiki/Setup/Yaml.pm
debian/changelog
debian/control
doc/bugs/Encoding_problem_in_calendar_plugin.mdwn [new file with mode: 0644]
doc/bugs/UTF-8_in_attachment_filenames.mdwn [new file with mode: 0644]
doc/bugs/backlink__40__.__41___doesn__39__t_work.mdwn [new file with mode: 0644]
doc/bugs/branchable_openid_site_uses_fixed-site_openid_realm__44___obviously_that_fails_when_domain_is_different.mdwn [deleted file]
doc/bugs/http_proxy_for_openid.mdwn
doc/bugs/ikiwiki_overzealously_honours_locks_when_asked_for_forms.mdwn [new file with mode: 0644]
doc/examples/blog/posts/Discussion.mdwn [deleted file]
doc/forum.mdwn
doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn [new file with mode: 0644]
doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment [new file with mode: 0644]
doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment [new file with mode: 0644]
doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment [new file with mode: 0644]
doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment [new file with mode: 0644]
doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn [new file with mode: 0644]
doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn [new file with mode: 0644]
doc/forum/How_to_change_registration_page.mdwn [new file with mode: 0644]
doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn [new file with mode: 0644]
doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn [new file with mode: 0644]
doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment [new file with mode: 0644]
doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment [new file with mode: 0644]
doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment [new file with mode: 0644]
doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment [new file with mode: 0644]
doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn [new file with mode: 0644]
doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment [new file with mode: 0644]
doc/forum/Run_script_on_markdown_source.mdwn [new file with mode: 0644]
doc/forum/index_attachments.mdwn [new file with mode: 0644]
doc/forum/index_attachments/comment_1_18b9531d273292b45051eef6a306ca26._comment [new file with mode: 0644]
doc/forum/index_attachments/comment_2._comment [new file with mode: 0644]
doc/forum/index_attachments/comment_3_050e5847641a27e0c14232632f3e700a._comment [new file with mode: 0644]
doc/forum/index_attachments/comment_4._comment [new file with mode: 0644]
doc/forum/two_new_contrib_plugins:_newpage__44___jssearchfield.mdwn [new file with mode: 0644]
doc/ikiwikiusers.mdwn
doc/install/discussion.mdwn
doc/news/version_3.20110715.mdwn [deleted file]
doc/news/version_3.20110905.mdwn [deleted file]
doc/news/version_3.20120109.mdwn [new file with mode: 0644]
doc/news/version_3.20120115.mdwn [new file with mode: 0644]
doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn [new file with mode: 0644]
doc/plugins/contrib/jssearchfield.mdwn [new file with mode: 0644]
doc/plugins/contrib/mandoc.mdwn
doc/plugins/contrib/newpage.mdwn [new file with mode: 0644]
doc/plugins/contrib/newpage/discussion.mdwn [new file with mode: 0644]
doc/plugins/wmd/discussion.mdwn
doc/plugins/write.mdwn
doc/rcs/cvs.mdwn
doc/rcs/cvs/discussion.mdwn
doc/sandbox/Test_it.mdwn [new file with mode: 0644]
doc/shortcuts.mdwn
doc/todo/Improve_markdown_speed.mdwn
doc/todo/multi-thread_ikiwiki.mdwn
doc/todo/rewrite_ikiwiki_in_haskell.mdwn
doc/todo/rewrite_ikiwiki_in_haskell/discussion.mdwn
doc/todo/submodule_support.mdwn
doc/users/schmonz.mdwn
ikiwiki.in
ikiwiki.spec
po/ikiwiki.pot
t/cvs.t

index a0bd60e46abdf9425b0f01b1ab7dee3af3c73ebe..0059362507117ed9ae9dc92ea38ac1a312b4c06f 100644 (file)
@@ -28,7 +28,7 @@ CGI::Session
 Mail::Sendmail
 CGI
 Data::Dumper
-YAML
+YAML::XS
 JSON
 RPC::XML
 
index 08e242a1f07de9e40bda8e91c521c69b9b7be0ba..0a788f35bd69411e4ee536903fd8acc7a8580452 100644 (file)
@@ -20,7 +20,7 @@ use Exporter q{import};
 our @EXPORT = qw(hook debug error htmlpage template template_depends
        deptype add_depends pagespec_match pagespec_match_list bestlink
        htmllink readfile writefile pagetype srcfile pagename
-       displaytime will_render gettext ngettext urlto targetpage
+       displaytime strftime_utf8 will_render gettext ngettext urlto targetpage
        add_underlay pagetitle titlepage linkpage newpagefile
        inject add_link add_autofile
        %config %links %pagestate %wikistate %renderedfiles
@@ -1148,9 +1148,19 @@ sub formattime ($;$) {
                $format=$config{timeformat};
        }
 
+       return strftime_utf8($format, localtime($time));
+}
+
+my $strftime_encoding;
+sub strftime_utf8 {
        # strftime doesn't know about encodings, so make sure
-       # its output is properly treated as utf8
-       return decode_utf8(POSIX::strftime($format, localtime($time)));
+       # its output is properly treated as utf8.
+       # Note that this does not handle utf-8 in the format string.
+       $strftime_encoding = POSIX::setlocale(&POSIX::LC_TIME) =~ m#\.([^@]+)#
+               unless defined $strftime_encoding;
+       $strftime_encoding
+               ? Encode::decode($strftime_encoding, POSIX::strftime(@_))
+               : POSIX::strftime(@_);
 }
 
 sub date_3339 ($) {
@@ -2647,8 +2657,14 @@ sub match_link ($$;@) {
 }
 
 sub match_backlink ($$;@) {
-       my $ret=match_link($_[1], $_[0], @_);
-       $ret->influences($_[1] => $IkiWiki::DEPEND_LINKS);
+       my $page=shift;
+       my $testpage=shift;
+       my %params=@_;
+       if ($testpage eq '.') {
+               $testpage = $params{'location'}
+       }
+       my $ret=match_link($testpage, $page, @_);
+       $ret->influences($testpage => $IkiWiki::DEPEND_LINKS);
        return $ret;
 }
 
index fd4096edf7de153ef01145f310c459f255e3fffc..5a180cd5cf3c3eaac5282ef267982327e49eba8d 100644 (file)
@@ -272,6 +272,7 @@ sub attachments_save {
        my @attachments;
        my $dir=attachment_holding_location($form->field('page'));
        foreach my $filename (glob("$dir/*")) {
+               $filename=Encode::decode_utf8($filename);
                next unless -f $filename;
                my $destdir=$config{srcdir}."/".
                        linkpage(IkiWiki::possibly_foolish_untaint(
@@ -345,6 +346,7 @@ sub attachment_list ($) {
        my $dir=attachment_holding_location($page);
        my $heldmsg=gettext("this attachment is not yet saved");
        foreach my $file (glob("$dir/*")) {
+               $file=Encode::decode_utf8($file);
                next unless -f $file;
                my $base=IkiWiki::basename($file);
                my $f=$loc.$base;
index c7d2b7c01d8943f26e34e43231cc4ee26e0b6847..fc497b3c7351ea2151bfb14092568dbb687c3eb2 100644 (file)
@@ -22,7 +22,6 @@ use warnings;
 use strict;
 use IkiWiki 3.00;
 use Time::Local;
-use POSIX ();
 
 my $time=time;
 my @now=localtime($time);
@@ -123,10 +122,10 @@ sub format_month (@) {
        }
 
        # Find out month names for this, next, and previous months
-       my $monthabbrev=POSIX::strftime("%b", @monthstart);
-       my $monthname=POSIX::strftime("%B", @monthstart);
-       my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
-       my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
+       my $monthabbrev=strftime_utf8("%b", @monthstart);
+       my $monthname=strftime_utf8("%B", @monthstart);
+       my $pmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
+       my $nmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
 
        my $archivebase = 'archives';
        $archivebase = $config{archivebase} if defined $config{archivebase};
@@ -182,7 +181,7 @@ EOF
        my %dowabbr;
        for my $dow ($week_start_day..$week_start_day+6) {
                my @day=localtime(timelocal(0,0,0,$start_day++,$params{month}-1,$params{year}-1900));
-               my $downame = POSIX::strftime("%A", @day);
+               my $downame = strftime_utf8("%A", @day);
                my $dowabbr = substr($downame, 0, 1);
                $downame{$dow % 7}=$downame;
                $dowabbr{$dow % 7}=$dowabbr;
@@ -329,8 +328,8 @@ EOF
        for (my $month = 1; $month <= 12; $month++) {
                my @day=localtime(timelocal(0,0,0,15,$month-1,$params{year}-1900));
                my $murl;
-               my $monthname = POSIX::strftime("%B", @day);
-               my $monthabbr = POSIX::strftime("%b", @day);
+               my $monthname = strftime_utf8("%B", @day);
+               my $monthabbr = strftime_utf8("%b", @day);
                $calendar.=qq{\t<tr>\n}  if ($month % $params{months_per_row} == 1);
                my $tag;
                my $mtag=sprintf("%02d", $month);
index 3ad2a0e13a2a51ffce1301e020687b4b0c6b36d3..91a482ed6660059ed3a77f30b5236dbd891303a8 100644 (file)
@@ -9,7 +9,6 @@ use warnings;
 use strict;
 use IkiWiki 3.00;
 use Encode;
-use POSIX qw(strftime);
 
 use constant PREVIEW => "Preview";
 use constant POST_COMMENT => "Post comment";
@@ -460,7 +459,7 @@ sub editcomment ($$) {
        }
        $content .= " subject=\"$subject\"\n";
 
-       $content .= " date=\"" . decode_utf8(strftime('%Y-%m-%dT%H:%M:%SZ', gmtime)) . "\"\n";
+       $content .= " date=\"" . strftime_utf8('%Y-%m-%dT%H:%M:%SZ', gmtime) . "\"\n";
 
        my $editcontent = $form->field('editcontent');
        $editcontent="" if ! defined $editcontent;
index 71566d212ba71ea3b8c2296ffeb46c0101bea92d..0a6cbfaf6358f7a53014260f71c69ae5820641dc 100644 (file)
@@ -35,10 +35,14 @@ use IkiWiki;
 
 use File::chdir;
 
+
+# GENERAL PLUGIN API CALLS
+
 sub import {
-       hook(type => "genwrapper", id => "cvs", call => \&genwrapper);
        hook(type => "checkconfig", id => "cvs", call => \&checkconfig);
        hook(type => "getsetup", id => "cvs", call => \&getsetup);
+       hook(type => "genwrapper", id => "cvs", call => \&genwrapper);
+
        hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
        hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
        hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
@@ -52,17 +56,6 @@ sub import {
        hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime);
 }
 
-sub genwrapper () {
-       return <<EOF;
-       {
-               int j;
-               for (j = 1; j < argc; j++)
-                       if (strstr(argv[j], "New directory") != NULL)
-                               exit(0);
-       }
-EOF
-}
-
 sub checkconfig () {
        if (! defined $config{cvspath}) {
                $config{cvspath}="ikiwiki";
@@ -132,39 +125,22 @@ sub getsetup () {
                },
 }
 
-sub cvs_info ($$) {
-       my $field=shift;
-       my $file=shift;
-
-       local $CWD = $config{srcdir};
-
-       my $info=`cvs status $file`;
-       my ($ret)=$info=~/^\s*$field:\s*(\S+)/m;
-       return $ret;
+sub genwrapper () {
+       return <<EOF;
+       {
+               int j;
+               for (j = 1; j < argc; j++)
+                       if (strstr(argv[j], "New directory") != NULL)
+                               exit(0);
+       }
+EOF
 }
 
-sub cvs_runcvs(@) {
-       my @cmd = @_;
-       unshift @cmd, 'cvs', '-Q';
-
-       local $CWD = $config{srcdir};
-
-       open(my $savedout, ">&STDOUT");
-       open(STDOUT, ">", "/dev/null");
-       my $ret = system(@cmd);
-       open(STDOUT, ">&", $savedout);
 
-       return ($ret == 0) ? 1 : 0;
-}
-
-sub cvs_is_controlling {
-       my $dir=shift;
-       $dir=$config{srcdir} unless defined($dir);
-       return (-d "$dir/CVS") ? 1 : 0;
-}
+# VCS PLUGIN API CALLS
 
 sub rcs_update () {
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
        cvs_runcvs('update', '-dP');
 }
 
@@ -175,7 +151,7 @@ sub rcs_prepedit ($) {
        # The file is relative to the srcdir.
        my $file=shift;
 
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
 
        # For cvs, return the revision of the file when
        # editing begins.
@@ -183,31 +159,13 @@ sub rcs_prepedit ($) {
        return defined $rev ? $rev : "";
 }
 
-sub commitmessage (@) {
-       my %params=@_;
-       
-       if (defined $params{session}) {
-               if (defined $params{session}->param("name")) {
-                       return "web commit by ".
-                               $params{session}->param("name").
-                               (length $params{message} ? ": $params{message}" : "");
-               }
-               elsif (defined $params{session}->remote_addr()) {
-                       return "web commit from ".
-                               $params{session}->remote_addr().
-                               (length $params{message} ? ": $params{message}" : "");
-               }
-       }
-       return $params{message};
-}
-
 sub rcs_commit (@) {
        # Tries to commit the page; returns undef on _success_ and
        # a version of the page with the rcs's conflict markers on failure.
        # The file is relative to the srcdir.
        my %params=@_;
 
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
 
        # Check to see if the page has been changed by someone
        # else since rcs_prepedit was called.
@@ -250,9 +208,6 @@ sub rcs_add ($) {
        my $parent=IkiWiki::dirname($file);
        my @files_to_add = ($file);
 
-       eval q{use File::MimeInfo};
-       error($@) if $@;
-
        until ((length($parent) == 0) || cvs_is_controlling("$config{srcdir}/$parent")){
                push @files_to_add, $parent;
                $parent = IkiWiki::dirname($parent);
@@ -261,15 +216,8 @@ sub rcs_add ($) {
        while ($file = pop @files_to_add) {
                if (@files_to_add == 0) {
                        # file
-                       my $filemime = File::MimeInfo::default($file);
-                       if (defined($filemime) && $filemime eq 'text/plain') {
-                               cvs_runcvs('add', $file) ||
-                                       warn("cvs add $file failed\n");
-                       }
-                       else {
-                               cvs_runcvs('add', '-kb', $file) ||
-                                       warn("cvs add binary $file failed\n");
-                       }
+                       cvs_runcvs('add', cvs_keyword_subst_args($file)) ||
+                               warn("cvs add $file failed\n");
                }
                else {
                        # directory
@@ -283,7 +231,7 @@ sub rcs_remove ($) {
        # filename is relative to the root of the srcdir
        my $file=shift;
 
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
 
        cvs_runcvs('rm', '-f', $file) ||
                warn("cvs rm $file failed\n");
@@ -293,7 +241,7 @@ sub rcs_rename ($$) {
        # filenames relative to the root of the srcdir
        my ($src, $dest)=@_;
 
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
 
        local $CWD = $config{srcdir};
 
@@ -309,7 +257,7 @@ sub rcs_recentchanges ($) {
        my $num = shift;
        my @ret;
 
-       return unless cvs_is_controlling;
+       return unless cvs_is_controlling();
 
        eval q{use Date::Parse};
        error($@) if $@;
@@ -493,4 +441,74 @@ sub rcs_getmtime ($) {
        error "rcs_getmtime is not implemented for cvs\n"; # TODO
 }
 
+
+# INTERNAL SUPPORT ROUTINES
+
+sub commitmessage (@) {
+       my %params=@_;
+
+       if (defined $params{session}) {
+               if (defined $params{session}->param("name")) {
+                       return "web commit by ".
+                               $params{session}->param("name").
+                               (length $params{message} ? ": $params{message}" : "");
+               }
+               elsif (defined $params{session}->remote_addr()) {
+                       return "web commit from ".
+                               $params{session}->remote_addr().
+                               (length $params{message} ? ": $params{message}" : "");
+               }
+       }
+       return $params{message};
+}
+
+sub cvs_info ($$) {
+       my $field=shift;
+       my $file=shift;
+
+       local $CWD = $config{srcdir};
+
+       my $info=`cvs status $file`;
+       my ($ret)=$info=~/^\s*$field:\s*(\S+)/m;
+       return $ret;
+}
+
+sub cvs_is_controlling {
+       my $dir=shift;
+       $dir=$config{srcdir} unless defined($dir);
+       return (-d "$dir/CVS") ? 1 : 0;
+}
+
+sub cvs_keyword_subst_args ($) {
+       my $file = shift;
+
+       local $CWD = $config{srcdir};
+
+       eval q{use File::MimeInfo};
+       error($@) if $@;
+       my $filemime = File::MimeInfo::default($file);
+       # if (-T $file) {
+
+       if (defined($filemime) && $filemime eq 'text/plain') {
+               return ($file);
+       }
+       else {
+               return ('-kb', $file);
+       }
+}
+
+sub cvs_runcvs(@) {
+       my @cmd = @_;
+       unshift @cmd, 'cvs', '-Q';
+
+       local $CWD = $config{srcdir};
+
+       open(my $savedout, ">&STDOUT");
+       open(STDOUT, ">", "/dev/null");
+       my $ret = system(@cmd);
+       open(STDOUT, ">&", $savedout);
+
+       return ($ret == 0) ? 1 : 0;
+}
+
 1
index b10d085174c5d808c322f8c78bc48c8ecaa6bc39..430194bffdcc6444f34036709d9dc3767187af85 100644 (file)
@@ -25,6 +25,13 @@ sub getsetup () {
                        safe => 1,
                        rebuild => 1,
                },
+               nodiscount => {
+                       type => "boolean",
+                       example => 0,
+                       description => "disable use of markdown discount?",
+                       safe => 1,
+                       rebuild => 1,
+               },
 }
 
 my $markdown_sub;
@@ -50,14 +57,22 @@ sub htmlize (@) {
                                }
                        }
                }
-               if (! defined $markdown_sub) {
+               if (! defined $markdown_sub &&
+                   (! exists $config{nodiscount} || ! $config{nodiscount})) {
                        eval q{use Text::Markdown::Discount};
                        if (! $@) {
                                $markdown_sub=sub {
+                                       my $t=shift;
                                        # Workaround for discount binding bug
                                        # https://rt.cpan.org/Ticket/Display.html?id=73657
-                                       return "" if $_[0]=~/^\s*$/;
-                                       Text::Markdown::Discount::markdown(@_);
+                                       return "" if $t=~/^\s*$/;
+                                       # Workaround for discount's eliding
+                                       # of <style> blocks.
+                                       # https://rt.cpan.org/Ticket/Display.html?id=74016
+                                       $t=~s/<style/<elyts/ig;
+                                       my $r=Text::Markdown::Discount::markdown($t);
+                                       $r=~s/<elyts/<style/ig;
+                                       return $r;
                                }
                        }
                }
index 82d8a3df3eeef1c0b4a45c532774637a2a3e5209..b0931cb5533b36bcab5cbb3afa514ef75c51f132 100644 (file)
@@ -118,10 +118,10 @@ sub IkiWiki::formattime ($;$) {
                }
        }
 
-       $t=~s{\%A-}{my @yest=@t; $yest[6]--; strftime("%A", \@yest)}eg;
+       $t=~s{\%A-}{my @yest=@t; $yest[6]--; strftime_utf8("%A", \@yest)}eg;
 
        $format=~s/\%X/$t/g;
-       return strftime($format, \@t);
+       return strftime_utf8($format, \@t);
 }
 
 1
index 71297572d7b74a5042e18fd93128a4dca773e170..41882279331f8b1a2171bb98197602197ba64190 100644 (file)
@@ -31,13 +31,21 @@ sub pagetemplate (@) {
                my @lines=IkiWiki::rcs_diff($params{rev}, $maxlines+1);
                if (@lines) {
                        my $diff;
+                       my $trunc=0;
                        if (@lines > $maxlines) {
-                               $diff=join("", @lines[0..($maxlines-1)])."\n".
-                                       gettext("(Diff truncated)");
+                               $diff=join("", @lines[0..($maxlines-1)]);
+                               $trunc=1;
                        }
                        else {
                                $diff=join("", @lines);
                        }
+                       if (length $diff > 102400) {
+                               $diff=substr($diff, 0, 10240);
+                               $trunc=1;
+                       }
+                       if ($trunc) {
+                               $diff.="\n".gettext("(Diff truncated)");
+                       }
                        # escape html
                        $diff = encode_entities($diff);
                        # escape links and preprocessor stuff
index 6da93bb644bb5f639dd6871b492782cfa059345d..6bf20f480d523ad5144dc6d1b61ec03d1f0118b5 100644 (file)
@@ -11,10 +11,8 @@ sub loaddump ($$) {
        my $class=shift;
        my $content=shift;
 
-       eval q{use YAML::Any};
-       eval q{use YAML} if $@;
+       eval q{use YAML::XS};
        die $@ if $@;
-       $YAML::Syck::ImplicitUnicode=1;
        IkiWiki::Setup::merge(Load(encode_utf8($content)));
 }
 
@@ -35,12 +33,12 @@ sub dumpline ($$$$) {
        my $type=shift;
        my $prefix=shift;
        
-       eval q{use YAML::Old};
-       eval q{use YAML} if $@;
+       eval q{use YAML::XS};
        die $@ if $@;
-       $YAML::UseHeader=0;
+       $YAML::XS::QuoteNumericStrings=0;
 
-       my $dump=Dump({$key => $value});
+       my $dump=decode_utf8(Dump({$key => $value}));
+       $dump=~s/^---\n//; # yaml header, we don't want
        chomp $dump;
        if (length $prefix) {
                $dump=join("\n", map { $prefix.$_ } split(/\n/, $dump));
index c9ab41ebd79eddebfae235b8a1920ce4aca0e3ba..8fa3f5b2d4fc9c4af4afe733984080a819af3537 100644 (file)
@@ -1,14 +1,35 @@
-ikiwiki (3.20111230) UNRELEASED; urgency=low
+ikiwiki (3.20120116) UNRELEASED; urgency=low
+
+  * mdwn: Added nodiscount setting, which can be used to avoid using the
+    markdown discount engine, when maximum compatability is needed.
+  * Switch to YAML::XS to work around insanity in YAML::Mo. Closes: #657533
+  * cvs: Ensure text files are added in non-binary mode. (Amitai Schlair)
+  * cvs: Various cleanups and testing. (Amitai Schlair)
+  * calendar, prettydate: Fix strftime encoding bug.
+  * shortcuts: Fixed a broken shortcut to wikipedia (accidentially
+    made into a shortcut to wikiMedia).
+
+ -- Joey Hess <joeyh@debian.org>  Mon, 16 Jan 2012 13:41:14 -0400
+
+ikiwiki (3.20120115) unstable; urgency=low
+
+  * Make backlink(.) work. Thanks, Giuseppe Bilotta.
+  * mdwn: Workaround discount's eliding of <style> blocks.
+  * attachment: Fix utf-8 display bug.
+
+ -- Joey Hess <joeyh@debian.org>  Sun, 15 Jan 2012 16:19:25 -0400
+
+ikiwiki (3.20120109) unstable; urgency=low
 
   * mdwn: Can use the discount markdown library, via the
     Text::Markdown::Discount perl module. This is preferred if available
     since it's the fastest currently supported markdown library, speeding up
-    ikiwiki's rendering by a factor of 40.
+    ikiwiki's markdown rendering by a factor of 40.
     (However, when multimarkdown is enabled, Text::Markdown::Multimarkdown
     is still used.)
   * On Debian, depend on libtext-markdown-discount.
 
- -- Joey Hess <joeyh@debian.org>  Sun, 01 Jan 2012 16:22:24 -0400
+ -- Joey Hess <joeyh@debian.org>  Mon, 09 Jan 2012 11:49:14 -0400
 
 ikiwiki (3.20111229) unstable; urgency=low
 
index 922fe3c7772d2538377c45b9d6751a195181ab3f..9403dfb442fdd5a45d5aeaebaad21fb87e9497f6 100644 (file)
@@ -7,7 +7,7 @@ Build-Depends-Indep: dpkg-dev (>= 1.9.0), libxml-simple-perl,
   libtimedate-perl, libhtml-template-perl,
   libhtml-scrubber-perl, wdg-html-validator,
   libhtml-parser-perl, liburi-perl (>= 1.36), perlmagick, po4a (>= 0.34),
-  libfile-chdir-perl, libyaml-perl, python-support
+  libfile-chdir-perl, libyaml-libyaml-perl, python-support
 Maintainer: Joey Hess <joeyh@debian.org>
 Uploaders: Josh Triplett <josh@freedesktop.org>
 Standards-Version: 3.9.2
@@ -19,7 +19,7 @@ Architecture: all
 Depends: ${misc:Depends}, ${perl:Depends}, ${python:Depends}, 
   libtext-markdown-discount-perl,
   libhtml-scrubber-perl, libhtml-template-perl,
-  libhtml-parser-perl, liburi-perl (>= 1.36), libyaml-perl, libjson-perl
+  libhtml-parser-perl, liburi-perl (>= 1.36), libyaml-libyaml-perl, libjson-perl
 Recommends: gcc | c-compiler, 
   libc6-dev | libc-dev,
   git (>= 1:1.7) | git-core (>= 1:1.5.0) | subversion | tla | bzr (>= 0.91) | mercurial | monotone (>= 0.38) | darcs,
diff --git a/doc/bugs/Encoding_problem_in_calendar_plugin.mdwn b/doc/bugs/Encoding_problem_in_calendar_plugin.mdwn
new file mode 100644 (file)
index 0000000..80e9f2c
--- /dev/null
@@ -0,0 +1,73 @@
+Hello,
+
+I studied this [[guy's problem|forum/Encoding_problem_in_french_with_ikiwiki-calendar]] and I propose here a (dirty) hack to correct it.
+
+Bug summary: when using the [[calendar plugin|plugins/calendar]] in French (`LANG=fr_FR.UTF-8`), "Décembre" (French for "December") is rendered as "Décembre".
+
+I managed to track this problem down to an encoding problem of `POSIX::strftime` in `Ikiwiki/Plugin/calendar.pm`. I used [[this guy's solution|http://www.perlmonks.org/?node_id=857018]] to solve the problem (the diff is printed below).
+
+The problem is that I do not know Perl, encoding is one of the thing I would be happy not to dive into, and it is the first time I contribute to Ikiwiki: I copied and made a few changes to the code I found without understanding it. So I am not sure that my code is neat, or works in every situation. Feel free to (help me to) improve it!
+
+Cheers,    
+Louis
+
+> Yes, this seems basically right. I've applied a modified version of this.
+> [[done]]
+> --[[Joey]] 
+
+
+    diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm
+    index c7d2b7c..1345939 100644
+    --- a/IkiWiki/Plugin/calendar.pm
+    +++ b/IkiWiki/Plugin/calendar.pm
+    @@ -22,7 +22,14 @@ use warnings;
+     use strict;
+     use IkiWiki 3.00;
+     use Time::Local;
+    -use POSIX ();
+    +
+    +use POSIX qw/setlocale LC_TIME strftime/;
+    +use Encode;
+    +my ($strftime_encoding)= setlocale(LC_TIME)=~m#\.([^@]+)#;
+    +sub strftime_utf8 {
+    +# try to return an utf8 value from strftime
+    +  $strftime_encoding ? Encode::decode($strftime_encoding, &strftime) : &strftime;
+    +}
+     
+     my $time=time;
+     my @now=localtime($time);
+    @@ -123,10 +130,10 @@ sub format_month (@) {
+       }
+     
+       # Find out month names for this, next, and previous months
+    -  my $monthabbrev=POSIX::strftime("%b", @monthstart);
+    -  my $monthname=POSIX::strftime("%B", @monthstart);
+    -  my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
+    -  my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
+    +  my $monthabbrev=strftime_utf8("%b", @monthstart);
+    +  my $monthname=strftime_utf8("%B", @monthstart);
+    +  my $pmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
+    +  my $nmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
+     
+       my $archivebase = 'archives';
+       $archivebase = $config{archivebase} if defined $config{archivebase};
+    @@ -182,7 +189,7 @@ EOF
+       my %dowabbr;
+       for my $dow ($week_start_day..$week_start_day+6) {
+               my @day=localtime(timelocal(0,0,0,$start_day++,$params{month}-1,$params{year}-1900));
+    -          my $downame = POSIX::strftime("%A", @day);
+    +          my $downame = strftime_utf8("%A", @day);
+               my $dowabbr = substr($downame, 0, 1);
+               $downame{$dow % 7}=$downame;
+               $dowabbr{$dow % 7}=$dowabbr;
+    @@ -329,8 +336,8 @@ EOF
+       for (my $month = 1; $month <= 12; $month++) {
+               my @day=localtime(timelocal(0,0,0,15,$month-1,$params{year}-1900));
+               my $murl;
+    -          my $monthname = POSIX::strftime("%B", @day);
+    -          my $monthabbr = POSIX::strftime("%b", @day);
+    +          my $monthname = strftime_utf8("%B", @day);
+    +          my $monthabbr = strftime_utf8("%b", @day);
+               $calendar.=qq{\t<tr>\n}  if ($month % $params{months_per_row} == 1);
+               my $tag;
+               my $mtag=sprintf("%02d", $month);
diff --git a/doc/bugs/UTF-8_in_attachment_filenames.mdwn b/doc/bugs/UTF-8_in_attachment_filenames.mdwn
new file mode 100644 (file)
index 0000000..07fff88
--- /dev/null
@@ -0,0 +1,25 @@
+I have ikiwiki_3.20111229 installed on Debian Squeeze (Perl 5.10.1, UTF-8
+locale). The attachment plugin mangles UTF8-encoded attachment filenames if
+the name contains multibyte characters, e.g. "lää.png" becomes "lää.png".
+Apparently glob returns byte strings which are subject to implicit
+upgrading when concatenated with Perl strings. The following patch fixes
+the problem for me:
+
+----
+
+    diff -r -U 1 a/attachment.pm b/attachment.pm
+    --- a/attachment.pm        2012-01-13 23:07:29.000000000 +0200
+    +++ b/attachment.pm        2012-01-13 23:33:07.000000000 +0200
+    @@ -274,2 +274,3 @@
+       foreach my $filename (glob("$dir/*")) {
+    +      $filename=Encode::decode_utf8($filename);
+               next unless -f $filename;
+    @@ -347,2 +348,3 @@
+       foreach my $file (glob("$dir/*")) {
+    +      $file = Encode::decode_utf8($file);
+               next unless -f $file;
+
+> Seems it only mangled display of the just-uploaded attachment's filename,
+> the attachment was otherwise saved to disk with a valid UTF-8 name, and
+> doing other stuff with it also was ok. In any case, I applied your patch,
+> thanks. [[done]] --[[Joey]]
diff --git a/doc/bugs/backlink__40__.__41___doesn__39__t_work.mdwn b/doc/bugs/backlink__40__.__41___doesn__39__t_work.mdwn
new file mode 100644 (file)
index 0000000..534e5a0
--- /dev/null
@@ -0,0 +1,57 @@
+It seems `backlink(.)` doesn't work, that is, it doesn't match pages linked
+to from the current page.
+
+If I have two test pages, `foo`, which links to `bar`, then (on the `foo`
+page):
+
+ * backlink(foo) lists 'bar'
+ * backlink(.) lists nothing
+
+tested with 3.20120109.
+
+— [[Jon]]
+
+> The attached patch should fix it:
+
+>> [[applied|done]] thanks --[[Joey]] 
+
+    From 30512ac5f6a724bafb1095ab246e0648999f7b6c Mon Sep 17 00:00:00 2001
+    From: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
+    Date: Fri, 13 Jan 2012 11:02:11 +0100
+    Subject: [PATCH] backlink(.) should behave like backlink(<current page>)
+    
+    Since commit c4d4cad3befbbd444d094cbeb0b6ebba3910a025, the single dot in
+    a pagespec can be used to mean the current page. While this worked
+    correctly in link() it didn't work in backlink(). Fix this by explicitly
+    checking the testpage in backlink against . and replacing it with the
+    current location if necessary.
+    ---
+     IkiWiki.pm |   10 ++++++++--
+     1 files changed, 8 insertions(+), 2 deletions(-)
+    
+    diff --git a/IkiWiki.pm b/IkiWiki.pm
+    index 08e242a..bc56501 100644
+    --- a/IkiWiki.pm
+    +++ b/IkiWiki.pm
+    @@ -2647,8 +2647,14 @@ sub match_link ($$;@) {
+     }
+     
+     sub match_backlink ($$;@) {
+    -  my $ret=match_link($_[1], $_[0], @_);
+    -  $ret->influences($_[1] => $IkiWiki::DEPEND_LINKS);
+    +  my $page=shift;
+    +  my $testpage=shift;
+    +  my %params=@_;
+    +  if ($testpage eq '.') {
+    +          $testpage = $params{'location'}
+    +  }
+    +  my $ret=match_link($testpage, $page, @_);
+    +  $ret->influences($testpage => $IkiWiki::DEPEND_LINKS);
+       return $ret;
+     }
+     
+    -- 
+    1.7.8.rc2.253.gdbf3
+
+
+> (you need to re-make IkiWiki for it to work)
diff --git a/doc/bugs/branchable_openid_site_uses_fixed-site_openid_realm__44___obviously_that_fails_when_domain_is_different.mdwn b/doc/bugs/branchable_openid_site_uses_fixed-site_openid_realm__44___obviously_that_fails_when_domain_is_different.mdwn
deleted file mode 100644 (file)
index 3388675..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-phil hands is kindly hosting rhombus-tech.net on an h-branchable ikiwiki.  openid has been enabled, for convenience.  unfortunately... :/etc/ikiwiki-hosting/ikiwiki-hosting.conf has an openid realm of "http://*.hands.com" which is kinda important (i assume) for security reasons.  however this conflicts with what openid requires.  openid logins are now specifying the realm of http://*.hands.com which of course doesn't match with http://rhombus-tech.net - it all goes pear-shaped from there.
-
-any ideas?  thanks folks.
index b7ae76aeb30ac1a4697d976719d16d3986da9639..566896ec328de870f4b698a4c55669f3aec7c8f0 100644 (file)
@@ -78,3 +78,9 @@ Brian May
 >>>>> explicitly removed", so if ikiwiki can preferentially find that 
 >>>>> installed, even with the above commit, `openid` won't be able to 
 >>>>> traverse a proxy. --[[schmonz]]
+
+[[!template id=gitbranch branch=schmonz/proxies author="[[schmonz]]"]]
+
+>>>>> I bollixed up my git, recloned, and reapplied the diffs, so
+>>>>> that commit won't exist anymore. My proxy-related changes are
+>>>>> now on a branch. --[[schmonz]]
diff --git a/doc/bugs/ikiwiki_overzealously_honours_locks_when_asked_for_forms.mdwn b/doc/bugs/ikiwiki_overzealously_honours_locks_when_asked_for_forms.mdwn
new file mode 100644 (file)
index 0000000..1e74fe8
--- /dev/null
@@ -0,0 +1,34 @@
+When an `ikiwiki` instance is holding a lock, a web user clicking on "add comment" (for example) will have to wait for the lock to be released.  However, all they are then presented with is a web form.  Perhaps CGI requests that are read-only (such as generating a comment form, or perhaps certain types of edits) should ignore locks? Of course, I'd understand that the submission would need to wait for a lock. â€” [[Jon]]
+
+> Ikiwiki has what I think of as the Big Wiki Lock (remembering the "Big
+> Kernel Lock"). It takes the exclusive lock before loading any state,
+> to ensure that any changes to that state are made safely.
+> 
+> A few CGI actions that don't need that info loaded do avoid taking the
+> lock.
+> 
+> In the case of showing the comment form, the comments
+> plugin needs CGI session information to be loaded, so it can check if
+> the user is logged in, and so it can add XSRF prevention tokens based on
+> the session ID. (Actually, it might be possible to rely on
+> `CGI::Session`'s own locking of the sessions file, and have a hook that
+> runs with a session but before the indexdb is loaded.)
+> 
+> But, the comment form also needs to load the indexdb, in order to call
+> `check_canedit`, which matches a pagespec, which can need to look things
+> up in the indexdb. (Though the pagespecs that can do that are unlikely
+> to be relevant when posting a comment.)
+> 
+> I've thought about trying to get rid of the Big Wiki Lock from time to
+> time. It's difficult though; if two ikiwikis are both making changes
+> to the stored state, it's hard to see a way to reconcile them. (There
+> could be a daemon that all changes are fed thru using a protocol, but
+> that's really complicated, and it'd almost be better to have a single
+> daemon that just runs ikiwiki; a major architectural change.)
+> 
+> One way that *almost* seems it could work is to have a entry path
+> that loads everything read-only, without a lock. And then in read-only
+> mode, `saveindex` would be an error to run. However, both the commenting
+> code and the page edit code currently have the same entry path for
+> drawing the form as is used for handling the posted form, so they would
+> need to be adapted to separate that into two code paths. --[[Joey]]
diff --git a/doc/examples/blog/posts/Discussion.mdwn b/doc/examples/blog/posts/Discussion.mdwn
deleted file mode 100644 (file)
index f04a955..0000000
+++ /dev/null
@@ -1 +0,0 @@
-foo bar.
index 19ca9ed0b26fee4d023b5022c2876d25c3c3ff93..62b62a401f370475e090807c3857e9a0c7566580 100644 (file)
@@ -4,6 +4,7 @@ page fitting enough. Users of ikiwiki can ask questions here.
 Note that for more formal bug reports or todo items, you can also edit the
 [[bugs]] and [[todo]] pages.
 
+
 ## Current topics ##
 
 [[!inline pages="forum/*  and !forum/discussion and !forum/*/*" 
diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn
new file mode 100644 (file)
index 0000000..50b5ea9
--- /dev/null
@@ -0,0 +1,7 @@
+Unfortunately debian stable / squeeze repos are still on version 3.20100815.7
+
+Do you think squeeze will update to a newer version soon? I am lacking support of the gallery plugin and 1 more that I forgot right now  ;)
+
+Is everyone else upgrading by directly installing via dpkg (no updates, but yeah)?
+
+Regards
diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment
new file mode 100644 (file)
index 0000000..e6d09b5
--- /dev/null
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="http://joey.kitenet.net/"
+ nickname="joey"
+ subject="comment 1"
+ date="2012-01-16T14:52:22Z"
+ content="""
+Nothing wrong with 3.20100815.7 unless you need newer features.
+
+At Branchable we run Debian stable and backport the current ikiwiki to run on it. This is quite easy to do, it just builds and works. (Edit debian/control and s/markdown-discount/markdown/)
+
+It's probably time someone released a backport. I have historically not done that myself though.
+"""]]
diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment
new file mode 100644 (file)
index 0000000..07955ac
--- /dev/null
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8"
+ nickname="Christian"
+ subject="thats cool"
+ date="2012-01-16T15:31:22Z"
+ content="""
+thanks
+"""]]
diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment
new file mode 100644 (file)
index 0000000..3ab401e
--- /dev/null
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8"
+ nickname="Christian"
+ subject="Great! It worked!"
+ date="2012-01-17T01:18:06Z"
+ content="""
+Thanks Joey, also for the replacement hint, had to install one or two dependencies and it worked like a charm. Version from the day before yesterday now. (Awesome!)
+
+I have not upgraded the mypage.setup file, yet. I included \"headinganchors\" which does not seem to work right now. The page compiles without errors but contains no anchors when viewed in browser. Hm..
+
+Great job thanks again!
+"""]]
diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment
new file mode 100644 (file)
index 0000000..569a735
--- /dev/null
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8"
+ nickname="Christian"
+ subject="updating setup file"
+ date="2012-01-17T01:30:32Z"
+ content="""
+just for the record - I created a new wiki and the setup file is then automatically in YAML format. I think I am going to just transfer the settings from the \"old\" setup file to the new one. 
+
+If anyone has an idea why the headinganchors don't work, pls let me know. 
+
+As for the rest - insanely cool piece of software - great
+"""]]
diff --git a/doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn b/doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn
new file mode 100644 (file)
index 0000000..472412d
--- /dev/null
@@ -0,0 +1,20 @@
+Hi!
+
+I'm using the ikiwiki calendar plugin.
+
+My website is in french (locale fr_FR.UTF-8), and calendars that are generated by the plugin makes some encodi$
+
+I don't know how the plugin generate translation for dates, but I've seen that there is no ikiwiki translation$
+
+That's why I suppose (but I'm not sure) that it use date unix command to insert date into the html page, witho$
+
+Could I have forgotten some options to make it nice or not?
+
+Is someone could test it and verify if it works or not?
+
+Thanks.
+
+Zut
+
+> This was discussed in [[bugs/Encoding_problem_in_calendar_plugin]]
+> and is now fixed. --[[Joey]] 
diff --git a/doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn b/doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn
new file mode 100644 (file)
index 0000000..d5f1449
--- /dev/null
@@ -0,0 +1 @@
+How to allow .markdown and .md (at the same time) as valid extensions for source files? The default is .mdwn.
diff --git a/doc/forum/How_to_change_registration_page.mdwn b/doc/forum/How_to_change_registration_page.mdwn
new file mode 100644 (file)
index 0000000..f339f71
--- /dev/null
@@ -0,0 +1,9 @@
+Well, I simply don't see it.
+I would like to change the "account registration" page, where it says user, password, repeat password, Account Creation Password, E-Mail.  
+
+I simply want it to ask a question like "Who's your daddy" or "What are we all working on" instead of "Account creation password".
+
+I already grepped through the files of the source which I compiled ikiwiki from - I just can't find it. I'm a noob in cgi, it seems to be somewhat in there, but that could also be totally wrong.
+
+Can you tell me where to look?
+
diff --git a/doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn b/doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn
new file mode 100644 (file)
index 0000000..e9dd665
--- /dev/null
@@ -0,0 +1,24 @@
+I followed instructions at 
+
+    http://ikiwiki.info/plugins/po/
+
+and added to `configfile`
+
+        po_master_language => 'en|English',
+       po_slave_languages => [ 'zh|Chinese' ],
+        po_translatable_pages => '(* and !*/Discussion and !blog/*/comment_*)',
+        po_link_to => 'current'
+
+and did 
+
+      ikiwiki --setup configfile
+
+But I don't seem to see any change in the newly built site. 
+
+How do I actually use po to create translation pages? 
+
+1) I have existing pages that's in English. How do I add translated versions of some of those pages in the slave language?
+
+2) How do I add new pages with the primary language version and alternative versions in slave languages?
+
+The documentation of po is not explicit with what are the concrete steps.
diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn
new file mode 100644 (file)
index 0000000..e23d3fd
--- /dev/null
@@ -0,0 +1,14 @@
+Since ikiwiki doesn't have much of a chance of working in windows, how about we compromise by making an offline ikiwiki editor for Windows? In fact, it might be advantageous to use it in Linux, too...
+
+It should be very simple: It would enter the source wiki and show the Markdown code by default, but would have an option to preview your page in another tab.
+
+Basic features:
+
+* wikilinks, maps, images, inlinepages, and other basic functions should all work in the preview
+* perhaps use local.css to format preview
+* See the DVCS history with diffs and all
+* have a discussion tab to easily see what other people have said about the page
+
+If we want to add some more bells and whistles, maybe we could throw in some buttons to insert markdown formatting (like in forums, mediawiki, or RES).
+
+Any thoughts on this?
diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment
new file mode 100644 (file)
index 0000000..20fd763
--- /dev/null
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://kerravonsen.dreamwidth.org/"
+ ip="202.173.183.92"
+ subject="comment 1"
+ date="2012-01-13T22:32:47Z"
+ content="""
+It would probably be quite complex to write, and difficult to maintain.  I don't think much of your chances of getting someone to write it.  If you want to write it yourself, have fun doing so!
+"""]]
diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment
new file mode 100644 (file)
index 0000000..b83042c
--- /dev/null
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawkr8GVPw30JBR34Btg-SKcS8gxEf7zpSJQ"
+ nickname="Lawrence"
+ subject="comment 2"
+ date="2012-01-14T03:14:38Z"
+ content="""
+Eh, ok, lol. I know that implementing most of the wiki features over again could be difficult, and so would a Git diff reader, but it shouldn't be that hard to get Wikilinking or a markdown previewer working.
+
+Could you point out some specific problems of this approach, so that it would help me out to do so?
+"""]]
diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment
new file mode 100644 (file)
index 0000000..e5eaf2c
--- /dev/null
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawkr8GVPw30JBR34Btg-SKcS8gxEf7zpSJQ"
+ nickname="Lawrence"
+ subject="comment 3"
+ date="2012-01-14T17:41:52Z"
+ content="""
+Like, there's already a whole host of Markdown previewer apps that are pretty good. [Here's a](http://www.macworld.com/article/164744/2012/01/marked_excels_at_previewing_markdown_and_html_documents.html) popular one on Mac, and there are many more...
+
+There's also a plugin for Emacs that does so, and even resolves wikilinks (in some way..).
+
+But I'd have to say that I probably made a misleading title, WYSIWYG would probably be low on the list of needed features. And I'm just dumping an idea I have here in case anyone has any suggestions or comments, I'll probably do it myself in my free time.
+"""]]
diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment
new file mode 100644 (file)
index 0000000..4724174
--- /dev/null
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8"
+ nickname="Christian"
+ subject="just my 2 cents"
+ date="2012-01-17T11:10:09Z"
+ content="""
+why?
+"""]]
diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn
new file mode 100644 (file)
index 0000000..e58844b
--- /dev/null
@@ -0,0 +1,12 @@
+Hi,
+
+unfortunately, openID is not working at my wiki. I get the error
+
+no_identity_server: The provided URL doesn't declare its OpenID identity server.
+
+I think this is related to the ID of my wiki not being defined right. Where and how do I have to define it? I have used the !meta openid as described on ikiwiki.info (are there two quotes at the end where only one should be (joeyh example) on index.html. 
+
+Somehow I think its not transferred right to the openID provider of the user upon login.
+
+thanks in advance
+chris
diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment
new file mode 100644 (file)
index 0000000..06d2a33
--- /dev/null
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8"
+ nickname="Christian"
+ subject="apache module?"
+ date="2012-01-18T15:40:57Z"
+ content="""
+Do I have to install the openid apache module, load it, and configure apache to use my openid? Except that in my case I can get it from the package system, there is a description <a href=\"http://findingscience.com/mod_auth_openid/\">here</a> what I mean. I got a feeling that's it.
+"""]]
diff --git a/doc/forum/Run_script_on_markdown_source.mdwn b/doc/forum/Run_script_on_markdown_source.mdwn
new file mode 100644 (file)
index 0000000..614815c
--- /dev/null
@@ -0,0 +1 @@
+How can I add a button to each wiki page which launches an external application or script with the markdown code of the current page as input?
diff --git a/doc/forum/index_attachments.mdwn b/doc/forum/index_attachments.mdwn
new file mode 100644 (file)
index 0000000..8167a60
--- /dev/null
@@ -0,0 +1,9 @@
+Why doesn't the [[plugins/search]] plugin index attachments? are there any
+technical reasons for not including this feature/option? (besides increased
+processing time, and depending from external programs.)
+
+One could check for all non-mdwn files, convert them to text, if such thing is
+possible, and add them as documents; I guess `needsbuild` would be a good site
+for that.
+
+--[[jerojasro]]
diff --git a/doc/forum/index_attachments/comment_1_18b9531d273292b45051eef6a306ca26._comment b/doc/forum/index_attachments/comment_1_18b9531d273292b45051eef6a306ca26._comment
new file mode 100644 (file)
index 0000000..056c413
--- /dev/null
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="http://joey.kitenet.net/"
+ nickname="joey"
+ subject="comment 1"
+ date="2012-01-13T17:46:49Z"
+ content="""
+I don't think there are really any reasons, other than noone having done it. 
+
+Although it is worth noting that using additional libraries/programs to eg, pull exif data and comments out of image files and make it searchable, does potentially increase ikiwiki's attack surface.
+"""]]
diff --git a/doc/forum/index_attachments/comment_2._comment b/doc/forum/index_attachments/comment_2._comment
new file mode 100644 (file)
index 0000000..a7eec29
--- /dev/null
@@ -0,0 +1,31 @@
+[[!comment format=mdwn
+ username="jerojasro"
+ nickname="jerojasro"
+ subject="RE: comment 1"
+ date="2012-01-15T23:49:49Z"
+ content="""
+I've modified the plugin adding the possibility of indexing attachments. Only
+PDF attachments for now, but support for other filetypes should be real easy to add.
+
+The changes to `IkiWiki/Plugin/search.pm` are available at
+<http://git.devnull.li/ikiwiki.git>, in the `srchatt` branch.
+
+I have a small question about filenames and security: I'm using `qx` to execute
+the program that extracts the text from the PDF files, but `qx` executes a
+whole string, and passes it not to the program I want to run, but to a shell,
+so it is possible (I think) to craft a filename that, in a shell, expands to
+something nasty.
+
+How do the Perl/IkiWiki experts suggest to handle these potentially unsafe
+filenames? I've thought of the following options:
+
+  * Running the text extractor program using `Proc::Safe`. I could not find a
+    Debian package for it, and I'd rather avoid adding another dependency to
+    IkiWiki.
+  * Running the text extractor program as suggested in the `perlipc` document,
+    using `fork` + `exec`.
+
+I haven't done any of those because I'd like to check if there are any helpers
+in IkiWiki to do this. Perhaps the `IkiWiki::possibly_foolish_untaint` function
+does it? (I didn't really understand what it does...)
+"""]]
diff --git a/doc/forum/index_attachments/comment_3_050e5847641a27e0c14232632f3e700a._comment b/doc/forum/index_attachments/comment_3_050e5847641a27e0c14232632f3e700a._comment
new file mode 100644 (file)
index 0000000..b589ae8
--- /dev/null
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawljSQThLsc4vHz0jw1aSR74Dj9K5J_NKqk"
+ nickname="Michal"
+ subject="comment 3"
+ date="2012-01-17T16:45:37Z"
+ content="""
+Maybe it could be sufficient to run a command similar to
+
+    omindex --db /path/to/.ikiwiki/xapian/default --url http://webserver/ikiwiki /path/to/public_html
+"""]]
diff --git a/doc/forum/index_attachments/comment_4._comment b/doc/forum/index_attachments/comment_4._comment
new file mode 100644 (file)
index 0000000..1a27262
--- /dev/null
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="jerojasro"
+ nickname="jerojasro"
+ subject="RE: comment 1"
+ date="2012-01-21T21:44:00"
+ content="""
+[[Michal]], that's not a bad idea IMO, but we would lose some [[searching
+keywords|ikiwiki/searching]] and would also index structural elements
+(navigation text, and so on)
+"""]]
diff --git a/doc/forum/two_new_contrib_plugins:_newpage__44___jssearchfield.mdwn b/doc/forum/two_new_contrib_plugins:_newpage__44___jssearchfield.mdwn
new file mode 100644 (file)
index 0000000..8293b09
--- /dev/null
@@ -0,0 +1,20 @@
+Just thought people might like to know I've added a couple more plugins to contrib.
+
+[[plugins/contrib/newpage]]: This plugin adds a new action to the "ACTIONS" section of a page; a button labelled "create" and an input field next to it.
+
+The common way of creating a new page is to edit a different page and add a link to the new page. However, there are some situations where that is a nuisance; for example, where pages are listed using a map directive. The newpage plugin enables one to simply type the name of the new page, click the "create" button, and one is then taken to the standard IkiWiki create-page form.
+
+[[plugins/contrib/jssearchfield]]: This plugin provides the [[plugins/contrib/ikiwiki/directive/jssearchfield]] directive.  This
+enables one to search the structured data ("field" values) of multiple pages.
+This uses Javascript for the searching, which means that the entire thing
+is self-contained and does not require a server or CGI access, unlike
+the default IkiWiki search. This means that it can be used in places such
+as ebook readers.  The disadvantage is that because Javascript runs
+in the browser, the searching is only as fast as the machine your browser
+is running on.
+
+Because this uses Javascript, the htmlscrubber must be turned off for any page where the directive is used.
+
+This plugin depends on the [[!iki plugins/contrib/field]] plugin.
+
+--[[KathrynAndersen]]
index 342d1494d67a86ea8519e28eeab483b85e9984f4..bd85d6cf8d663ba8ad3b4eb7a9c47868a7a57c81 100644 (file)
@@ -77,6 +77,8 @@ Projects & Organizations
 * [The Amnesic Incognito Live System](https://tails.boum.org/index.en.html)
 * [The Progress Linux OS wiki](http://wiki.progress-linux.org/)
 * [Oxford Computer Society](http://www.ox.compsoc.net/)
+* [Russian OpenBSD Community wiki](http://wiki.openbsd.ru/)
+* [Arcada Project](http://arcadaproject.org/)
 
 Personal sites and blogs
 ========================
@@ -162,7 +164,7 @@ Personal sites and blogs
 * [Richard "RichiH" Hartmann](http://richardhartmann.de/blog) - I thought I had added myself a year ago. Oups :)
 * [Jonas Smedegaard](http://dr.jones.dk/) multilingual "classic" website w/ blog
 * [Siri Reiter](http://sirireiter.dk/) portfolio website with a blog (in danish)
-* [L'Altro Wiki](http://laltromondo.dynalias.net/~iki/) Tutorials, reviews, miscellaneus articles in English and Italian, from the IRC network syrolnet.org
+* [L'Altro Wiki](http://laltromondo.dynalias.net/~iki/) Tutorials, reviews, miscellaneus articles in English and Italian.
 * [STUPiD](http://lhzhang.com/)
 * gregoa's [p.r. - political rants](http://info.comodo.priv.at/pr/)
 * [Michael Hammer](http://www.michael-hammer.at/)
index b4ec5ebf474a46335a89490b2b1e64a18e5de32c..b27cc4bacb13d011dc16aee6243265f0fe132fec 100644 (file)
@@ -349,3 +349,10 @@ I've attempted to mergeably patch these in my git, commit
 5c177c96ac98b24aaa0613ca241fb113f1b32c55.
 
 --[[schmonz]]
+
+-----
+
+[[!template id=gitbranch branch=schmonz/portability author="[[schmonz]]"]]
+
+My git was in a screwy state so I started over. These changes are
+now on a branch. --[[schmonz]]
diff --git a/doc/news/version_3.20110715.mdwn b/doc/news/version_3.20110715.mdwn
deleted file mode 100644 (file)
index da291da..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-ikiwiki 3.20110715 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * rename: Fix logic error that broke renaming pages when the attachment
-     plugin was disabled.
-   * rename: Fix logic error that bypassed the usual pagespec checks."""]]
\ No newline at end of file
diff --git a/doc/news/version_3.20110905.mdwn b/doc/news/version_3.20110905.mdwn
deleted file mode 100644 (file)
index bff02c3..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-ikiwiki 3.20110905 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * mercurial: Openid nicknames are now used when committing. (Daniel Andersson)
-   * mercurial: Implement rcs\_commit\_staged so comments, attachments, etc
-     can be used. (Daniel Andersson)
-   * mercurial: Implement rcs\_rename, rcs\_remove. (Daniel Andersson)
-   * mercurial: Fix viewing of a diff containing non-utf8 changes.
-     (Daniel Andersson)
-   * mercurial: Make both rcs\_getctime and rcs\_getmtime fast. (Daniel Andersson)
-   * mercurial: Implement rcs\_diff. (Daniel Andersson)
-   * po: Add `LANG\_CODE` and `LANG\_NAME` template variables. (intrigeri)
-   * Fix typo in Danish translation of shortcuts page that caused exponential
-     regexp blowup.
-   * Fix escaping of html entities in permalinks.
-   * Fix escaping of html entities in tag names.
-   * Avoid using named capture groups in heredoc code for oldperl compatibility.
-   * Put in a workaround for #622591, by ensuring Search::Xapian gets loaded
-     before Image::Magick.
-   * Add unminified jquery js and css files to source.
-   * Update to jquery 1.6.2, and jquery-ui 1.8.14.
-   * Use lockf rather than flock when taking the cgilock, for better
-     portability.
-   * search: Fix encoding bug in calculation of maximum term size.
-   * inline: When indexing internal pages for searching, use the url of
-     the inlining page.
-   * Fix comments testsuite to not rely on Date::Parse's ability to
-     parse the date Columbus discovered America. Closes: #[640350](http://bugs.debian.org/640350)
-   * Avoid warning message when generating setup file if highlight
-     is not installed. Closes: #[637606](http://bugs.debian.org/637606)
-   * Promote RPC::XML to a Recommends, since it's used by auto-blog.setup.
-     Closes: #[637603](http://bugs.debian.org/637603)
-   * Fix web revert of a file deletion."""]]
\ No newline at end of file
diff --git a/doc/news/version_3.20120109.mdwn b/doc/news/version_3.20120109.mdwn
new file mode 100644 (file)
index 0000000..de53c5d
--- /dev/null
@@ -0,0 +1,9 @@
+ikiwiki 3.20120109 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * mdwn: Can use the discount markdown library, via the
+     Text::Markdown::Discount perl module. This is preferred if available
+     since it's the fastest currently supported markdown library, speeding up
+     ikiwiki's markdown rendering by a factor of 40.
+     (However, when multimarkdown is enabled, Text::Markdown::Multimarkdown
+     is still used.)
+   * On Debian, depend on libtext-markdown-discount."""]]
\ No newline at end of file
diff --git a/doc/news/version_3.20120115.mdwn b/doc/news/version_3.20120115.mdwn
new file mode 100644 (file)
index 0000000..ba665c6
--- /dev/null
@@ -0,0 +1,5 @@
+ikiwiki 3.20120115 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Make backlink(.) work. Thanks, Giuseppe Bilotta.
+   * mdwn: Workaround discount's eliding of &lt;style&gt; blocks.
+   * attachment: Fix utf-8 display bug."""]]
\ No newline at end of file
diff --git a/doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn b/doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn
new file mode 100644 (file)
index 0000000..5d33890
--- /dev/null
@@ -0,0 +1,42 @@
+The `jssearchfield` directive is supplied by the [[!iki plugins/contrib/jssearchfield desc=jssearchfield]] plugin.
+
+This enables one to search the structured data ("field" values) of
+multiple pages.  A search form is constructed, and the searching is
+done with Javascript, which means that the entire thing is self-contained.
+This depends on the [[!iki plugins/contrib/field]] plugin.
+
+The pages to search are selected by a PageSpec given by the "pages"
+parameter.
+The fields to search are given by the "fields" parameter.  By default,
+the field name is given, and the user can type the search parameter for
+that field into a text input field.
+
+## OPTIONS
+
+**pages**: A PageSpec to determine the pages to search through.
+
+**fields**: The fields to put into the search form, and to display
+in the results.
+
+**tagfields**: Display the given fields as a list of tags that can
+be selected from, rather than having a text input field.  Every distinct
+value of that field will be listed, so it is best used for things with
+short values, like "Author" rather than long ones like "Description".
+Note that "tagfields" must be a subset of "fields".
+
+**sort**: A SortSpec to determine how the matching pages should be sorted; this is the "default" sort order that the results will be displayed in.
+The search form also gives the option of "random" sort, which will
+display the search results in random order.
+
+## SEARCHING
+
+The search form that is created by this directive contains the following:
+
+* for each search field, a label, plus either a text input field, or a list of checkboxes with values next to them if the field is also a tagfield.  Note that the lists of checkboxes are initially hidden; one must click on the triangle next to the label to display them.
+* a "sort" toggle. One can select either "default" or "random".
+* A "Search!" button, to trigger the search if needed (see below)
+* A "Reset" button, which will clear all the values.
+
+The searching is dynamic.  As soon as a value is changed, either by tabbing out of the text field, or by selecting or de-selecting a checkbox, the search
+results are updated.  Furthermore, for tagfields, the tagfield lists
+themselves are updated to reflect the current search results.
diff --git a/doc/plugins/contrib/jssearchfield.mdwn b/doc/plugins/contrib/jssearchfield.mdwn
new file mode 100644 (file)
index 0000000..2d41ee2
--- /dev/null
@@ -0,0 +1,35 @@
+[[!template id=plugin name=jssearchfield author="[[rubykat]]"]]
+[[!tag type/search]]
+IkiWiki::Plugin::jssearchfield - Create a search form to search page field data.
+
+This plugin provides the [[ikiwiki/directive/jssearchfield]] directive.  This
+enables one to search the structured data ("field" values) of multiple pages.
+This uses Javascript for the searching, which means that the entire thing
+is self-contained and does not require a server or CGI access, unlike
+the default IkiWiki search. This means that it can be used in places such
+as ebook readers.  The disadvantage is that because Javascript runs
+in the browser, the searching is only as fast as the machine your browser
+is running on.
+
+Because this uses Javascript, the htmlscrubber must be turned off for any page where the directive is used.
+
+This plugin depends on the [[!iki plugins/contrib/field]] plugin.
+
+## Activate the plugin
+
+    # activate the plugin
+    add_plugins => [qw{goodstuff field jssearchfield ....}],
+
+    # disable scrubbing for search page
+    htmlscrubber_skip => 'mysearchpage',
+
+## PREREQUISITES
+
+    IkiWiki
+    IkiWiki::Plugin::field
+    HTML::Template
+
+## DOWNLOAD
+
+* browse at GitHub: <http://github.com/rubykat/ikiplugins/blob/master/IkiWiki/Plugin/jssearchfield.pm>
+* git repo at git://github.com/rubykat/ikiplugins.git
index 15d2826edf3f898361b68ef6f56623ae199248b5..672a268ccda9b216de6da8c876a0fc488f63f07b 100644 (file)
@@ -1,5 +1,5 @@
 [[!template id=plugin name=mandoc author="[[schmonz]]"]]
-[[!template id=gitbranch branch=schmonz/master author="[[schmonz]]"]]
+[[!template id=gitbranch branch=schmonz/mandoc author="[[schmonz]]"]]
 [[!tag type/format]]
 
 This plugin lets ikiwiki convert Unix man pages to HTML. It uses
diff --git a/doc/plugins/contrib/newpage.mdwn b/doc/plugins/contrib/newpage.mdwn
new file mode 100644 (file)
index 0000000..54c2f53
--- /dev/null
@@ -0,0 +1,29 @@
+[[!template id=plugin name=newpage author="[[rubykat]]"]]
+[[!tag type/web]]
+[[!toc]]
+## NAME
+
+IkiWiki::Plugin::newpage - add a "create new page" form to actions
+
+## SYNOPSIS
+
+    # activate the plugin
+    add_plugins => [qw{goodstuff newpage ....}],
+
+## DESCRIPTION
+
+This plugin adds a new action to the "ACTIONS" section of a page;
+a button labelled "create" and an input field next to it.
+
+The common way of creating a new page is to edit a different page
+and add a link to the new page.  However, there are some situations
+where that is a nuisance; for example, where pages are listed using
+a [[plugins/map]] directive.  The newpage plugin enables
+one to simply type the name of the new page, click the "create" button,
+and one is then taken to the standard IkiWiki create-page form.
+
+## DOWNLOAD
+
+* browse at GitHub: <http://github.com/rubykat/ikiplugins/blob/master/IkiWiki/Plugin/newpage.pm>
+* git repo at git://github.com/rubykat/ikiplugins.git
+
diff --git a/doc/plugins/contrib/newpage/discussion.mdwn b/doc/plugins/contrib/newpage/discussion.mdwn
new file mode 100644 (file)
index 0000000..d312ce4
--- /dev/null
@@ -0,0 +1,4 @@
+How is this better than creating an inline with `rootpage` set, 
+which creates a similar new page form? I sometimes make the inline match
+nothing, while still creating pages, in the odd cases where I have a map 
+or such displaying the pages. --[[Joey]]
index 42af97ec3d39dc507642247efb3c4e94e7d7e2a1..b57ef40571253a1e4af997bdbfd64eb5fd861a3e 100644 (file)
@@ -59,3 +59,15 @@ copy [...]
 > It does not, however, have a markdown to html converter -- for 
 > previewing it has to talk to the server with AJAX.
 > --[[Joey]] 
+
+>> I've got pagedown working on my personal site (simon.kisikew.org) but I'm not sure how
+>> I can inject the relevant &lt;div&gt;'s in the right place. They need to go **above**
+>> the editing &lt;textarea&gt; . (Too bad about the licensing, it's rather nice.)
+>> I had to do one minor change to it to have it inject itself into the page properly,
+>> and that was to make this change in `Markdown.Editor.js`:
+>>
+>> `this.input = doc.getElementById("editcontent" + postfix);`
+>>
+>> on line 247.  --[[simonraven]]
+
+>>> Well, I re-figured out that I needed a TMPL_VAR FOO in the template(s). --[[simonraven]]
index 9a5ca60a0f967cb276dcd77eb781fc056512d694..dcab041dc285b0ae9214a629c692d1f8e747b7d9 100644 (file)
@@ -1110,9 +1110,7 @@ to version control; the subdir can be added if so.
 Remove a file. The filename is relative to the root of the srcdir.
 
 Note that this should not commit the removal, it should only prepare for it
-to be committed when `rcs_commit` (or `rcs_commit_staged`) is called. Note
-that the new file may be in a new subdir that is not yet in version
-control; the subdir can be added if so.
+to be committed when `rcs_commit` (or `rcs_commit_staged`) is called.
 
 #### `rcs_rename($$)`
 
index 9beb08ecef02ffd6e08fe91e7ee30114037b13d3..a0ee5ab60454632b2125afb525ac07aaa8882fc2 100644 (file)
@@ -1,13 +1,17 @@
-If you really need to, you can use [[!wikipedia desc="CVS" Concurrent Versions System]]
-with ikiwiki.
+[[!template id=gitbranch branch=schmonz/cvs author="[[schmonz]]"]]
+
+If you really need to, you can use [[!wikipedia desc="CVS" Concurrent
+Versions System]] with ikiwiki.
 
 ### Usage
 7. Install [[!cpan File::chdir]], [[!cpan File::ReadBackwards]],
-[cvsps](http://www.cobite.com/cvsps/), and
-[cvsweb](http://www.freebsd.org/projects/cvsweb.html) or the like.
+   [cvsps](http://www.cobite.com/cvsps/), and
+   [cvsweb](http://www.freebsd.org/projects/cvsweb.html) or the like.
 7. Adjust CVS-related parameters in your setup file.
 
-Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn't need it, but you yourself might. Here's a good general-purpose one:
+Consider creating `$HOME/.cvsrc` if you don't have one already; the
+plugin doesn't need it, but you yourself might. Here's a good
+general-purpose one:
 
     cvs -q
     checkout -P
@@ -17,12 +21,25 @@ Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn
 
 ### Implementation details
 * [[ikiwiki-makerepo]]:
- * creates a repository,
- * imports `$SRCDIR` into top-level module `ikiwiki` (vendor tag IKIWIKI, release tag PRE_CVS),
- * configures the post-commit hook in `CVSROOT/loginfo`.
+    * creates a repository,
+    * imports `$SRCDIR` into top-level module `ikiwiki` (vendor tag
+      IKIWIKI, release tag PRE_CVS),
+    * configures the post-commit hook in `CVSROOT/loginfo`.
 
 ### To do
-* Have `ikiwiki-makerepo` set up NetBSD-like `log_accum` and `commit_prep` scripts that coalesce commits into changesets. Reasons:
-    7. Obviates the need to scrape the repo's complete history to determine the last N changesets. (Repositories without such records can fall back on the `cvsps` and `File::ReadBackwards` code.)
-    7. Arranges for ikiwiki to be run once per changeset, rather than CVS's once per committed file (!), which is a waste at best and bug-inducing at worst. (Currently, on multi-directory commits, only the first directory's changes get mentioned in [[recentchanges|plugins/recentchanges]].)
-* Perhaps prevent web edits from attempting to create `.../CVS/foo.mdwn` (and `.../cvs/foo.mdwn` on case-insensitive filesystems); thanks to the CVS metadata directory, the attempt will fail anyway (and much more confusingly) if we don't.
+* Expand test coverage and fix bugs.
+* Have `ikiwiki-makerepo` set up NetBSD-like `log_accum` and
+  `commit_prep` scripts that coalesce commits into changesets. Reasons:
+    7. Obviates the need to scrape the repo's complete history to
+       determine the last N changesets. (Repositories without such
+       records can fall back on the `cvsps` and `File::ReadBackwards`
+       code.)
+    7. Arranges for ikiwiki to be run once per changeset, rather
+       than CVS's once per committed file (!), which is a waste at
+       best and bug-inducing at worst. (Currently, on multi-directory
+       commits, only the first directory's changes get mentioned
+       in [[recentchanges|plugins/recentchanges]].)
+* Perhaps prevent web edits from attempting to create `.../CVS/foo.mdwn`
+  (and `.../cvs/foo.mdwn` on case-insensitive filesystems); thanks
+  to the CVS metadata directory, the attempt will fail anyway (and
+  much more confusingly) if we don't.
index 645b2388be1b54ee15042b8abede429488bcadee..e10892e7d5645c93c62bc768446c85f442c113ab 100644 (file)
@@ -147,3 +147,26 @@ short and clear as possible. --[[schmonz]]
 > that. --[[Joey]]
 
 >> Done. --[[schmonz]].
+
+----
+
+I'm attempting to bring some polish to this plugin, starting with
+fuller test coverage. In preparation, I've refactored the tests a
+bunch (and shuffled the code a bit) in my branch. I'm worried,
+however, that my misunderstanding of `git rebase` may have made my
+branch harder for you to pull.
+
+Before I go writing a whole swack of test cases, could you merge
+my latest? Through at least ad0e56cdcaaf76bc68d1b5c56e6845307b51c44a
+there should be no functional change. --[[schmonz]]
+
+Never mind, I was able to convince myself (by cloning `origin`
+afresh and merging from `schmonz/cvs`). The history is a little
+gross but the before-and-after diff looks right.
+
+Bugs found and fixed so far:
+
+* Stop treating text files as binary (`-kb`) on `rcs_add()`
+   (ac8eab29e8394aca4c0b23a6687ec947ea1ac869)
+
+> Merged to current head. --[[Joey]] 
diff --git a/doc/sandbox/Test_it.mdwn b/doc/sandbox/Test_it.mdwn
new file mode 100644 (file)
index 0000000..5478d7a
--- /dev/null
@@ -0,0 +1 @@
+Test it just now!
index ecd73f52c38a2c612b07ec2ab76e9c1d27e235e6..07210f9bfe88092cdcfd5a09c66f37923653cbcb 100644 (file)
@@ -15,7 +15,7 @@ This page controls what shortcut links the wiki supports.
 * [[!shortcut name=archive url="http://web.archive.org/*/%S"]]
 * [[!shortcut name=gmap url="https://maps.google.com/maps?q=%s"]]
 * [[!shortcut name=gmsg url="https://groups.google.com/groups?selm=%s"]]
-* [[!shortcut name=wikipedia url="https://en.wikimedia.org/wiki/%s"]]
+* [[!shortcut name=wikipedia url="https://en.wikipedia.org/wiki/%s"]]
 * [[!shortcut name=wikitravel url="https://wikitravel.org/en/%s"]]
 * [[!shortcut name=wiktionary url="https://en.wiktionary.org/wiki/%s"]]
 * [[!shortcut name=debbug url="http://bugs.debian.org/%S" desc="Debian bug #%s"]]
index 5d5647e9b9529fcb99cd357b2bd0396b2076a4c2..de3230c9ed8a46ff192aaa709dab203f3daf2af7 100644 (file)
@@ -25,4 +25,9 @@ support of the C implementation of Markdown called
 >>> (Upskirt, discount... Who comes up with these names? Discount also 
 >>> features a "NOPANTS" option.) --[[Joey]]
 
+>>>> Thanks for doing this; it's given a well-needed speedup to my huge site.
+>>>>
+>>>> (At least "Discount" is related to "Mark Down" but I don't fathom "Upskirt" either.)
+>>>> --[[KathrynAndersen]]
+
 [[wishlist]]
index 1494fed7a606fc4984d5ff279dfebabd46576d33..358185a22675ce25240f9aa2249133e9d261714c 100644 (file)
@@ -6,3 +6,84 @@ Lots of \[[!img ]] (~2200), lots of \[[!teximg ]] (~2700). A complete rebuild ta
 We could use a big machine, with plenty of CPUs. Could some multi-threading support be added to ikiwiki, by forking out all the external heavy  plugins (imagemagick, tex, ...) and/or by processing pages in parallel?
 
 Disclaimer: I know nothing of the Perl approach to parallel processing.
+
+> I agree that it would be lovely to be able to use multiple processors to speed up rebuilds on big sites (I have a big site myself), but, taking a quick look at what Perl threads entails, and taking into acount what I've seen of the code of IkiWiki, it would take a massive rewrite to make IkiWiki thread-safe - the API would have to be completely rewritten - and then more work again to introduce threading itself.  So my unofficial humble opinion is that it's unlikely to be done.
+> Which is a pity, and I hope I'm mistaken about it.
+> --[[KathrynAndersen]]
+
+> > I have much less experience with the internals of Ikiwiki, much
+> > less Multi-threading perl, but I agree that to make Ikiwiki thread
+> > safe and to make the modifications to really take advantage of the
+> > threads is probably beyond the realm of reasonable
+> > expectations. Having said that, I wonder if there aren't ways to
+> > make Ikiwiki perform better for these big cases where the only
+> > option is to wait for it to grind through everything. Something
+> > along the lines of doing all of the aggregation and dependency
+> > heavy stuff early on, and then doing all of the page rendering
+> > stuff at the end quasi-asynchronously? Or am I way off in the deep
+> > end.
+> >
+> > From a practical perspective, it seems like these massive rebuild
+> > situations represent a really small subset of ikiwiki builds. Most
+> > sites are pretty small, and most sites need full rebuilds very
+> > very infrequently. In that scope, 10 minute rebuilds aren't that
+> > bad seeming. In terms of performance challenges, it's the one page
+> > with 3-5 dependency that takes 10 seconds (say) to rebuild that's
+> > a larger challenge for Ikiwiki as a whole. At the same time, I'd
+> > be willing to bet that performance benefits for these really big
+> > repositories for using fast disks (i.e. SSDs) could probably just
+> > about meet the benefit of most of the threading/async work.
+> >
+> > --[[tychoish]]
+
+>>> It's at this point that doing profiling for a particular site would come
+>>> in, because it would depend on the site content and how exactly IkiWiki is
+>>> being used as to what the performance bottlenecks would be.  For the
+>>> original poster, it would be image processing.  For me, it tends to be
+>>> PageSpecs, because I have a lot of maps and reports.
+
+>>> But I sincerely don't think that Disk I/O is the main bottleneck, not when
+>>> the original poster mentions CPU usage, and also in my experience, I see
+>>> IkiWiki chewing up 100% CPU usage one CPU, while the others remain idle.  I
+>>> haven't noticed slowdowns due to waiting for disk I/O, whether that be a
+>>> system with HD or SSD storage.
+
+>>> I agree that large sites are probably not the most common use-case, but it
+>>> can be a chicken-and-egg situation with large sites and complete rebuilds,
+>>> since it can often be the case with a large site that rebuilding based on
+>>> dependencies takes *longer* than rebuilding the site from scratch, simply
+>>> because there are so many pages that are interdependent.  It's not always
+>>> the number of pages itself, but how the site is being used.  If IkiWiki is
+>>> used with the absolute minimum number of page-dependencies - that is, no
+>>> maps, no sitemaps, no trails, no tags, no backlinks, no albums - then one
+>>> can have a very large number of pages without having performance problems.
+>>> But when you have a change in PageA affecting PageB which affects PageC,
+>>> PageD, PageE and PageF, then performance can drop off horribly.  And it's a
+>>> trade-off, because having features that interlink pages automatically is
+>>> really nifty ad useful - but they have a price.
+
+>>> I'm not really sure what the best solution is.  Me, I profile my IkiWiki builds and try to tweak performance for them... but there's only so much I can do.
+>>> --[[KathrynAndersen]]
+
+>>>> IMHO, the best way to get a multithreaded ikiwiki is to rewrite it
+>>>> in haskell, using as much pure code as possible. Many avenues
+>>>> then would open up to taking advantage of haskell's ability to
+>>>> parallize pure code.
+>>>>
+>>>> With that said, we already have some nice invariants that could be
+>>>> used to parallelize page builds. In particular, we know that
+>>>> page A never needs state built up while building page B, for any
+>>>> pages A and B that don't have a dependency relationship -- and ikiwiki
+>>>> tracks such dependency relationships, although not currently in a form
+>>>> that makes it very easy (or fast..) to pick out such groups of
+>>>> unrelated pages.
+>>>> 
+>>>> OTOH, there are problems.. building page A can result in changes to
+>>>> ikiwiki's state; building page B can result in other changes. All
+>>>> such changes would have to be made thread-safely. And would the
+>>>> resulting lock contention result in a program that ran any faster
+>>>> once parallelized?
+>>>> 
+>>>> Which is why [[rewrite_ikiwiki_in_haskell]], while pretty insane, is
+>>>> something I keep thinking about. If only I had a spare year..
+>>>> --[[Joey]]
index 48ed744b165c045aee15635de6465ea05f9ef648..e48765b0e14802bcef48b8dc33e7ce82607c569a 100644 (file)
@@ -62,8 +62,4 @@ Some other things to be scared about:
   a bunch of haskell libraries. OTOH, it might be possible to build a
   static binary at home and upload it, thus avoiding a messy installation
   procedure entirely.
-* I can barely code in haskell yet. I'm probably about 100x faster at
-  programming in perl. I need to get some more practical experience before
-  I´m fast and seasoned enough in haskell to attempt such a project.
-  (And so far, progress at learning has been slow and I have not managed
-  to write anything serious in haskell.) --[[Joey]] 
+  --[[Joey]] 
index 1edebe4e8f01556e4381515499647571de5afcce..01910a97cbebbe428dfef8c9f9b481025f363ccb 100644 (file)
@@ -12,3 +12,44 @@ Congratulations for demonstrating that April fools jokes can still be subtle
 >>> It doesn't really. I recently (re-)read about couchdb and thought that
 >>> what it was trying to do had some comparisons with the thinking going on
 >>> in [[todo/structured_page_data]]. -- [[Jon]]
+
+-----
+
+I'm torn about this idea, if it's actually serious.  I'm very comfortable
+programming in Perl, and have written quite a few modules for IkiWiki, and
+it would be a huge pain to have to start from scratch all over again. On
+the other hand, this could be a motivation for me to learn Haskell.  My
+only encounter with Haskell has been a brief time when I was using the
+Xmonad window manager, but it looks like an interesting language.
+Functional programming is cool.
+
+There are a lot of interesting plusses for Haskell you note (in the parent
+page), but it's true that the idea is horribly daunting (as [[Joey]] said
+"If only I had a spare year").  Is there any way that you could "start
+small"?  Because nothing will ever happen if the task is too daunting to
+even start.
+
+> This seems destined to remain a thought experiment unless something like
+> that can be done, or I get a serious case of second system disease.
+> 
+> I've considered doing things like using the external plugin interface
+> to run a separate haskell program, which would allow implementing
+> arbitrary plugins in haskell (starting with a pandoc plugin..),
+> and could perhaps grow to subsume the perl code. However, this would
+> stick us with the perl data structures, which are not a very good fit
+> for haskell. --[[Joey]]
+
+On further thought... perhaps it would be easier to fork or contribute to
+an existing Haskell-based wiki, such as <a
+href="http://jaspervdj.be/hakyll">Hakyll</a>?
+
+--[[KathrynAndersen]]
+
+> As far as I know there are no other wikis (haskell or otherwise)
+> that are wiki compilers. Since we know from experience that dealing
+> with static compilation turns out to be one of the trickiest parts of
+> ikiwiki, I'm doubtful about trying to bolt that into one. --[[Joey]] 
+
+>> Haykll isn't a wiki but it does do static compilation. The missing
+>> parts are: the web interface, the wiki link processing, and page
+>> dependency stuff. -- [[tychoish]]
index 56a11ce0ba91e9b90efb6eea975c50f5429a7323..d6a7edb03c43a7483445a0306941892170d73308 100644 (file)
@@ -11,5 +11,5 @@ Other people had experience with this? Or other suggestions on how to publish re
 
 > Ikiwiki does not support git submodules. 
 > 
-> You can use the [[ikiwiki/plugin/underlay]] plugin to merge the
+> You can use the [[plugins/underlay]] plugin to merge the
 > contents of other directories into your wiki's source. --[[Joey]] 
index ebfcf3cdd6356d9ae71b3bc946162eb3efcecbc8..fc7558b240a3b9228f6a937babe1afca9ec77a58 100644 (file)
@@ -1,5 +1,5 @@
-[Amitai Schlair](http://www.netbsd.org/~schmonz/) finds himself
-using ikiwiki for all sorts of things. His attempts at contributing:
+[Amitai Schlair](http://www.schmonz.com/) finds himself using ikiwiki
+for all sorts of things. His attempts at contributing:
 
 [[!map
 pages="!*/Discussion and ((link(users/schmonz) and plugins/*) or rcs/cvs)"
index adff1411e8aa715a192f3850a7aef59f4cd04f0b..e6b64f43949aba391a411c31b1cf57a0c8b56c2e 100755 (executable)
@@ -108,11 +108,9 @@ sub getconfig () {
                                if (! defined $var || ! defined $val) {
                                        die gettext("usage: --set-yaml var=value"), "\n";
                                }
-                               eval q{use YAML::Any};
-                               eval q{use YAML} if $@;
+                               eval q{use YAML::XS; use Encode};
                                die $@ if $@;
-                               eval q{$YAML::Syck::ImplicitUnicode=1};
-                               $config{$var}=Load($val."\n");
+                               $config{$var}=Load(encode_utf8($val)."\n");
                        },
                        "version" => sub {
                                print "ikiwiki version $IkiWiki::version\n";
index 675d29864db08a4e5614aa4a3c4539668827bc0d..fff50b7409950d1befa965f3c82aa41774e4358a 100644 (file)
@@ -1,5 +1,5 @@
 Name:           ikiwiki
-Version: 3.20111229
+Version: 3.20120115
 Release:        1%{?dist}
 Summary:        A wiki compiler
 
index 047371251f9c8e0577eb89e9ec9277decc9e44be..416625a3078cf779921c4c89f55369ed9bf7f509 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-12-29 12:03-0400\n"
+"POT-Creation-Date: 2012-01-15 16:40-0400\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -171,15 +171,15 @@ msgstr ""
 msgid "bad attachment filename"
 msgstr ""
 
-#: ../IkiWiki/Plugin/attachment.pm:295
+#: ../IkiWiki/Plugin/attachment.pm:296
 msgid "attachment upload"
 msgstr ""
 
-#: ../IkiWiki/Plugin/attachment.pm:346
+#: ../IkiWiki/Plugin/attachment.pm:347
 msgid "this attachment is not yet saved"
 msgstr ""
 
-#: ../IkiWiki/Plugin/attachment.pm:363
+#: ../IkiWiki/Plugin/attachment.pm:365
 msgid "just uploaded"
 msgstr ""
 
@@ -508,7 +508,7 @@ msgstr ""
 msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
 msgstr ""
 
-#: ../IkiWiki/Plugin/mdwn.pm:70
+#: ../IkiWiki/Plugin/mdwn.pm:88
 #, perl-format
 msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
 msgstr ""
diff --git a/t/cvs.t b/t/cvs.t
index 5ed377ed5e7234b369cc456d814e4ceefb51266c..1c20d7741343dd4ae668ff879909b024f4eb4d6d 100755 (executable)
--- a/t/cvs.t
+++ b/t/cvs.t
 #!/usr/bin/perl
 use warnings;
 use strict;
-my $dir;
-BEGIN {
-       $dir="/tmp/ikiwiki-test-cvs.$$";
-       my $cvs=`which cvs`;
-       chomp $cvs;
-       my $cvsps=`which cvsps`;
-       chomp $cvsps;
-       if (! -x $cvs || ! -x $cvsps) {
-               eval q{
-                       use Test::More skip_all => "cvs or cvsps not available"
-               }
-       }
-       if (! mkdir($dir)) {
-               die $@;
+use Test::More; my $total_tests = 40;
+use IkiWiki;
+
+my $default_test_methods = '^test_*';
+my @required_programs = qw(
+       cvs
+       cvsps
+);
+my @required_modules = qw(
+       File::chdir
+       File::MimeInfo
+       Date::Parse
+       File::Temp
+       File::ReadBackwards
+);
+my $dir = "/tmp/ikiwiki-test-cvs.$$";
+
+# TESTS FOR GENERAL META-BEHAVIOR
+
+sub test_web_comments {
+       # how much of the web-edit workflow are we actually testing?
+       # because we want to test comments:
+       # - when the first comment for page.mdwn is added, and page/ is
+       #   created to hold the comment, page/ isn't added to CVS control,
+       #   so the comment isn't either
+       # - side effect for moderated comments: after approval they
+       #   show up normally AND are still pending, too
+       # - comments.pm treats rcs_commit_staged() as returning conflicts?
+}
+
+sub test_chdir_magic {
+       # cvs.pm operations are always occurring inside $config{srcdir}
+       # other ikiwiki operations are occurring wherever, and are unaffected
+       # when are we bothering with "local $CWD" and when aren't we?
+}
+
+sub test_cvs_info {
+       # inspect "Repository revision" (used in code)
+       # inspect "Sticky Options" (used in tests to verify existence of "-kb")
+}
+
+sub test_cvs_run_cvs {
+       # extract the stdout-redirect thing
+       # - prove that it silences stdout
+       # - prove that stderr comes through just fine
+       # prove that when cvs exits nonzero (fail), function exits false
+       # prove that when cvs exits zero (success), function exits true
+       # always pass -f, just in case
+       # steal from git.pm: safe_git(), run_or_{die,cry,non}
+       # - open() instead of system()
+       # always call cvs_run_cvs(), don't ever run 'cvs' directly
+}
+
+sub test_cvs_run_cvsps {
+       # parameterize command like run_cvs()
+       # expose config vars for e.g. "--cvs-direct -z 30"
+       # always pass -x (unless proven otherwise)
+       # always pass -b HEAD (configurable like gitmaster_branch?)
+}
+
+sub test_cvs_parse_cvsps {
+       # extract method from rcs_recentchanges
+       # document expected changeset format
+       # document expected changeset delimiter
+       # try: cvsps -q -x -p && ls | sort -rn | head -100
+       # - benchmark against current impl (that uses File::ReadBackwards)
+}
+
+sub test_cvs_parse_log_accum {
+       # add new, preferred method for rcs_recentchanges to use
+       # teach log_accum to record commits (into transient?)
+       # script cvsps to bootstrap (or replace?) commit history
+       # teach ikiwiki-makerepo to set up log_accum and commit_prep
+       # why are NetBSD commit mails unreliable?
+       # - is it working for CVS commits and failing for web commits?
+}
+
+sub test_cvs_is_controlling {
+       # with no args:
+       # - if srcdir is in CVS, return true
+       # - else, return false
+       # with a dir arg:
+       # - if dir is in CVS, return true
+       # - else, return false
+       # with a file arg:
+       # - is there anything that wants the answer? if so, answer
+       # - else, die
+}
+
+
+# TESTS FOR GENERAL PLUGIN API CALLS
+
+sub test_checkconfig {
+       # undef cvspath, expect "ikiwiki"
+       # define cvspath normally, get it back
+       # define cvspath in a subdir, get it back?
+       # define cvspath with extra slashes, get sanitized version back
+       # - yoink test_extra_path_slashes
+       # undef cvs_wrapper, expect $config{wrappers} same size as before
+
+       my $initial_cvspath = $config{cvspath};
+       $config{cvspath} = "/ikiwiki//";
+       IkiWiki::checkconfig();
+       is(
+               $config{cvspath},
+               $initial_cvspath,
+               q{rcs_recentchanges assumes checkconfig has sanitized cvspath},
+       );
+}
+
+sub test_getsetup {
+       # anything worth testing?
+}
+
+sub test_genwrapper {
+       # testable directly? affects rcs_add, but are we exercising this?
+}
+
+
+# TESTS FOR VCS PLUGIN API CALLS
+
+sub test_rcs_update {
+       # can it assume we're under CVS control? or must it check?
+       # anything else worth testing?
+}
+
+sub test_rcs_prepedit {
+       # can it assume we're under CVS control? or must it check?
+       # for existing file, returns latest revision in repo
+       # - what's this used for? should it return latest revision in checkout?
+       # for new file, returns empty string
+}
+
+sub test_rcs_commit {
+       # can it assume we're under CVS control? or must it check?
+       # if someone else changed the page since rcs_prepedit was called:
+       # - try to merge into our working copy
+       # - if merge succeeds, proceed to commit
+       # - else, return page content with the conflict markers in it
+       # commit:
+       # - if success, return undef
+       # - else, revert + return content with the conflict markers in it
+       # git.pm receives "session" param -- useful here?
+       # web commits start with "web commit {by,from} "
+       # seeing File::chdir errors on commit?
+}
+
+sub test_rcs_commit_staged {
+       # if commit succeeds, return undef
+       # else, warn and return error message (really? or just non-undef?)
+}
+
+sub test_rcs_add {
+       my $message = "add a top-level ASCII (non-UTF-8) page via VCS API";
+       writefile('test0.mdwn', $config{srcdir}, "* some plain ASCII text");
+       IkiWiki::rcs_add("test0.mdwn");
+       IkiWiki::rcs_commit(
+               file => "test0.mdwn",
+               message => $message,
+               token => "moo",
+       );
+       is_newly_added("test0.mdwn");
+       is_in_keyword_substitution_mode("test0.mdwn", undef);
+       my @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 1);
+       is_most_recent_change(\@changes, "test0", $message);
+
+       $message = "add a top-level dir via VCS API";
+       my $dir1 = "test3";
+       can_mkdir($dir1);
+       IkiWiki::rcs_add($dir1);
+       # XXX test that the wrapper hangs here without our genwrapper()
+       # XXX test that the wrapper doesn't hang here with it
+       @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 1);       # despite the dir add
+       IkiWiki::rcs_commit(
+               file => $dir1,
+               message => $message,
+               token => "oom",
+       );
+       @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 1);       # dirs aren't tracked
+
+       $message = "add a non-ASCII (UTF-8) text file in an un-added dir";
+       my $dir2 = "test4/test5";
+       can_mkdir($_) for ('test4', $dir2);
+       writefile("$dir2/test1.mdwn", $config{srcdir},readfile("t/test1.mdwn"));
+       IkiWiki::rcs_add("$dir2/test1.mdwn");
+       IkiWiki::rcs_commit(
+               file => "$dir2/test1.mdwn",
+               message => $message,
+               token => "omo",
+       );
+       is_newly_added("$dir2/test1.mdwn");
+       is_in_keyword_substitution_mode("$dir2/test1.mdwn", undef);
+       @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 2);
+       is_most_recent_change(\@changes, "$dir2/test1", $message);
+
+       $message = "add a binary file in an un-added dir, and commit_staged";
+       my $dir3 = "test6";
+       my $file = "$dir3/test7.ico";
+       can_mkdir($dir3);
+       my $bindata_in = readfile("doc/favicon.ico", 1);
+       my $bindata_out = sub { readfile($config{srcdir} . "/$file", 1) };
+       writefile($file, $config{srcdir}, $bindata_in, 1);
+       is(&$bindata_out(), $bindata_in, q{binary files match before commit});
+       IkiWiki::rcs_add($file);
+       IkiWiki::rcs_commit_staged(message => $message);
+       is_newly_added($file);
+       is_in_keyword_substitution_mode($file, q{-kb});
+       is(&$bindata_out(), $bindata_in, q{binary files match after commit});
+       @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 3);
+       is_most_recent_change(\@changes, $file, $message);
+       ok(
+               unlink($config{srcdir} . "/$file"),
+               q{can remove file in order to re-fetch it from repo},
+       );
+       ok(! -e $config{srcdir} . "/$file", q{really removed file});
+       IkiWiki::rcs_update();
+       is(&$bindata_out(), $bindata_in, q{binary files match after re-fetch});
+
+       $message = "add a UTF-8 and a binary file in different dirs";
+       my $file1 = "test8/test9.mdwn";
+       my $file2 = "test10/test11.ico";
+       can_mkdir(qw(test8 test10));
+       writefile($file1, $config{srcdir}, readfile('t/test2.mdwn'));
+       writefile($file2, $config{srcdir}, $bindata_in, 1);
+       IkiWiki::rcs_add($_) for ($file1, $file2);
+       IkiWiki::rcs_commit_staged(message => $message);
+       is_newly_added($_) for ($file1, $file2);
+       is_in_keyword_substitution_mode($file1, undef);
+       is_in_keyword_substitution_mode($file2, '-kb');
+       @changes = IkiWiki::rcs_recentchanges(3);
+       is_total_number_of_changes(\@changes, 3);
+       @changes = IkiWiki::rcs_recentchanges(4);
+       is_total_number_of_changes(\@changes, 4);
+       # XXX test for both files in the commit, and no other files
+       is_most_recent_change(\@changes, $file2, $message);
+
+       # prevent web edits from attempting to create .../CVS/foo.mdwn
+       # on case-insensitive filesystems, also prevent .../cvs/foo.mdwn
+       # unless your "CVS" is something else and we've made it configurable
+
+       # can it assume we're under CVS control? or must it check?
+
+       # extract method: filetype-guessing
+       # add a binary file, remove it, add a text file by same name, no -kb?
+       # add a text file, remove it, add a binary file by same name, -kb?
+}
+
+sub test_rcs_remove {
+       # can it assume we're under CVS control? or must it check?
+       # remove a top-level file
+       # - rcs_commit
+       # - inspect recentchanges: one new change, file removed
+       # remove two files (in different dirs)
+       # - rcs_commit_staged
+       # - inspect recentchanges: one new change, both files removed
+}
+
+sub test_rcs_rename {
+       # can it assume we're under CVS control? or must it check?
+       # rename a file in the same dir
+       # - rcs_commit_staged
+       # - inspect recentchanges: one new change, one file removed, one added
+       # rename a file into a different dir
+       # - rcs_commit_staged
+       # - inspect recentchanges: one new change, one file removed, one added
+       # rename a file into a not-yet-existing dir
+       # - rcs_commit_staged
+       # - inspect recentchanges: one new change, one file removed, one added
+       # is it safe to use "mv"? what if $dest is somehow outside the wiki?
+}
+
+sub test_rcs_recentchanges {
+       my $message = "Add a page via CVS directly";
+       writefile('test2.mdwn', $config{srcdir}, readfile("t/test2.mdwn"));
+       system "cd $config{srcdir}"
+               . " && cvs add test2.mdwn >/dev/null 2>&1";
+       system "cd $config{srcdir}"
+               . " && cvs commit -m \"$message\" test2.mdwn >/dev/null";
+
+       my @changes = IkiWiki::rcs_recentchanges(3);
+       is(
+               $#changes,
+               0,
+               q{total commits: 1},
+       );
+       is(
+               $changes[0]{message}[0]{"line"},
+               $message,
+               q{most recent commit's first message line matches},
+       );
+       is(
+               $changes[0]{pages}[0]{"page"},
+               "test2",
+               q{most recent commit's first pagename matches},
+       );
+
+       # CVS commits run ikiwiki once for every committed file (!)
+       # - commit_prep alone should fix this
+       # CVS multi-dir commits show only the first dir in recentchanges
+       # - commit_prep might also fix this?
+       # CVS post-commit hook is amped off to avoid locking against itself
+       # - commit_prep probably doesn't fix this... but maybe?
+       # can it assume we're under CVS control? or must it check?
+       # don't worry whether we're called with a number (we always are)
+       # other rcs tests already inspect much of the returned structure
+       # CVS commits say "cvs" and get the right committer
+       # web commits say "web" and get the right committer
+       # - and don't start with "web commit {by,from} "
+       # "nickname" -- can we ever meaningfully set this?
+
+       # prefer log_accum, then cvsps, else die
+       # run the high-level recentchanges tests 2x (once for each method)
+       # - including in other test subs that check recentchanges?
+}
+
+sub test_rcs_diff {
+       # can it assume we're under CVS control? or must it check?
+       # in list context, return all lines (with \n), up to $maxlines if set
+       # in scalar context, return the whole diff, up to $maxlines if set
+}
+
+sub test_rcs_getctime {
+       # can it assume we're under CVS control? or must it check?
+       # given a file, find its creation time, else return 0
+       # first implement in the obvious way
+       # then cache
+}
+
+sub test_rcs_getmtime {
+       # can it assume we're under CVS control? or must it check?
+       # given a file, find its modification time, else return 0
+       # first implement in the obvious way
+       # then cache
+}
+
+sub test_rcs_receive {
+       pass(q{rcs_receive doesn't make sense for CVS});
+}
+
+sub test_rcs_preprevert {
+       # can it assume we're under CVS control? or must it check?
+       # given a patchset number, return structure describing what'd happen:
+       # - see doc/plugins/write.mdwn:rcs_receive()
+       # don't forget about attachments
+}
+
+sub test_rcs_revert {
+       # can it assume we're under CVS control? or must it check?
+       # given a patchset number, stage the revert for rcs_commit_staged()
+       # if commit succeeds, return undef
+       # else, warn and return error message (really? or just non-undef?)
+}
+
+sub main {
+       my $test_methods = defined $ENV{TEST_METHOD} 
+                        ? $ENV{TEST_METHOD}
+                        : $default_test_methods;
+
+       _startup($test_methods eq $default_test_methods);
+       _runtests(_get_matching_test_subs($test_methods));
+       _shutdown($test_methods eq $default_test_methods);
+}
+
+main();
+
+
+# INTERNAL SUPPORT ROUTINES
+
+sub _plan_for_test_more {
+       my $can_plan = shift;
+
+       foreach my $program (@required_programs) {
+               my $program_path = `which $program`;
+               chomp $program_path;
+               return plan(skip_all => "$program not available")
+                       unless -x $program_path;
        }
-       foreach my $module ('File::ReadBackwards', 'File::MimeInfo') {
+
+       foreach my $module (@required_modules) {
                eval qq{use $module};
-               if ($@) {
-                       eval qq{
-                               use Test::More skip_all => "$module not available"
-                       }
-               }
+               return plan(skip_all => "$module not available")
+                       if $@;
        }
+
+       return plan(skip_all => "can't create $dir: $!")
+               unless mkdir($dir);
+       return plan(skip_all => "can't remove $dir: $!")
+               unless rmdir($dir);
+
+       return unless $can_plan;
+
+       return plan(tests => $total_tests);
+}
+
+# http://stackoverflow.com/questions/607282/whats-the-best-way-to-discover-all-subroutines-a-perl-module-has
+
+use B qw/svref_2object/;
+
+sub in_package {
+       my ($coderef, $package) = @_;
+       my $cv = svref_2object($coderef);
+       return if not $cv->isa('B::CV') or $cv->GV->isa('B::SPECIAL');
+       return $cv->GV->STASH->NAME eq $package;
+}
+
+sub list_module {
+       my $module = shift;
+       no strict 'refs';
+       return grep {
+               defined &{"$module\::$_"} and in_package(\&{*$_}, $module)
+       } keys %{"$module\::"};
 }
-use Test::More tests => 12;
-
-BEGIN { use_ok("IkiWiki"); }
-
-%config=IkiWiki::defaultconfig();
-$config{rcs} = "cvs";
-$config{srcdir} = "$dir/src";
-$config{cvsrepo} = "$dir/repo";
-$config{cvspath} = "ikiwiki";
-IkiWiki::loadplugins();
-IkiWiki::checkconfig();
-
-my $cvsrepo = "$dir/repo";
-
-system "cvs -d $cvsrepo init >/dev/null";
-system "mkdir $dir/ikiwiki >/dev/null";
-system "cd $dir/ikiwiki && cvs -d $cvsrepo import -m import ikiwiki VENDOR RELEASE >/dev/null";
-system "rm -rf $dir/ikiwiki >/dev/null";
-system "cvs -d $cvsrepo co -d $config{srcdir} ikiwiki >/dev/null";
-
-# Web commit
-my $test1 = readfile("t/test1.mdwn");
-writefile('test1.mdwn', $config{srcdir}, $test1);
-IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit(
-       files => "test1.mdwn",
-       message => "Added the first page",
-       token => "moo"
-);
 
-my @changes;
-@changes = IkiWiki::rcs_recentchanges(3);
-
-is($#changes, 0);
-is($changes[0]{message}[0]{"line"}, "Added the first page");
-is($changes[0]{pages}[0]{"page"}, "test1");
-
-# Manual commit
-my $message = "Added the second page";
-
-my $test2 = readfile("t/test2.mdwn");
-writefile('test2.mdwn', $config{srcdir}, $test2);
-system "cd $config{srcdir} && cvs add test2.mdwn >/dev/null 2>&1";
-system "cd $config{srcdir} && cvs commit -m \"$message\" test2.mdwn >/dev/null";
-
-@changes = IkiWiki::rcs_recentchanges(3);
-is($#changes, 1);
-is($changes[0]{message}[0]{"line"}, $message);
-is($changes[0]{pages}[0]{"page"}, "test2");
-is($changes[1]{pages}[0]{"page"}, "test1");
-
-# extra slashes in the path shouldn't break things
-$config{cvspath} = "/ikiwiki//";
-IkiWiki::checkconfig();
-@changes = IkiWiki::rcs_recentchanges(3);
-is($#changes, 1);
-is($changes[0]{message}[0]{"line"}, $message);
-is($changes[0]{pages}[0]{"page"}, "test2");
-is($changes[1]{pages}[0]{"page"}, "test1");
-
-system "rm -rf $dir";
+
+# support for xUnit-style testing, a la Test::Class
+
+sub _startup {
+       my $can_plan = shift;
+       _plan_for_test_more($can_plan);
+       _generate_test_config();
+}
+
+sub _shutdown {
+       my $had_plan = shift;
+       done_testing() unless $had_plan;
+}
+
+sub _setup {
+       _generate_test_repo();
+}
+
+sub _teardown {
+       system "rm -rf $dir";
+}
+
+sub _runtests {
+       my @coderefs = (@_);
+       for (@coderefs) {
+               _setup();
+               $_->();
+               _teardown();
+       }
+}
+
+sub _get_matching_test_subs {
+       my $re = shift;
+       no strict 'refs';
+       return map { \&{*$_} } grep { /$re/ } sort(list_module('main'));
+}
+
+sub _generate_test_config {
+       %config = IkiWiki::defaultconfig();
+       $config{rcs} = "cvs";
+       $config{srcdir} = "$dir/src";
+       $config{cvsrepo} = "$dir/repo";
+       $config{cvspath} = "ikiwiki";
+       IkiWiki::loadplugins();
+       IkiWiki::checkconfig();
+}
+
+sub _generate_test_repo {
+       die "can't create $dir: $!"
+               unless mkdir($dir);
+
+       my $cvs = "cvs -d $config{cvsrepo}";
+       my $dn = ">/dev/null";
+       system "$cvs init $dn";
+       system "mkdir $dir/$config{cvspath} $dn";
+       system "cd $dir/$config{cvspath} && "
+               . "$cvs import -m import $config{cvspath} VENDOR RELEASE $dn";
+       system "rm -rf $dir/$config{cvspath} $dn";
+       system "$cvs co -d $config{srcdir} $config{cvspath} $dn";
+}
+
+sub can_mkdir {
+       my $dir = shift;
+       ok(
+               mkdir($config{srcdir} . "/$dir"),
+               qq{can mkdir $dir},
+       );
+}
+
+sub is_newly_added {
+       my $file = shift;
+       is(
+               IkiWiki::Plugin::cvs::cvs_info("Repository revision", $file),
+               '1.1',
+               qq{$file is newly added to CVS},
+       );
+}
+
+sub is_in_keyword_substitution_mode {
+       my ($file, $mode) = @_;
+       $mode = '(none)' unless defined $mode;
+       is(
+               IkiWiki::Plugin::cvs::cvs_info("Sticky Options", $file),
+               $mode,
+               qq{$file is in CVS with expected keyword substitution mode},
+       );
+}
+
+sub is_total_number_of_changes {
+       my ($changes, $expected_total) = @_;
+       is(
+               $#{$changes},
+               $expected_total - 1,
+               qq{total commits == $expected_total},
+       );
+}
+
+sub is_most_recent_change {
+       my ($changes, $page, $message) = @_;
+       is(
+               $changes->[0]{message}[0]{"line"},
+               $message,
+               q{most recent commit's first message line matches},
+       );
+       is(
+               $changes->[0]{pages}[0]{"page"},
+               $page,
+               q{most recent commit's first pagename matches},
+       );
+}