Merge branch 'master' of ssh://git.ikiwiki.info/srv/git/ikiwiki.info
authorJoey Hess <joey@kodama.kitenet.net>
Fri, 21 Mar 2008 18:53:41 +0000 (14:53 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Fri, 21 Mar 2008 18:53:41 +0000 (14:53 -0400)
IkiWiki.pm
debian/changelog
doc/ikiwiki-transition.mdwn
doc/index/discussion.mdwn
doc/tips/inside_dot_ikiwiki.mdwn [new file with mode: 0644]
ikiwiki-transition

index 221d1e589d1a977ec97648220e78804565e07be3..6847138211625853d85ab8982ab2de6ef8078abc 100644 (file)
@@ -7,6 +7,7 @@ use Encode;
 use HTML::Entities;
 use URI::Escape q{uri_escape_utf8};
 use POSIX;
+use Storable;
 use open qw{:utf8 :std};
 
 use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
@@ -896,39 +897,49 @@ sub loadindex () { #{{{
        %oldrenderedfiles=%pagectime=();
        if (! $config{rebuild}) {
                %pagesources=%pagemtime=%oldlinks=%links=%depends=
-                       %destsources=%renderedfiles=%pagecase=%pagestate=();
-       }
-       open (my $in, "<", "$config{wikistatedir}/index") || return;
-       while (<$in>) {
-               $_=possibly_foolish_untaint($_);
-               chomp;
-               my %items;
-               $items{link}=[];
-               $items{dest}=[];
-               foreach my $i (split(/ /, $_)) {
-                       my ($item, $val)=split(/=/, $i, 2);
-                       push @{$items{$item}}, decode_entities($val);
+               %destsources=%renderedfiles=%pagecase=%pagestate=();
+       }
+       my $in;
+       if (! open ($in, "<", "$config{wikistatedir}/indexdb")) {
+               if (-e "$config{wikistatedir}/index") {
+                       system("ikiwiki-transition", "indexdb", $config{srcdir});
+                       open ($in, "<", "$config{wikistatedir}/indexdb") || return;
                }
-
-               next unless exists $items{src}; # skip bad lines for now
-
-               my $page=pagename($items{src}[0]);
+               else {
+                       return;
+               }
+       }
+       my $ret=Storable::fd_retrieve($in);
+       if (! defined $ret) {
+               return 0;
+       }
+       my %index=%$ret;
+       foreach my $src (keys %index) {
+               my %d=%{$index{$src}};
+               my $page=pagename($src);
+               $pagectime{$page}=$d{ctime};
                if (! $config{rebuild}) {
-                       $pagesources{$page}=$items{src}[0];
-                       $pagemtime{$page}=$items{mtime}[0];
-                       $oldlinks{$page}=[@{$items{link}}];
-                       $links{$page}=[@{$items{link}}];
-                       $depends{$page}=$items{depends}[0] if exists $items{depends};
-                       $destsources{$_}=$page foreach @{$items{dest}};
-                       $renderedfiles{$page}=[@{$items{dest}}];
-                       $pagecase{lc $page}=$page;
-                       foreach my $k (grep /_/, keys %items) {
-                               my ($id, $key)=split(/_/, $k, 2);
-                               $pagestate{$page}{decode_entities($id)}{decode_entities($key)}=$items{$k}[0];
+                       $pagesources{$page}=$src;
+                       $pagemtime{$page}=$d{mtime};
+                       $renderedfiles{$page}=$d{dest};
+                       if (exists $d{links} && ref $d{links}) {
+                               $links{$page}=$d{links};
+                               $oldlinks{$page}=[@{$d{links}}];
+                       }
+                       if (exists $d{depends}) {
+                               $depends{$page}=$d{depends};
+                       }
+                       if (exists $d{state}) {
+                               $pagestate{$page}=$d{state};
                        }
                }
-               $oldrenderedfiles{$page}=[@{$items{dest}}];
-               $pagectime{$page}=$items{ctime}[0];
+               $oldrenderedfiles{$page}=[@{$d{dest}}];
+       }
+       foreach my $page (keys %pagesources) {
+               $pagecase{lc $page}=$page;
+       }
+       foreach my $page (keys %renderedfiles) {
+               $destsources{$_}=$page foreach @{$renderedfiles{$page}};
        }
        return close($in);
 } #}}}
@@ -938,39 +949,45 @@ sub saveindex () { #{{{
 
        my %hookids;
        foreach my $type (keys %hooks) {
-               $hookids{encode_entities($_)}=1 foreach keys %{$hooks{$type}};
+               $hookids{$_}=1 foreach keys %{$hooks{$type}};
        }
-       my @hookids=sort keys %hookids;
+       my @hookids=keys %hookids;
 
        if (! -d $config{wikistatedir}) {
                mkdir($config{wikistatedir});
        }
-       my $newfile="$config{wikistatedir}/index.new";
+       my $newfile="$config{wikistatedir}/indexdb.new";
        my $cleanup = sub { unlink($newfile) };
        open (my $out, '>', $newfile) || error("cannot write to $newfile: $!", $cleanup);
+       my %index;
        foreach my $page (keys %pagemtime) {
                next unless $pagemtime{$page};
-               my $line="mtime=$pagemtime{$page} ".
-                       "ctime=$pagectime{$page} ".
-                       "src=$pagesources{$page}";
-               $line.=" dest=$_" foreach @{$renderedfiles{$page}};
-               my %count;
-               $line.=" link=$_" foreach grep { ++$count{$_} == 1 } @{$links{$page}};
+               my $src=$pagesources{$page};
+
+               $index{$src}={
+                       ctime => $pagectime{$page},
+                       mtime => $pagemtime{$page},
+                       dest => $renderedfiles{$page},
+                       links => $links{$page},
+               };
+
                if (exists $depends{$page}) {
-                       $line.=" depends=".encode_entities($depends{$page}, " \t\n");
+                       $index{$src}{depends} = $depends{$page};
                }
+
                if (exists $pagestate{$page}) {
                        foreach my $id (@hookids) {
                                foreach my $key (keys %{$pagestate{$page}{$id}}) {
-                                       $line.=' '.$id.'_'.encode_entities($key, " \t\n")."=".encode_entities($pagestate{$page}{$id}{$key}, " \t\n");
+                                       $index{$src}{state}{$id}{$key}=$pagestate{$page}{$id}{$key};
                                }
                        }
                }
-               print $out $line."\n" || error("failed writing to $newfile: $!", $cleanup);
        }
+       my $ret=Storable::nstore_fd(\%index, $out);
+       return if ! defined $ret || ! $ret;
        close $out || error("failed saving to $newfile: $!", $cleanup);
-       rename($newfile, "$config{wikistatedir}/index") ||
-               error("failed renaming $newfile to $config{wikistatedir}/index", $cleanup);
+       rename($newfile, "$config{wikistatedir}/indexdb") ||
+               error("failed renaming $newfile to $config{wikistatedir}/indexdb", $cleanup);
        
        return 1;
 } #}}}
index 90b13ed7df191ba0c81d1cf63004c011ca673329..2169f310d2029b9d67fddc89c04b1ccd60e29715 100644 (file)
@@ -58,6 +58,7 @@ ikiwiki (2.41) UNRELEASED; urgency=low
   * smiley: Detect smileys inside pre and code tags, and do not expand.
   * inline: Crazy optimisation to work around slow markdown.
   * Precompile pagespecs, about 10% overall speedup.
+  * Changed to a binary index file, written using Storable, for speed.
 
  -- martin f. krafft <madduck@debian.org>  Sun, 02 Mar 2008 17:46:38 +0100
 
index 118050a6ce05c98c78c47261def9e223367826cc..da3b3a8d55a0cf3b8b03c87eaad9015b16fa7051 100644 (file)
@@ -4,7 +4,7 @@ ikiwiki-transition - transition ikiwiki pages to new syntaxes
 
 # SYNOPSIS
 
-ikiwiki-transition prefix_directives page.mdwn...
+ikiwiki-transition type ...
 
 # DESCRIPTION
 
@@ -12,8 +12,8 @@ ikiwiki-transition prefix_directives page.mdwn...
 there's a major change in ikiwiki syntax.
 
 Currently only one such transition is handled, the `prefix_directives` mode
-converts an ikiwiki page from the old preprocessor directive syntax,
-requiring a space, to the new syntax, prefixed by '!'.
+converts the specified ikiwiki page from the old preprocessor directive
+syntax, requiring a space, to the new syntax, prefixed by '!'.
 
 Preprocessor directives which already use the new syntax will remain
 unchanged.
@@ -22,6 +22,12 @@ Note that if the page contains wiki links with spaces, which some
 older versions of ikiwiki accepted, the prefix_directives transition will
 treat these as preprocessor directives and convert them.
 
+One other transition is handled, the `indexdb` mode handles converting
+a plain text `.ikiwiki/index` file to a binary `.ikiwiki/indexdb`. In this
+mode, you should specify the srcdir of the wiki as the second parameter.
+You do not normally need to run `ikiwiki-transition indexdb`; ikiwiki will
+automatically run it as necessary.
+
 # AUTHOR
 
 Josh Triplett <josh@freedesktop.org>
index df4e57aba7f1d3e0542516300875480b89fd080d..3d17ddb2a53e8ba5f1e1f284c874b87bf9a2049c 100644 (file)
@@ -337,42 +337,6 @@ Clicking on an old "?" or going to a create link but new Markdown content exists
 
 ----
 
-# User database tools?
-
-Any tool to view user database?
-
-Any tool to edit the user database?
-
-> No, but it's fairly easy to write such tools in perl. For example, to
-> list all users in the user database:
-
-       joey@kodama:~/src/joeywiki/.ikiwiki>perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); print $_ foreach keys %$userinfo'         
-       http://joey.kitenet.net/
-       foo
-
-> To list each user's email address:
-
-       joey@kodama:~/src/joeywiki/.ikiwiki>perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); print $userinfo->{$_}->{email} foreach keys %$userinfo'
-       
-       joey@kitenet.net
-
-> Editing is simply a matter of changing values and calling Storable::store().
-> I've not written actual utilities to do this yet because I've only needed
-> to do it rarely, and the data I've wanted has been different each time.
-> --[[Joey]]
-
->> Thanks for these examples -- I have been using them. I don't know the
->> Storable yet. Can someone share an example of removing a user? (I now
->> setup account\_creation\_password and I have some spammer with different
->> login names that I have banned that I might as well remove from the
->> userdb.)
-
->>> Let's see, you could do something like this:
->>>    perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); delete $$userinfo{"joey"}; Storable::lock_store($userinfo, "userdb")'
->>> I suppose I should stop being lame and create a command line tool wrapping up these operations.. --[[Joey]]
-
-----
-
 # Spaces in WikiLinks?
 
 Hello Joey,
