Merge branch 'master' into autoconfig
authorJoey Hess <joey@kodama.kitenet.net>
Thu, 31 Jul 2008 23:35:37 +0000 (19:35 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Thu, 31 Jul 2008 23:35:37 +0000 (19:35 -0400)
Conflicts:

IkiWiki/Plugin/git.pm
debian/changelog
po/ikiwiki.pot

1  2 
IkiWiki/Plugin/git.pm
debian/changelog
doc/plugins/write.mdwn
doc/todo/color_plugin.mdwn

diff --combined IkiWiki/Plugin/git.pm
index 6f0ac56d5c3b13204c92d0dda1c0dbac417d07d4,1fa9188aa3c29fbfa35065382bb0c92ef5eb25b8..b683e4ec3b7fbba4b1f41c5bb7ac96c074ec2fd2
@@@ -1,5 -1,6 +1,5 @@@
  #!/usr/bin/perl
 -
 -package IkiWiki;
 +package IkiWiki::Plugin::git;
  
  use warnings;
  use strict;
@@@ -10,86 -11,7 +10,86 @@@ use open qw{:utf8 :std}
  my $sha1_pattern     = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
  my $dummy_commit_msg = 'dummy commit';      # message to skip in recent changes
  
 -sub _safe_git (&@) { #{{{
 +sub import { #{{{
 +      if (exists $IkiWiki::hooks{rcs}) {
 +              error(gettext("cannot use multiple rcs plugins"));
 +      }
 +      hook(type => "checkconfig", id => "git", call => \&checkconfig);
 +      hook(type => "getsetup", id => "git", call => \&getsetup);
 +      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);
 +      hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
 +      hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
 +      hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
 +      hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
 +      hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
 +      hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
 +      hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
 +} #}}}
 +
 +sub checkconfig () { #{{{
 +      if (! defined $config{gitorigin_branch}) {
 +              $config{gitorigin_branch}="origin";
 +      }
 +      if (! defined $config{gitmaster_branch}) {
 +              $config{gitmaster_branch}="master";
 +      }
 +      if (defined $config{git_wrapper} && length $config{git_wrapper}) {
 +              push @{$config{wrappers}}, {
 +                      wrapper => $config{git_wrapper},
 +                      wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"),
 +              };
 +      }
 +} #}}}
 +
 +sub getsetup () { #{{{
 +      return
 +              git_wrapper => {
 +                      type => "string",
 +                      example => "/git/wiki.git/hooks/post-update",
 +                      description => "git post-update executable to generate",
 +                      safe => 0, # file
 +                      rebuild => 0,
 +              },
 +              git_wrappermode => {
 +                      type => "string",
 +                      example => '06755',
 +                      description => "mode for git_wrapper (can safely be made suid)",
 +                      safe => 0,
 +                      rebuild => 0,
 +              },
 +              historyurl => {
 +                      type => "string",
 +                      example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=history;f=[[file]]",
 +                      description => "gitweb url to show file history ([[file]] substituted)",
 +                      safe => 1,
 +                      rebuild => 1,
 +              },
 +              diffurl => {
 +                      type => "string",
 +                      example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=blobdiff;h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_parent]];f=[[file]]",
 +                      description => "gitweb url to show a diff ([[sha1_to]], [[sha1_from]], [[sha1_parent]], and [[file]] substituted)",
 +                      safe => 1,
 +                      rebuild => 1,
 +              },
 +              gitorigin_branch => {
 +                      type => "string",
 +                      example => "origin",
 +                      description => "where to pull and push changes (set to empty string to disable)",
 +                      safe => 0, # paranoia
 +                      rebuild => 0,
 +              },
 +              gitmaster_branch => {
 +                      type => "string",
 +                      example => "master",
 +                      description => "branch that the wiki is stored in",
 +                      safe => 0, # paranoia
 +                      rebuild => 0,
 +              },
 +} #}}}
 +
 +sub safe_git (&@) { #{{{
        # Start a child process safely without resorting /bin/sh.
        # Return command output or success state (in scalar context).
  
        return wantarray ? @lines : ($? == 0);
  }
  # Convenient wrappers.
 -sub run_or_die ($@) { _safe_git(\&error, @_) }
 -sub run_or_cry ($@) { _safe_git(sub { warn @_ },  @_) }
 -sub run_or_non ($@) { _safe_git(undef,            @_) }
 +sub run_or_die ($@) { safe_git(\&error, @_) }
 +sub run_or_cry ($@) { safe_git(sub { warn @_ },  @_) }
 +sub run_or_non ($@) { safe_git(undef,            @_) }
  #}}}
  
 -sub _merge_past ($$$) { #{{{
 +sub merge_past ($$$) { #{{{
        # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'.
        # Git merge commands work with the committed changes, except in the
        # implicit case of '-m' of git checkout(1).  So we should invent a
        return $conflict;
  } #}}}
  
 -sub _parse_diff_tree ($@) { #{{{
 +sub parse_diff_tree ($@) { #{{{
        # Parse the raw diff tree chunk and return the info hash.
        # See git-diff-tree(1) for the syntax.
  
@@@ -340,7 -262,7 +340,7 @@@ sub git_commit_info ($;$) { #{{
        my ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix');
  
        my @ci;
 -      while (my $parsed = _parse_diff_tree(($prefix or ""), \@raw_lines)) {
 +      while (my $parsed = parse_diff_tree(($prefix or ""), \@raw_lines)) {
                push @ci, $parsed;
        }
  
@@@ -393,7 -315,7 +393,7 @@@ sub rcs_commit ($$$;$$) { #{{
        my ($prev) = $rcstoken =~ /^($sha1_pattern)$/; # untaint
  
        if (defined $cur && defined $prev && $cur ne $prev) {
 -              my $conflict = _merge_past($prev, $file, $dummy_commit_msg);
 +              my $conflict = merge_past($prev, $file, $dummy_commit_msg);
                return $conflict if defined $conflict;
        }
  
@@@ -414,11 -336,23 +414,23 @@@ sub rcs_commit_staged ($$$) 
                $ENV{GIT_AUTHOR_EMAIL}="$u\@web";
        }
  
 -      $message = possibly_foolish_untaint($message);
++      $message = IkiWiki::possibly_foolish_untaint($message);
+       my @opts;
+       if ($message !~ /\S/) {
+               # Force git to allow empty commit messages.
+               # (If this version of git supports it.)
+               my ($version)=`git --version` =~ /git version (.*)/;
+               if ($version ge "1.5.4") {
+                       push @opts, '--cleanup=verbatim';
+               }
+               else {
+                       $message.=".";
+               }
+       }
+       push @opts, '-q';
        # git commit returns non-zero if file has not been really changed.
        # so we should ignore its exit status (hence run_or_non).
-       $message = IkiWiki::possibly_foolish_untaint($message);
-       if (run_or_non('git', 'commit', '--cleanup=verbatim',
-                      '-q', '-m', $message)) {
+       if (run_or_non('git', 'commit', @opts, '-m', $message)) {
                if (length $config{gitorigin_branch}) {
                        run_or_cry('git', 'push', $config{gitorigin_branch});
                }
@@@ -472,7 -406,7 +484,7 @@@ sub rcs_recentchanges ($) { #{{
                foreach my $detail (@{ $ci->{'details'} }) {
                        my $file = $detail->{'file'};
  
 -                      my $diffurl = $config{'diffurl'};
 +                      my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
                        $diffurl =~ s/\[\[file\]\]/$file/go;
                        $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
                        $diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go;
diff --combined debian/changelog
index 4954c77377ce6489387fad28dc230e5189d2195d,1290904f8bac0af7a4044fe9a4269fedf20b3edb..440910313131e8e21be85a0b9a7591c8b04df27d
@@@ -1,25 -1,15 +1,31 @@@
- ikiwiki (2.56) UNRELEASED; urgency=low
 +ikiwiki (2.60) UNRELEASED; urgency=low
 + 
 +  * Starting with this version, "ikiwiki -setup /etc/ikiwiki/auto.setup"
 +    can be used create a new wiki in seconds.
 +  * Add getsetup hook, all plugins that add fields to %config should use it.
 +  * ikiwiki --dumpsetup can generate a nice setup file snapshotting ikiwiki's
 +    current configuration.
 +  * Large amounts of internal config data reorg.
 +  * The way wrappers are defined in the setup file has changed. Old setup
 +    files will continue to work, for now.
 +  * Version control backends promoted to first-class plugins.
 +  * ikiwiki-update-wikilist: Add -r switch to remove. Default behavior is now
 +    always to add.
 +
 + -- Joey Hess <joeyh@debian.org>  Mon, 21 Jul 2008 11:35:46 -0400
 +
+ ikiwiki (2.56) unstable; urgency=low
  
    * autoindex: New plugin that generates missing index pages.
      (Sponsored by The TOVA Company.)
+   * Escape HTML is rss and atom feeds instead of respectively using CDATA and
+     treating it as XHTML. This avoids problems with escaping the end of the
+     CDATA when the htmlscrubber is not used, and it avoids problems with atom
+     XHTML using named entity references that are not in the atom DTD. (Simon McVittie)
+   * Add test for old versions of git that don't support --cleanup=verbatim,
+     and munge empty commit messages.
  
-  -- Joey Hess <joeyh@debian.org>  Tue, 29 Jul 2008 15:53:26 -0400
+  -- Joey Hess <joeyh@debian.org>  Thu, 31 Jul 2008 19:25:24 -0400
  
  ikiwiki (2.55) unstable; urgency=low
  
diff --combined doc/plugins/write.mdwn
index 04b6ea8e9d4528291ffeac1791a993d7f3e0c87c,58c04d97adf6a7e64aec96f129abcbc946de162c..77210d35cb8bd8731b42e921f0e5f289546a4f3c
@@@ -128,26 -128,34 +128,34 @@@ of a plugin
  
          hook(type => "preprocess", id => "foo", call => \&preprocess);
  
- Replace "foo" with the command name that will be used inside brackets for
- the preprocessor directive.
- Each time the directive is processed, the referenced function (`preprocess`
- in the example above) is called, and is passed named parameters. A "page"
- parameter gives the name of the page that embedded the preprocessor
- directive, while a "destpage" parameter gives the name of the page the
- content is going to (different for inlined pages), and a "preview"
- parameter is set to a true value if the page is being previewed. All
- parameters included in the directive are included as named parameters as
- well. Whatever the function returns goes onto the page in place of the
+ Replace "foo" with the command name that will be used for the preprocessor
  directive.
  
- An optional "scan" parameter, if set to a true value, makes the hook be
- called during the preliminary scan that ikiwiki makes of updated pages,
- before begining to render pages. This parameter should be set to true if
- the hook modifies data in `%links`. Note that doing so will make the hook
- be run twice per page build, so avoid doing it for expensive hooks. (As an
- optimisation, if your preprocessor hook is called in a void contets, you
- can assume it's being run in scan mode.)
+ Each time the directive is processed, the referenced function (`preprocess`
+ in the example above) is called. Whatever the function returns goes onto
+ the page in place of the directive. Or, if the function aborts using
+ `error()`, the directive will be replaced with the error message.
+ The function is passed named parameters. First come the parameters set
+ in the preprocessor directive. These are passed in the same order as
+ they're in the directive, and if the preprocessor directive contains a bare
+ parameter (example: `\[[!foo param]]`), that parameter will be passed with
+ an empty value.
+ After the parameters from the preprocessor directive some additional ones
+ are passed: A "page" parameter gives the name of the page that embedded the
+ preprocessor directive, while a "destpage" parameter gives the name of the
+ page the content is going to (different for inlined pages), and a "preview"
+ parameter is set to a true value if the page is being previewed.
+ If `hook` is passed an optional "scan" parameter, set to a true value, this
+ makes the hook be called during the preliminary scan that ikiwiki makes of
+ updated pages, before begining to render pages. This should be done if the
+ hook modifies data in `%links`. Note that doing so will make the hook be
+ run twice per page build, so avoid doing it for expensive hooks. (As an
+ optimisation, if your preprocessor hook is called in a void context, you
+ can assume it's being run in scan mode, and avoid doing expensive things at
+ that point.)
  
  Note that if the [[htmlscrubber]] is enabled, html in
  [[ikiwiki/PreProcessorDirective]] output is sanitised, which may limit what
@@@ -357,47 -365,6 +365,47 @@@ something. The hook is passed named par
  `newpage`, and `content`, and should try to modify the content to reflect
  the name change. For example, by converting links to point to the new page.
  
 +### getsetup
 +
 +      hook(type => "getsetup", id => "foo", call => \&getsetup);
 +
 +This hooks is not called during normal operation, but only when setting up 
 +the wiki, or generating a setup file. Plugins can use this hook to add
 +configuration options.
 +
 +The hook is passed no parameters. It returns data about the configuration
 +options added by the plugin. It can also check if the plugin is usable, and
 +die if not, which will cause the plugin to not be offered in the configuration
 +interface.
 +
 +The data returned is a list of `%config` options, followed by a hash
 +describing the option. For example:
 +
 +                return
 +                      option_foo => {
 +                              type => "boolean",
 +                              description => "enable foo",
 +                              safe => 1,
 +                              rebuild => 1,
 +                      },
 +                      option_bar => {
 +                              type => "string",
 +                              example => "hello",
 +                              description => "what to say",
 +                              safe => 1,
 +                              rebuild => 0,
 +                      },
 +
 +* `type` can be "boolean", "string", "integer", "pagespec", or "internal" 
 +  (used for values that are not user-visible). The type is the type of
 +  the leaf values;  the `%config` option may be an array or hash of these.
 +* `example` can be set to an example value.
 +* `description` is a short description of the option.
 +* `safe` should be false if the option should not be displayed in unsafe
 +  configuration methods, such as the web interface. Anything that specifies
 +  a command to run, a path on disk, or a regexp should be marked as unsafe.
 +* `rebuild` should be true if changing the option will require a wiki rebuild.
 +
  ## Plugin interface
  
  To import the ikiwiki plugin interface:
@@@ -417,7 -384,7 +425,7 @@@ it's not exported, the wise choice is t
  
  A plugin can access the wiki's configuration via the `%config`
  hash. The best way to understand the contents of the hash is to look at
 -[[ikiwiki.setup]], which sets the hash content to configure the wiki.
 +your ikiwiki setup file, which sets the hash content to configure the wiki.
  
  ### %pagestate
  
@@@ -654,107 -621,15 +662,107 @@@ PageSpecs glob patterns, but instead on
  
  ### RCS plugins
  
 -ikiwiki's support for [[revision_control_systems|rcs]] also uses pluggable
 -perl modules. These are in the `IkiWiki::RCS` namespace, for example
 -`IkiWiki::RCS::svn`. 
 +ikiwiki's support for [[revision_control_systems|rcs]] is also done via
 +plugins. See [[RCS_details|rcs/details]] for some more info.
 +
 +RCS plugins must register a number of hooks. Each hook has type 'rcs', 
 +and the 'id' field is set to the name of the hook. For example:
 +      
 +      hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
 +      hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
 +
 +#### `rcs_update()`
 +
 +Updates the working directory with any remote changes.
 +
 +#### `rcs_prepedit($)`
 +
 +Is passed a file to prepare to edit. It can generate and return an arbitrary
 +token, that will be passed into `rcs_commit` when committing. For example,
 +it might return the current revision ID of the file, and use that
 +information later when merging changes.
 +
 +#### `rcs_commit($$$;$$)`
 +
 +Passed a file, message, token (from `rcs_prepedit`), user, and ip address.
 +Should try to commit the file. Returns `undef` on *success* and a version
 +of the page with the rcs's conflict markers on failure.
 +
 +#### `rcs_commit_staged($$$)`
 +
 +Passed a message, user, and ip address. Should commit all staged changes.
 +Returns undef on success, and an error message on failure.
 +
 +Changes can be staged by calls to `rcs_add, `rcs_remove`, and
 +`rcs_rename`.
 +
 +#### `rcs_add($)`
 +
 +Adds the passed file to the archive. The filename is relative to the root
 +of the srcdir.
 +
 +Note that this should not check the new file in, it should only
 +prepare for it to be checked in when rcs_commit (or `rcs_commit_staged`) is
 +called. Note that the file may be in a new subdir that is not yet in
 +to version control; the subdir can be added if so.
 +
 +#### `rcs_remove($)`
 +
 +Remove a file. The filename is relative to the root of the srcdir.
 +
 +Note that this should not check the removal in, it should only prepare for it
 +to be checked in when `rcs_commit` (or `rcs_commit_staged`) is called. Note
 +that the new file may be in a new subdir that is not yet inversion
 +control; the subdir can be added if so.
 +
 +#### `rcs_rename($$)`
 +
 +Rename a file. The filenames are relative to the root of the srcdir.
 +
 +Note that this should not commit the rename, it should only
 +prepare it for when `rcs_commit` (or `rcs_commit_staged`) is called.
 +The new filename may be in a new subdir, that is not yet added to
 +version control. If so, the subdir will exist already, and should
 +be added to revision control.
 +
 +#### `rcs_recentchanges($)`
 +
 +Examine the RCS history and generate a list of recent changes.
 +The parameter is how many changes to return.
 +
 +The data structure returned for each change is:
 +
 +      {
 +              rev => # the RCSs id for this commit
 +              user => # name of user who made the change,
 +              committype => # either "web" or the name of the rcs,
 +              when => # time when the change was made,
 +              message => [
 +                      { line => "commit message line 1" },
 +                      { line => "commit message line 2" },
 +                      # etc,
 +              ],
 +              pages => [
 +                      {
 +                              page => # name of page changed,
 +                              diffurl => # optional url to a diff of changes
 +                      },
 +                      # repeat for each page changed in this commit,
 +              ],
 +      }
 +
 +#### `rcs_diff($)`
 +
 +The parameter is the rev from `rcs_recentchanges`.
 +Should return a list of lines of the diff (including \n) in list
 +context, and the whole diff in scalar context.
 +
 +#### `rcs_getctime($)`
  
 -Each RCS plugin must support all the `IkiWiki::rcs_*` functions.
 -See IkiWiki::RCS::Stub for the full list of functions. It's ok if
 -`rcs_getctime` does nothing except for throwing an error.
 +This is used to get the page creation time for a file from the RCS, by looking
 +it up in the history.
  
 -See [[RCS_details|rcs/details]] for some more info.
 +It's ok if this is not implemented, and throws an error.
  
  ### PageSpec plugins
  
@@@ -769,15 -644,15 +777,15 @@@ IkiWiki::FailReason object if the matc
  
  ### Setup plugins
  
 -The ikiwiki setup file is loaded using a pluggable mechanism. If you
 -look at the top of [[ikiwiki.setup]], it starts with 
 -'use IkiWiki::Setup::Standard', and the rest of the file is passed to
 -that module's import method.
 +The ikiwiki setup file is loaded using a pluggable mechanism. If you look
 +at the top of a setup file, it starts with 'use IkiWiki::Setup::Standard',
 +and the rest of the file is passed to that module's import method.
  
  It's possible to write other modules in the `IkiWiki::Setup::` namespace that
  can be used to configure ikiwiki in different ways. These modules should,
  when imported, populate `$IkiWiki::Setup::raw_setup` with a reference
 -to a hash containing all the config items.
 +to a hash containing all the config items. They should also implement a
 +`gendump` function.
  
  By the way, to parse a ikiwiki setup file, a program just needs to
  do something like:
index 511851ba3b5920e6afd97809ec713fb5fa336694,68370158ca968944fec33f16a6d5e8f515093e43..ebf5b084c9bb96944aa9889f04c7e752d811fd87
@@@ -58,6 -58,11 +58,11 @@@ comments are very welcome. --[[PaweÅ‚|p
  >> Similar hardcoded method I've found in `img` plugin :) But only one
  >> argument is not named there (image path).
  
+ >>> I think I hadn't realized what you were doing there. The order
+ >>> for unnamed parameters can in fact be relied on. 
+ >>> 
+ >>> --[[Joey]]
  >> Maybe I shouldn't use so simple plugin syntax? For following syntax
  >> I wouldn't have that problem:
  
@@@ -96,6 -101,8 +101,8 @@@ seems to be too enigmatic and it was ha
  in not hardcoded way. I hope that my changes are acceptable for you.
  Of course, I'm open for discussion or exchange of ideas :) --[[PaweÅ‚|ptecza]]
  
+ > One question, why the 2px padding for span.color? --[[Joey]]
        --- /dev/null   2008-06-21 02:02:15.000000000 +0200
        +++ color.pm    2008-07-27 14:58:12.000000000 +0200
        @@ -0,0 +1,69 @@
        +       $content =~ s!<span class="color">((color: ([a-z]+|\#[0-9a-f]{3,6})?)?((; )?(background-color: ([a-z]+|\#[0-9a-f]{3,6})?)?)?)</span>!<span class="color" style="$1">!g;
        +       $content =~ s!<span class="colorend">!!g;
        +
-       +       return $content; 
+       +       return $content;
        +} #}}}
        +
        +sub preprocess(@) { #{{{
        +    \[[!color background=#ff0000 text="Default color text on red background"]]
        +
        +Foreground is missing, so the text has default color.
 -      +
 -      +This plugin is not enabled by default. You can do that in [[ikiwiki.setup]]
 -      +file (hint: `add_plugins` variable).
        --- style.css-orig      2008-07-27 15:12:39.000000000 +0200
        +++ style.css   2008-07-27 15:15:06.000000000 +0200
        @@ -333,3 +333,7 @@