Edgewall Software

Ticket #1132: store-wiki-in-svn-for-0.11.7.patch

File store-wiki-in-svn-for-0.11.7.patch, 15.0 KB (added by bkuhn@…, 20 months ago)

Hack patch against 0.11.7, based on previous ones, to store your Wiki in svn.

  • trac/versioncontrol/api.py

    diff -x '*~' -ruN Trac-0.11.7/trac/versioncontrol/api.py patched-trac/trac/versioncontrol/api.py
    old new  
    380380        """ 
    381381        raise NotImplementedError 
    382382 
     383    def set_content(self, content, commitmsg=None): 
     384        """ 
     385        Set the content of the node. Add the commitmsg to the logs. If Node is 
     386        of type DIRECTORY this method raise an Error. 
     387         
     388        If the Node doesn't exist it's created.  
     389 
     390        Returns the revision Number that tags the commit. 
     391        """ 
     392        raise NotImplementedError 
     393 
    383394    def get_entries(self): 
    384395        """Generator that yields the immediate child entries of a directory. 
    385396 
     
    521532    access to view certain parts of a repository. 
    522533    """ 
    523534 
    524     def assert_permission(self, path): 
     535    def assert_permission(self, path, perm='r'): 
    525536        if not self.has_permission(path): 
    526537            raise PermissionDenied(_('Insufficient permissions to access ' 
    527538                                     '%(path)s', path=path)) 
     
    531542            raise PermissionDenied(_('Insufficient permissions to access ' 
    532543                                     'changeset %(id)s', id=rev)) 
    533544 
    534     def has_permission(self, path): 
     545    def has_permission(self, path, perm='r'): 
    535546        return True 
    536547 
    537548    def has_permission_for_changeset(self, rev): 
  • trac/versioncontrol/svn_authz.py

    diff -x '*~' -ruN Trac-0.11.7/trac/versioncontrol/svn_authz.py patched-trac/trac/versioncontrol/svn_authz.py
    old new  
    8989 
    9090        self.groups = self._groups() 
    9191 
    92     def has_permission(self, path): 
     92    def has_permission(self, path, perm='r'): 
    9393        if path is None: 
    9494            return 1 
    9595 
    9696        for p in parent_iter(path): 
    9797            if self.module_name: 
    98                 for perm in self._get_section(self.module_name + ':' + p): 
     98                for perm in self._get_section(self.module_name + ':' + p, perm): 
    9999                    if perm is not None: 
    100100                        return perm 
    101101            for perm in self._get_section(p): 
     
    144144        # expand groups 
    145145        return expanded.keys() 
    146146 
    147     def _get_section(self, section): 
     147    def _get_section(self, section, perm='r'): 
    148148        if not self.conf_authz.has_section(section): 
    149149            return 
    150150 
    151         yield self._get_permission(section, self.auth_name) 
     151        yield self._get_permission(section, self.auth_name, perm) 
    152152 
    153153        group_perm = None 
    154154        for g in self.groups: 
    155             p = self._get_permission(section, '@' + g) 
     155            p = self._get_permission(section, '@' + g, perm) 
    156156            if p is not None: 
    157157                group_perm = p 
    158158 
     
    161161 
    162162        yield group_perm 
    163163 
    164         yield self._get_permission(section, '*') 
     164        yield self._get_permission(section, '*', perm) 
    165165 
    166     def _get_permission(self, section, subject): 
     166    def _get_permission(self, section, subject, perm='r'): 
    167167        if self.conf_authz.has_option(section, subject): 
    168             return 'r' in self.conf_authz.get(section, subject) 
     168            return perm in self.conf_authz.get(section, subject) 
    169169        return None 
  • trac/versioncontrol/svn_fs.py

    diff -x '*~' -ruN Trac-0.11.7/trac/versioncontrol/svn_fs.py patched-trac/trac/versioncontrol/svn_fs.py
    old new  
    450450            revs.append(r) 
    451451        return revs 
    452452 
     453    def delete_node(self, path, commitmsg): 
     454        return NotImplementedError 
     455 
    453456    def _history(self, path, start, end, pool): 
    454457        """`path` is a unicode path in the scope. 
    455458 
     
    670673        else: 
    671674            self.root = fs.revision_root(self.fs_ptr, rev, self.pool()) 
    672675        node_type = fs.check_path(self.root, self._scoped_path_utf8, pool) 
    673         if not node_type in _kindmap: 
     676        if node_type == core.svn_node_none: 
     677            self.created_rev = 0 
     678            self.created_path = self._scoped_path_utf8 
     679            self.rev = self.created_rev 
     680            node_type = core.svn_node_file 
     681        elif not node_type in _kindmap: 
    674682            raise NoSuchNode(path, rev) 
    675683        cp_utf8 = fs.node_created_path(self.root, self._scoped_path_utf8, pool) 
    676684        cp = _from_svn(cp_utf8) 
     
    700708        # is not destroyed before the stream object. 
    701709        s._pool = self.pool 
    702710        return s 
     711    def set_content(self,content,commitmsg="changed by trac",uname=""): 
     712        # this check is untested!  
     713        self.authz.assert_permission(self.scoped_path, 'w') 
     714 
     715        # based on the putfile.py example of the subversion dist. 
     716        # open a transaction against HEAD. 
     717        rev = fs.youngest_rev(repos.fs(self.repos),self.pool()) 
     718        txn = repos.fs_begin_txn_for_commit(self.repos, rev, uname, 
     719                                            commitmsg, self.pool()) 
     720 
     721        root = fs.txn_root(txn,self.pool()) 
     722        kind = fs.check_path(root,self._scoped_path_utf8,self.pool()) 
     723 
     724        if kind == core.svn_node_none: 
     725            fs.make_file(root,self._scoped_path_utf8,self.pool()) 
     726        elif not kind == core.svn_node_file: 
     727            raise TracError("Node is not a File.") 
     728         
     729        handler, baton = fs.apply_textdelta(root,self._scoped_path_utf8,  
     730                                            None, None, self.pool()) 
     731 
     732        delta.svn_txdelta_send_string(content,handler,baton,self.pool()) 
     733        return repos.fs_commit_txn(self.repos,txn,self.pool()) 
    703734 
    704735    def get_entries(self): 
    705736        if self.isfile: 
  • trac/versioncontrol/tests/svn_fs.py

    diff -x '*~' -ruN Trac-0.11.7/trac/versioncontrol/tests/svn_fs.py patched-trac/trac/versioncontrol/tests/svn_fs.py
    old new  
    197197        self.assertEqual('text/plain', node.content_type) 
    198198        self.assertEqual('A test.\n', node.get_content().read()) 
    199199 
     200    def test_set_file_content(self): 
     201        node = self.repos.get_node('/trunk/README.txt') 
     202        node.set_content('This is the test Content\n', 'change.') 
     203 
     204        # reload the repository for the newly commited change.  
     205        self.repos = SubversionRepository(REPOS_PATH, None, 
     206                                          logger_factory('test')) 
     207 
     208        node = self.repos.get_node('/trunk/README.txt') 
     209        chgset = self.repos.get_changeset(self.repos.get_youngest_rev()) 
     210 
     211        self.assertEqual('This is the test Content\n',  
     212            node.get_content().read()) 
     213        self.assertEqual('change.', chgset.message ) 
     214 
     215    def test_delete_node(self): 
     216        node = self.repos.delete_node('/trunk/README.txt', "delete.") 
     217         
     218        self.repos = SubversionRepository(REPOS_PATH, None, 
     219                                          logger_factory('test')) 
     220 
     221        node = self.repos.get_node('/trunk/README.txt') 
     222        chgset = self.repos.get_changeset(self.repos.get_youngest_rev()) 
     223 
     224        self.assertNotEqual(Node.DIRECTORY, node.kind) 
     225        self.assertNotEqual(Node.FILE, node.kind) 
     226        self.assertEqual('delete.', chgset.message ) 
     227 
    200228    def test_get_dir_properties(self): 
    201229        f = self.repos.get_node(u'/tête') 
    202230        props = f.get_properties() 
  • trac/wiki/api.py

    diff -x '*~' -ruN Trac-0.11.7/trac/wiki/api.py patched-trac/trac/wiki/api.py
    old new  
    3535from trac.util.translation import _ 
    3636from trac.wiki.parser import WikiParser 
    3737 
     38from trac.wiki.model_svn import WikiPage 
    3839 
    3940class IWikiChangeListener(Interface): 
    4041    """Extension point interface for components that should get notified about 
     
    198199                cursor = db.cursor() 
    199200                cursor.execute("SELECT DISTINCT name FROM wiki") 
    200201                self._index = {} 
    201                 for (name,) in cursor: 
    202                     self._index[name] = True 
     202                for page in WikiPage.select(self.env): 
     203                    self._index[page.name] = True 
     204 
    203205                self._last_index_update = now 
    204206        finally: 
    205207            self._index_lock.release() 
  • trac/wiki/macros.py

    diff -x '*~' -ruN Trac-0.11.7/trac/wiki/macros.py patched-trac/trac/wiki/macros.py
    old new  
    3434from trac.wiki.api import IWikiMacroProvider, WikiSystem, parse_args 
    3535from trac.wiki.formatter import format_to_html, format_to_oneliner, \ 
    3636                                extract_link, OutlineFormatter 
    37 from trac.wiki.model import WikiPage 
     37from trac.wiki.model_svn import WikiPage 
    3838from trac.web.chrome import add_stylesheet 
    3939 
    4040 
  • trac/wiki/model.py

    diff -x '*~' -ruN Trac-0.11.7/trac/wiki/model.py patched-trac/trac/wiki/model.py
    old new  
    169169        for version,ts,author,comment,ipnr in cursor: 
    170170            time = datetime.fromtimestamp(ts, utc) 
    171171            yield version,time,author,comment,ipnr 
     172 
     173    def select(cls, env, db=None): 
     174        if not db: 
     175            db = env.get_db_cnx() 
     176 
     177        cursor = db.cursor() 
     178        cursor.execute("SELECT DISTINCT name FROM wiki") 
     179        for (name,) in cursor: 
     180            yield WikiPage(env,name) 
     181 
     182    select = classmethod(select) 
     183 
     184 
  • trac/wiki/model_svn.py

    diff -x '*~' -ruN Trac-0.11.7/trac/wiki/model_svn.py patched-trac/trac/wiki/model_svn.py
    old new  
     1# -*- coding: iso8859-1 -*- 
     2# 
     3# Copyright (C) 2003-2005 Edgewall Software 
     4# Copyright (C) 2005 Philipp Scholl <pscholl@bawue.de> 
     5# All rights reserved. 
     6# 
     7# This software is licensed as described in the file COPYING, which 
     8# you should have received as part of this distribution. The terms 
     9# are also available at http://trac.edgewall.com/license.html. 
     10# 
     11# This software consists of voluntary contributions made by many 
     12# individuals. For the exact contribution history, see the revision 
     13# history and logs, available at http://projects.edgewall.com/trac/. 
     14# 
     15# Author: Philipp Scholl <pscholl@bawue.de> 
     16 
     17from __future__ import generators 
     18import time 
     19 
     20from trac.core import * 
     21from trac.resource import Resource 
     22#from trac.wiki.api import WikiSystem 
     23from trac.versioncontrol.api import Node 
     24 
     25 
     26class WikiPage(object): 
     27    """Represents a wiki page (new or existing).""" 
     28 
     29    def __init__(self, env, name=None, version=None, db=None): 
     30        self.env = env 
     31        self.root = env.config.get( 'wiki', 'svn_root' ) 
     32        if not env.get_repository().get_node(self.root).kind in (Node.DIRECTORY, Node.FILE): 
     33            raise TracError( "wiki root couldn't be found!" ) 
     34        if self.root[:-1] != '/': self.root += '/' 
     35        if isinstance(name, Resource): 
     36            self.resource = name 
     37            name = self.resource.id 
     38        else: 
     39            self.resource = Resource('wiki', name, version) 
     40        self.name = name 
     41        if name: 
     42            self._fetch(name, version, db) 
     43        else: 
     44            self.version = 0 
     45            self.text = '' 
     46            self.readonly = 0 
     47        self.old_text = self.text 
     48        self.old_readonly = self.readonly 
     49         
     50    def _fetch(self, name, version=None, db=None): 
     51        repos = self.env.get_repository() 
     52        try: 
     53            if version: 
     54                node = repos.get_node(self.root+name,version) 
     55                self.text = node.get_content().read() 
     56                self.version = version 
     57                self.readonly = 0 
     58            else: 
     59                node = repos.get_node(self.root+name) 
     60                self.text = node.get_content().read() 
     61                history = node.get_history() 
     62                self.version = 0 
     63                for path, rev, chg in history: 
     64                    if self.version < rev: self.version = rev 
     65                self.readonly = 0 
     66        except Exception: 
     67            self.version = 0 
     68            self.text = '' 
     69            self.readonly = 0 
     70        except: 
     71            repos.close() 
     72 
     73    exists = property(fget=lambda self: self.version > 0) 
     74 
     75    def delete(self, version=None, db=None): 
     76        assert self.exists, 'Cannot delete non-existent page' 
     77        if version: 
     78            raise NotImplementedError( "deletion of versions not supported in \ 
     79            wiki_svn" ) 
     80        repos = self.env.get_repository() 
     81        repos.delete_node(self.root+self.name) 
     82 
     83    def save(self, author, comment, remote_addr, t=None, db=None): 
     84        repos = self.env.get_repository() 
     85         
     86        # make sure that noone can escape the wiki root. 
     87        if self.name.find( "..") != -1: 
     88            raise TracError( ".. not allowed in wiki names." ) 
     89 
     90        node = repos.get_node(self.root+self.name) 
     91 
     92        commitmsg  = self.name+" edited by "+author+" from "+remote_addr+"\n" 
     93        commitmsg += comment 
     94        self.version = node.set_content(self.text, commitmsg, author) 
     95        self.resource = self.resource(version=self.version) 
     96 
     97        if t is None: 
     98            t = time.time() 
     99             
     100#        for listener in WikiSystem(self.env).change_listeners: 
     101#            if self.version == repos.get_youngest_rev(): 
     102#                listener.wiki_page_added(self) 
     103#            else: 
     104#                listener.wiki_page_changed(self, self.version, t, author, 
     105#                                           comment, remote_addr) 
     106 
     107    def get_history(self, db=None): 
     108        repos = self.env.get_repository() 
     109 
     110        history = repos.get_path_history(self.root+self.name) 
     111 
     112        for path, rev, kind in history: 
     113            chgset = repos.get_changeset(rev) 
     114            yield rev,chgset.date,chgset.author,chgset.message,"missing" 
     115 
     116    def select(cls, env, db=None): 
     117        if not 'get_repository' in dir(env): 
     118            return 
     119        repos = env.get_repository() 
     120        dnode = repos.get_node( env.config.get('wiki', 'svn_root') ) 
     121         
     122        for node in dnode.get_entries(): 
     123            if node.kind == Node.DIRECTORY: 
     124                for subnode in node.get_entries(): 
     125                    yield WikiPage(env,node.get_name()) 
     126            yield WikiPage(env,node.get_name()) 
     127 
     128    select = classmethod(select) 
     129 
     130 
  • trac/wiki/web_ui.py

    diff -x '*~' -ruN Trac-0.11.7/trac/wiki/web_ui.py patched-trac/trac/wiki/web_ui.py
    old new  
    4242from trac.web import IRequestHandler 
    4343from trac.wiki.api import IWikiPageManipulator, WikiSystem 
    4444from trac.wiki.formatter import format_to 
    45 from trac.wiki.model import WikiPage 
     45from trac.wiki.model_svn import WikiPage 
    4646  
    4747class InvalidWikiPage(TracError): 
    4848    """Exception raised when a Wiki page fails validation.