diff --git a/doc/tips/inside_dot_ikiwiki.mdwn b/doc/tips/inside_dot_ikiwiki.mdwn
new file mode 100644 (file)
index 0000000..69083a9
--- /dev/null
@@ -0,0 +1,65 @@
+[[meta title="inside .ikiwiki"]]
+
+The `.ikiwiki` directory contains ikiwiki's internal state. Normally,
+you don't need to look in it, but here's some tips for how to do so if
+you need/want to.
+
+## the index
+
+`.ikiwiki/indexdb` contains a cache of information about pages, as well
+as all persisitant state about pages. It used to be a (semi) human-readable
+text file, but is not anymore.
+
+To dump the contents of the file, enter a perl command like this.
+
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $index=Storable::retrieve("indexdb"); use Data::Dumper; print Dumper $index' | head
+       $VAR1 = {
+          'index' => {
+                     'ctime' => 1199739528,
+                     'dest' => [
+                                 'index.html'
+                               ],
+                     'mtime' => 1199739528,
+                     'src' => 'index.mdwn',
+                     'links' => [
+                                  'index/discussion',
+
+## the user database
+
+`.ikiwiki/userdb` is the user database, which records preferences of all
+web users.
+
+To list all users in the database, enter a perl command like this.
+Note that the output can include both registered users, and known
+openids.
+
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); print $_ foreach keys %$userinfo'         
+       http://joey.kitenet.net/
+       foo
+
+To list each user's email address:
+
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); print $userinfo->{$_}->{email} foreach keys %$userinfo'
+       
+       joey@kitenet.net
+
+To dump the entire database contents:
+
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); use Data::Dumper; print Dumper $userinfo'
+       $VAR1 = {
+                 'http://joey.kitenet.net/' => {
+                                                 'email' => 'joey@kitenet.net',
+       [...]
+
+Editing values is simply a matter of changing values and calling Storable::nstore().
+So to change a user's password:
+
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); $userinfo->{"foo"}->{email}=q{foo@bar}; Storable::lock_nstore($userinfo, "underdb")'
+
+To remove that user:
+       
+       joey@kodama:~/src/joeywiki/.ikiwiki> perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); delete $userinfo->{"foo"}; Storable::lock_nstore($userinfo, "underdb")'
+
+I've not written actual utilities to do this yet because I've only needed
+to do it rarely, and the data I've wanted has been different each time.
+--[[Joey]]
index 1fd23cec55edcd56e2e854d23948ba71f713305c..0177f98a9263917d6554d880fd150d5f1fe44d12 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/perl -i
 use warnings;
 use strict;
