Dear all,

Attached is a patch based on trac-0.10.3 containing some refactoring to
the versioncontrol module (not the svn backend though).

Here is a summary of the changes:

class Repository:
        def get_revision(self, path, rev): return Revision
        def get_node(self, path, rev): return Node

class Node:
        self.path
        self.rev
        def get_revision(self): return Revision
        def get_history(self, limit, stop_rev):return [Node, ...]

class Revision:
        self.message
        self.author
        self.date
        self.base_path  # branch/repository base
        def get_node(path): return Node

I currently have the browser and log almost completely working with the
new interface and the modified trac+bzr plugin but I’m still far from ready.

I see plenty of calls to normalize_rev and normalize_path in the
trac.log. I would like to suggest removing the functions normalize_*.
The normalization would be done by the implementation of Repository in
functions like get_revision(path, rev) and get_node(path, rev). These
functions return objects of types Revision and Node and this objects
have members keeping the normalized values (you can see this approach in
the attached path). I would also like to clean up the interfaces and
make them simpler.

I really liked Christian’s suggestion to use
revision.get_changeset(path). The second way of getting a changeset
would be by calling repository.get_changeset(new_node, old_node).
Furthermore, I thought it might make sense to have the Changeset class
ONLY represent the changes (files) but NOT the revision (message, data,
author). I feel like a lot of refactoring can be done in
web_ui.changeset and I guess I’ll start from there before further
refactoring the versioncontrol api.

Looking forward to your comments!

Regards,

Peter


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac 
Development" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/trac-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Index: trac/versioncontrol/api.py
===================================================================
--- trac/versioncontrol/api.py  (revision 4673)
+++ trac/versioncontrol/api.py  (working copy)
@@ -178,6 +178,10 @@
         """
         raise NotImplementedError
 
+    def get_revision(self, path, rev=None):
+        """Retrieve a Revision object of the node at path and rev."""
+        raise NotImplementedError
+    
     def get_oldest_rev(self):
         """Return the oldest revision stored in the repository."""
         raise NotImplementedError
@@ -258,7 +262,37 @@
         """
         raise NotImplementedError
 
+class Revision(object):
+    """Represents a revision from a repository."""
+    
+    def __init__(self, base_path, rev_str, message, author, date):
+        self.base_path = base_path
+        self.rev_str = rev_str
+        self.message = message
+        self.author = author
+        self.date = date
 
+    def get_node(self, path):
+        """Retrieve a Node at the given path and this revision.
+
+        A Node represents a directory or a file at a given revision in the
+        repository.
+        """
+        raise NotImplementedError
+
+    def get_changeset(self, path):
+        """Retrieve a Changeset corresponding to the this revision and possibly
+        restricted to the given path."""
+        raise NotImplementedError
+
+    def get_properties(self):
+        """Returns the properties (meta-data) of the node, as a dictionary.
+
+        The set of properties depends on the version control system.
+        """
+        raise NotImplementedError
+
+
 class Node(object):
     """Represents a directory or file in the repository at a given revision."""
 
Index: trac/versioncontrol/web_ui/browser.py
===================================================================
--- trac/versioncontrol/web_ui/browser.py       (revision 4673)
+++ trac/versioncontrol/web_ui/browser.py       (working copy)
@@ -93,12 +93,7 @@
 
         # Find node for the requested path/rev
         repos = self.env.get_repository(req.authname)
-        if rev:
-            rev = repos.normalize_rev(rev)
-        # If `rev` is `None`, we'll try to reuse `None` consistently,
-        # as a special shortcut to the latest revision.
-        rev_or_latest = rev or repos.youngest_rev
-        node = get_existing_node(req, repos, path, rev_or_latest)
+        node = get_existing_node(req, repos, path, rev)
 
         # Rendered list of node properties
         hidden_properties = self.hidden_properties
@@ -117,7 +112,7 @@
             'href': req.href.browser(path, rev=rev),
             'log_href': req.href.log(path, rev=rev),
             'restr_changeset_href': req.href.changeset(node.rev,
-                                                       node.created_path),
+                                                       node.path),
             'anydiff_href': req.href.anydiff(),
         }
 
@@ -142,6 +137,7 @@
 
         # Entries metadata
         info = []
+        revisions = {}
         for entry in node.get_entries():
             info.append({
                 'name': entry.name,
@@ -153,7 +149,10 @@
                 'log_href': req.href.log(entry.path, rev=rev),
                 'browser_href': req.href.browser(entry.path, rev=rev)
             })
-        changes = get_changes(self.env, repos, [i['rev'] for i in info])
+            # May not work correctly in root because two branches may have the 
same rev:
+            if not revisions.has_key(entry.rev):
+                revisions[entry.rev] = entry.get_revision()
+        changes = get_revisions_properties(self.env, repos, revisions.values())
 
         # Ordering of entries
         order = req.args.get('order', 'name').lower()
Index: trac/versioncontrol/web_ui/log.py
===================================================================
--- trac/versioncontrol/web_ui/log.py   (revision 4673)
+++ trac/versioncontrol/web_ui/log.py   (working copy)
@@ -72,12 +72,11 @@
         limit = LOG_LIMIT
 
         repos = self.env.get_repository(req.authname)
-        normpath = repos.normalize_path(path)
-        rev = unicode(repos.normalize_rev(rev))
+        node = repos.get_node(path, rev)
+        rev = node.rev
+        node_history = node.get_history(limit+1, stop_rev)
         if stop_rev:
