Edgewall Software
Modify

Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#9096 closed enhancement (fixed)

wiki pre-commit hook

Reported by: team@… Owned by: Christian Boos
Priority: normal Milestone: 0.12
Component: wiki system Version: 0.12dev
Severity: normal Keywords: review
Cc: Branch:
Release Notes:
API Changes:
Internal Changes:

Description

Would be nice to have a feature of wiki pre-commit hook. In my trac.ini file I would say something like this:

[wiki]
pre_commit=/home/trac/pre-commit.sh

Every time anyone makes changes to any wiki page, this shell script is called with params:

pre-commit.sh "pagename" "comment" < "new content"

If the script returns empty string, everything is fine, and the changes are saved to wiki. If the result is not empty, it is interpreted like comments/errors/warnings to certain lines of the wiki page (or to the entire page). Every line will contain one comment, with a prefix (which could be omitted):

crit,7-9:itemized lists are disallowed in specification pages...
err,14,32:syntax error, NAME expected...
warn,19:it is recommended to use existing CamelCase entities...
empty comment line, please use format required by DevelopmentGuidelines

Prefix has three fields (any one of them can be omitted):

  • type of error (err by default)
  • lines interval (7-9) or line number (14, 19), entire document by default
  • position in line (32), no position by default

Empty prefix means that this is an error related to entire page.

If and when pre-commit hook returns errors/warnings Trac disables changes and shows errors on their correspondent lines. Or on top of the page, if errors/warnings are related to the entire page.

Attachments (1)

t9096-prepare_wiki_page-r9388.patch (3.0 KB ) - added by Christian Boos 14 years ago.
wiki web_ui: finally call IWikiPageManipulator.prepare_wiki_page(req, page, fields) (now making the wiki text modifiable before formatting))

Download all attachments as: .zip

Change History (14)

comment:1 by Christian Boos, 14 years ago

Component: generalwiki system
Resolution: worksforme
Status: newclosed

You can program exactly that in a plugin by using the IWikiPageManipulator interface.

There, you can easily fetch whatever you want in the TracIni (e.g. self.config['wiki'].get('pre-commit')), then run an external script (e.g. using subprocess), and allow the submission to proceed or fail, in the latter case presenting a list of warnings to the user.

comment:2 by team@…, 14 years ago

how about post-commit? can I implement a validation of a page when it's already in DB? some pages were created before the pre-commit hook was introduced, and might contain errors/warnings. I would like to have an ability to validate them during rendering.

is it possible as well? thanks.

comment:3 by Christian Boos, 14 years ago

Milestone: 0.12
Resolution: worksforme
Status: closedreopened

This seems like an use case for the other method of the IWikiPageManipulator interface, prepare_wiki_page(req, page, fields), which like the doc says is Not currently called, but should be provided for future compatibility.

