[meld] Add new VC file request interface and SVN support



commit 24798fb11d13f68bb83f4d1e8344b668ea1ffa00
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Sep 4 13:26:54 2011 +1000

    Add new VC file request interface and SVN support
    
    Currently, all VC plugins are asked for a diff between the on-disk
    contents and the repository head, which VCView then reverse applies
    with patch to get a temporary copy of the repository contents. This
    works surprisingly well, but has several issues, most notable of which
    is that it's borderline impossible to figure out what's happening when
    it breaks. In addition, some VCSs (e.g., subversion) give out patches
    that won't actually reverse-apply because of other magic that's been
    performed on the checkout, but isn't reflected in the diff.
    
    This patch adds a simple 'give me the file' API to the Vc class, and
    adds support for it to the svn plugin. While it has a slot for a
    commit argument to retrieve non-HEAD commits, this currently doesn't
    work and has no UI anyway.

 meld/vc/_vc.py |   19 +++++++++++++++++++
 meld/vc/svn.py |   20 ++++++++++++++++++++
 meld/vcview.py |   14 ++++++++++++--
 3 files changed, 51 insertions(+), 2 deletions(-)
---
diff --git a/meld/vc/_vc.py b/meld/vc/_vc.py
index 3efc0d0..61a583e 100644
--- a/meld/vc/_vc.py
+++ b/meld/vc/_vc.py
@@ -110,6 +110,25 @@ class Vc(object):
     def patch_command(self, workdir):
         return ["patch", "-p%i" % self.PATCH_STRIP_NUM, "-R", "-d", workdir]
 
+    def get_repo_file_path(self, path, commit=None):
+        """Requests a file path for the repository copy of the given path.
+
+        Regardless of whether the VCS in question maintains an on-disk copy of
+        the given path, to avoid destructive editing, a temp file with the
+        given content must be created and its path returned. The VCS plugin
+        must **not** delete temp files it creates.
+
+        If *commit* is given, then the path returned will point to a copy of
+        the file at path at the given commit, as interpreted by the VCS in
+        question. If *commit* is **None**, then the current tip is used.
+        """
+
+        # TODO: This method is required to return a path because of how
+        # FileDiff currently operates. In the future, allowing for blob
+        # returns would be desirable.
+
+        raise NotImplementedError()
+
     def check_repo_root(self, location):
         if not os.path.isdir(os.path.join(location, self.VC_DIR)):
             raise ValueError
diff --git a/meld/vc/svn.py b/meld/vc/svn.py
index 24de407..440e778 100644
--- a/meld/vc/svn.py
+++ b/meld/vc/svn.py
@@ -1,4 +1,5 @@
 ### Copyright (C) 2002-2005 Stephen Kennedy <stevek gnome org>
+### Copyright (C) 2011 Kai Willadsen <kai willadsen gmail com>
 
 ### Redistribution and use in source and binary forms, with or without
 ### modification, are permitted provided that the following conditions
@@ -24,6 +25,8 @@
 import errno
 import os
 import re
+import shutil
+import tempfile
 import xml.etree.ElementTree as ElementTree
 
 from . import _vc
@@ -65,6 +68,23 @@ class Vc(_vc.CachedVc):
         return [self.CMD,"revert"]
     def resolved_command(self):
         return [self.CMD,"resolved"]
+
+    def get_repo_file_path(self, path, commit=None):
+        if commit is not None:
+            raise NotImplementedError()
+
+        base, fname = os.path.split(path)
+        svn_path = os.path.join(base, ".svn", "text-base", fname + ".svn-base")
+
+        # TODO: In Python 2.6+, this could be done with NamedTemporaryFile
+        tmp_handle, tmp_path = tempfile.mkstemp(prefix='meld-tmp', text=True)
+        with open(svn_path, 'r') as vc_file:
+            tmp_file = os.fdopen(tmp_handle, 'w')
+            shutil.copyfileobj(vc_file, tmp_file)
+            tmp_file.close()
+
+        return tmp_path
+
     def valid_repo(self):
         if _vc.call([self.CMD, "info"], cwd=self.root):
             return False
diff --git a/meld/vcview.py b/meld/vcview.py
index 486ee99..27bae2e 100644
--- a/meld/vcview.py
+++ b/meld/vcview.py
@@ -156,6 +156,7 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
             button = self.actiongroup.get_action(action)
             button.props.icon_name = button.props.stock_id
         self.tempdirs = []
+        self.temp_files = set()
         self.model = VcTreeStore()
         self.widget.connect("style-set", self.model.on_style_set)
         self.treeview.set_model(self.model)
@@ -381,6 +382,9 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
         for f in self.tempdirs:
             if os.path.exists(f):
                 shutil.rmtree(f, ignore_errors=1)
+        for f in self.temp_files:
+            if os.path.exists(f):
+                os.remove(f)
 
     def on_delete_event(self, appquit=0):
         self.on_quit_event()
@@ -428,8 +432,14 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
                     self.emit("create-diff", [path])
 
     def run_diff(self, path_list):
-        for path in path_list:
-            self.scheduler.add_task(self.run_diff_iter([path]), atfront=1)
+        try:
+            for path in path_list:
+                comp_path = self.vc.get_repo_file_path(path)
+                self.temp_files.add(comp_path)
+                self.emit("create-diff", [comp_path, path])
+        except NotImplementedError:
+            for path in path_list:
+                self.scheduler.add_task(self.run_diff_iter([path]), atfront=1)
 
     def on_treeview_popup_menu(self, treeview):
         time = gtk.get_current_event_time()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]