-            stop_rev = unicode(repos.normalize_rev(stop_rev))
-            if repos.rev_older_than(rev, stop_rev):
-                rev, stop_rev = stop_rev, rev
+            stop_rev = node_history[-1].rev
             
         req.hdf['title'] = path + ' (log)'
         req.hdf['log'] = {
@@ -96,42 +95,31 @@
         if path_links:
             add_link(req, 'up', path_links[-1]['href'], 'Parent directory')
 
-        # The `history()` method depends on the mode:
-        #  * for ''stop on copy'' and ''follow copies'', it's `Node.history()` 
-        #  * for ''show only add, delete'' it's`Repository.get_path_history()` 
-        if mode == 'path_history':
-            def history(limit):
-                for h in repos.get_path_history(path, rev, limit):
-                    yield h
-        else:
-            history = get_existing_node(req, repos, path, rev).get_history
-
         # -- retrieve history, asking for limit+1 results
         info = []
-        previous_path = repos.normalize_path(path)
-        for old_path, old_rev, old_chg in history(limit+1):
-            if stop_rev and repos.rev_older_than(old_rev, stop_rev):
-                break
-            old_path = repos.normalize_path(old_path)
+        revisions = {}
+        previous_path = node.path
+        for node in node_history:
+            old_chg = 'modified' #\todo
             item = {
-                'rev': str(old_rev),
-                'path': old_path,
-                'log_href': req.href.log(old_path, rev=old_rev),
-                'browser_href': req.href.browser(old_path, rev=old_rev),
-                'changeset_href': req.href.changeset(old_rev),
-                'restricted_href': req.href.changeset(old_rev, 
new_path=old_path),
+                'rev': node.rev,
+                'path': node.path,
+                'log_href': req.href.log(node.path, rev=node.rev),
+                'browser_href': req.href.browser(node.path, rev=node.rev),
+                'changeset_href': req.href.changeset(node.rev, 
node.get_revision().base_path),
+                'restricted_href': req.href.changeset(node.rev, 
new_path=node.path),
                 'change': old_chg
             }
             if not (mode == 'path_history' and old_chg == Changeset.EDIT):
                 info.append(item)
-            if old_path and old_path != previous_path \
-               and not (mode == 'path_history' and old_path == normpath):
-                item['copyfrom_path'] = old_path
+            if node.path and node.path != previous_path \
+               and not (mode == 'path_history' and old_path == normpath): 
#this maybe is never avaluated
+                item['copyfrom_path'] = node.rev
                 if mode == 'stop_on_copy':
                     break
-            if len(info) > limit: # we want limit+1 entries
-                break
-            previous_path = old_path
+            previous_path = node.path
+            if not revisions.has_key(node.rev):
+                revisions[node.rev] = node.get_revision()
         if info == []:
             # FIXME: we should send a 404 error here
             raise TracError("The file or directory '%s' doesn't exist "
@@ -159,8 +147,7 @@
         
         req.hdf['log.items'] = info
 
-        revs = [i['rev'] for i in info]
-        changes = get_changes(self.env, repos, revs, verbose, req, format)
+        changes = get_revisions_properties(self.env, repos, 
revisions.values(), verbose, req, format)
         if format == 'rss':
             # Get the email addresses of all known users
             email_map = {}
Index: trac/versioncontrol/web_ui/util.py
===================================================================
--- trac/versioncontrol/web_ui/util.py  (revision 4673)
+++ trac/versioncontrol/web_ui/util.py  (working copy)
@@ -26,21 +26,17 @@
 from trac.versioncontrol.api import NoSuchNode, NoSuchChangeset
 from trac.wiki import wiki_to_html, wiki_to_oneliner
 
-__all__ = ['get_changes', 'get_path_links', 'get_path_rev_line',
+__all__ = ['get_revisions_properties', 'get_path_links', 'get_path_rev_line',
            'get_existing_node', 'render_node_property']
 
-def get_changes(env, repos, revs, full=None, req=None, format=None):
+def get_revisions_properties(env, repos, revisions, full=None, req=None, 
format=None):
     db = env.get_db_cnx()
-    changes = {}
-    for rev in revs:
-        try:
-            changeset = repos.get_changeset(rev)
-        except NoSuchChangeset:
-            changes[rev] = {}
-            continue
-
+    properties = {}
+    for revision in revisions:
+        if not revision:
+            continue # \todo don't let Nones here
         wiki_format = env.config['changeset'].getbool('wiki_format_messages')
-        message = changeset.message or '--'
+        message = revision.message or '--'
         absurls = (format == 'rss')
         if wiki_format:
             shortlog = wiki_to_oneliner(message, env, db,
@@ -62,14 +58,14 @@
                 shortlog = shortlog.plaintext(keeplinebreaks=False)
             message = unicode(message)
 
-        changes[rev] = {
-            'date_seconds': changeset.date,
-            'date': format_datetime(changeset.date),
-            'age': pretty_timedelta(changeset.date),
-            'author': changeset.author or 'anonymous',
+        properties[revision.rev_str] = {
+            'date_seconds': revision.date,
+            'date': format_datetime(revision.date),
+            'age': pretty_timedelta(revision.date),
+            'author': revision.author or 'anonymous',
             'message': message, 'shortlog': shortlog,
         }
-    return changes
+    return properties
 
 def get_path_links(href, fullpath, rev):
     links = [{'name': 'root', 'href': href.browser(rev=rev)}]
@@ -95,7 +91,7 @@
 
 def get_existing_node(req, repos, path, rev):
     try: 
-        return repos.get_node(path, rev) 
+        return repos.get_node(path, rev)
     except NoSuchNode, e:
         raise TracError(Markup('%s<br><p>You can <a href="%s">search</a> ' 
                                'in the repository history to see if that path '

Reply via email to