+use IkiWiki;
+use HTML::Entities;
 
 my $regex = qr{
        (\\?)           # 1: escape?
@@ -48,10 +50,32 @@ sub prefix_directives {
        }
 }
 
+sub indexdb {
+       $config{wikistatedir}=shift()."/.ikiwiki";
+
+       if (! defined $config{wikistatedir}) {
+               usage();                
+       }
+
+       if (! IkiWiki::oldloadindex()) {
+               die "failed to load index\n";
+       }
+       if (! IkiWiki::saveindex()) {
+               die "failed to save indexdb\n"
+       }
+       if (! IkiWiki::loadindex()) {
+               die "transition failed, cannot load new indexdb\n";
+       }
+       if (! unlink("$config{wikistatedir}/index")) {
+               die "unlink failed: $!\n";
+       }
+}
+
 sub usage {
-       print STDERR "Usage: ikiwiki-transition type file ...\n";
-       print STDERR "Currently supported transition types:\n";
-       print STDERR "  prefix_directives\n";
+       print STDERR "Usage: ikiwiki-transition type ...\n";
+       print STDERR "Currently supported transition subcommands:\n";
+       print STDERR "  prefix_directives file\n";
+       print STDERR "  indexdb srcdir\n";
        exit 1;
 }
 
@@ -61,6 +85,63 @@ my $mode=shift;
 if ($mode eq 'prefix_directives') {
        prefix_directives(@ARGV);
 }