This could be called before rendering, you can then use req.add_warning and friends to inform the reader about the needed fixes (be careful to show them only to those who can actually edit the page and do something about it ;-) ).

  • trac/wiki/api.py

    diff --git a/trac/wiki/api.py b/trac/wiki/api.py
    a b class IWikiPageManipulator(Interface):  
    5555    """
    5656
    5757    def prepare_wiki_page(req, page, fields):
    58         """Not currently called, but should be provided for future
    59         compatibility."""
     58        """Validate a wiki page before rendering it.
     59
     60        `page` is the `WikiPage` being view and `fields` is currently `{}`. """
    6061
    6162    def validate_wiki_page(req, page):
    6263        """Validate a wiki page after it's been populated from user input.
     64
     65        `page` is the `WikiPage` being edited.
    6366
    6467        Must return a list of `(field, message)` tuples, one for each problem
    6568        detected. `field` can be `None` to indicate an overall problem with the
  • trac/wiki/web_ui.py

    diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py
    a b class WikiModule(Component):  
    593593                add_ctxtnav(req, _('Up'), req.href.wiki(parent))
    594594            self._wiki_ctxtnav(req, page)
    595595
     596        # Plugin content validation
     597        for manipulator in self.page_manipulators:
     598            manipulator.prepare_wiki_page(req, page, {})
     599
    596600        data.update({
    597601            'context': context,
    598602            'latest_version': latest_page.version,

And here's an example validator (for testing, save as a file, place it below <env>/plugins):

from trac.core import *
from trac.wiki.api import IWikiPageManipulator
from trac.web.chrome import add_warning

class TracWikiValidator(Component):

    implements(IWikiPageManipulator)

    def validate(self, page):
        lines = page.text.splitlines()
        if not lines:
            return ["Page shouldn't be empty"]
        messages = []
        if not lines[0].lstrip().startswith("= "):
            messages.append("First line must be the page's '= title ='")
        # etc.
        return messages
        
    # IWikiPageManipulator
    
    def prepare_wiki_page(self, req, page, fields):
        for message in self.validate(page):
            add_warning(req, message)

    def validate_wiki_page(self, req, page):
        for message in self.validate(page):
            yield ('text', message)

comment:4 by Christian Boos, 14 years ago

Keywords: review added
Owner: set to Christian Boos
Status: reopenednew

comment:5 by team@…, 14 years ago

The biggest problem for me here is to render the wiki page after validation. I understand how to call pre-commit/post-commit hook, and how to get results from it (thanks for your explanation and examples!). But then I would like to show errors/warnings right inside the lines/paragraphs they are related to.

In order to do this I have to change the way wiki page is rendered in HTML. I should start using <table> instead of the normal way of rendering. I should add some new column with paragraph lines, etc.

I though that maybe it's better to integrate such a functionality into Trac core? Or it will require me to create a much more complex plugin than in your example. And in such a case maybe it's good to host it then in track-hacks.org?

in reply to:  5 ; comment:6 by Christian Boos, 14 years ago

Replying to team@…:

But then I would like to show errors/warnings right inside the lines/paragraphs they are related to. In order to do this I have to change the way wiki page is rendered in HTML. I should start using <table> instead of the normal way of rendering. I should add some new column with paragraph lines, etc.

This would require a custom subclass of WikiFormatter… plus an IStreamFilter to substitute the normal wikified output with your own. So yes, this is much more work than my simple example.

I though that maybe it's better to integrate such a functionality into Trac core?

Well, I suggest that you watch closely #4431 which is going to be one my priorities for the next release (0.13 that is). It should become much easier to analyse the content of wiki texts, as well as writing custom formatters or even interfering with existing formatter (for example, #1245 or validation like here).

Or it will require me to create a much more complex plugin than in your example. And in such a case maybe it's good to host it then in track-hacks.org?

If you start something like that, then I could also watch it and it could help me shape the way the future WikiEngine will work in order to make this kind of extension easier to write…

In the meantime, if you can see a more useful way how the existing prepare_wiki_page could be used, let me know. For example, by returning a transformed page, which would not be saved but simply used for preparing the display, you could prepare your table in the wiki directly, see 0.12/WikiHtml.

in reply to:  6 ; comment:7 by Christian Boos, 14 years ago

In the meantime, if you can see a more useful way how the existing prepare_wiki_page could be used, let me know. For example, by returning a transformed page, which would not be saved but simply used for preparing the display, you could prepare your table in the wiki directly, see 0.12/WikiHtml.

This transformed page should actually be stuck into the fields dict under the 'text' key, so that multiple filters could access it in turn. The page.text stays unchanged with the original text.

by Christian Boos, 14 years ago

wiki web_ui: finally call IWikiPageManipulator.prepare_wiki_page(req, page, fields) (now making the wiki text modifiable before formatting))

in reply to:  7 comment:8 by Christian Boos, 14 years ago

Replying to cboos:

This transformed page should actually be stuck into the fields dict under the 'text' key, so that multiple filters could access it in turn. The page.text stays unchanged with the original text.

Implemented in t9096-prepare_wiki_page-r9388.patch, please review.

comment:9 by Remy Blank, 14 years ago

I haven't tested the patch, but it "reads" well. +1

comment:10 by Christian Boos, 14 years ago

Resolution: fixed
Status: newclosed

No problem, I've tested it, and it works well too ;-)

Thanks for the review, committed as [9390].

comment:11 by team@…, 14 years ago

Resolution: fixed
Status: closedreopened

cboos, could you please explain again, how exactly I can change wiki page content on-fly, before rendering. I want to be able to inject my plugin between Trac database and Trac wiki-to-html renderer. Every page, before converting from wiki to html will be passed to my plugin and it will change its wiki formatting (change in memory, not in DB). I feel that the answer is somewhere in this ticket, but I can't understand it without an example from you :)

Also, please mention which Trac version I should use.

in reply to:  11 comment:12 by Remy Blank, 14 years ago

Resolution: fixed
Status: reopenedclosed

Replying to team@…:

could you please explain again, how exactly I can change wiki page content on-fly, before rendering.

Implement IWikiPageManipulator, and in prepare_wiki_page(), mutate fields['text']. Initially, it contains the page content from the database. If you change it, the changed content will be rendered.

Also, please mention which Trac version I should use.

Current trunk (0.12dev).

comment:13 by team@…, 14 years ago

many thanks!

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Christian Boos.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Christian Boos to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.