+elsif ($mode eq 'indexdb') {
+       indexdb(@ARGV);
+}
 else {
        usage();
 }
+
+package IkiWiki;
+
+# A slightly modified version of the old loadindex function.
+sub oldloadindex {
+       %oldrenderedfiles=%pagectime=();
+       if (! $config{rebuild}) {
+               %pagesources=%pagemtime=%oldlinks=%links=%depends=
+                       %destsources=%renderedfiles=%pagecase=%pagestate=();
+       }
+       open (my $in, "<", "$config{wikistatedir}/index") || return;
+       while (<$in>) {
+               chomp;
+               my %items;
+               $items{link}=[];
+               $items{dest}=[];
+               foreach my $i (split(/ /, $_)) {
+                       my ($item, $val)=split(/=/, $i, 2);
+                       push @{$items{$item}}, decode_entities($val);
+               }
+
+               next unless exists $items{src}; # skip bad lines for now
+
+               my $page=pagename($items{src}[0]);
+               if (! $config{rebuild}) {
+                       $pagesources{$page}=$items{src}[0];
+                       $pagemtime{$page}=$items{mtime}[0];
+                       $oldlinks{$page}=[@{$items{link}}];
+                       $links{$page}=[@{$items{link}}];
+                       $depends{$page}=$items{depends}[0] if exists $items{depends};
+                       $destsources{$_}=$page foreach @{$items{dest}};
+                       $renderedfiles{$page}=[@{$items{dest}}];
+                       $pagecase{lc $page}=$page;
+                       foreach my $k (grep /_/, keys %items) {
+                               my ($id, $key)=split(/_/, $k, 2);
+                               $pagestate{$page}{decode_entities($id)}{decode_entities($key)}=$items{$k}[0];
+                       }
+               }
+               $oldrenderedfiles{$page}=[@{$items{dest}}];
+               $pagectime{$page}=$items{ctime}[0];
+       }
+
+       # saveindex relies on %hooks being populated, else it won't save
+       # the page state owned by a given hook. But no plugins are loaded
+       # by this program, so populate %hooks with all hook ids that
+       # currently have page state.
+       foreach my $page (keys %pagemtime) {
+               foreach my $id (keys %{$pagestate{$page}}) {
+                       $hooks{_dummy}{$id}=1;
+               }
+       }
+       
+       return close($in);
+}