Fix more tests.
authorJelmer Vernooij <jelmer@samba.org>
Sat, 24 Jun 2006 18:22:41 +0000 (20:22 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Sat, 24 Jun 2006 18:22:41 +0000 (20:22 +0200)
README
logwalker.py
repository.py
tests/__init__.py
tests/test_workingtree.py
workingtree.py

diff --git a/README b/README
index 4d29bac310cea36e0a100dcab8375ccffcd80780..f04b12154eaf859f7eecc21f929b64f9124c788a 100644 (file)
--- a/README
+++ b/README
@@ -1,15 +1,30 @@
+== Introduction ==
+
 This directory contains a simple plugin that adds 
 Subversion (http://subversion.tigris.org/) branch support to 
 Bazaar (http://www.bazaar-vcs.org/)
 
-You will need a recent version of Bazaar-NG, most likely bzr.dev. If you have 
-an older version of Bazaar and don't want to upgrade, try the svn-0.8 branch. 
-This contains some hacks to make the Subversion plugin work with Bazaar 0.8.
+== Dependencies == 
+You will need at least version 0.9 of Bazaar-NG (currently unreleased).
+
+You also need a fairly recent version of the Python bindings to the 
+Subversion libraries. At the moment, the svn plugin only works with 
+Subversion 1.5 (trunk). I plan to submit patches against the python-subversion 
+package in Ubuntu Edgy later.
 
-You also need the Subversion bindings for python, with my patch for svn_info_t,
-which has been in Subversions' repository since r19413.
+== Installation ==
 
 Simply place this directory in ~/.bazaar/plugins and you should be able 
 to check out branches from Subversion using bzr.
 
-Jelmer Vernooij <jelmer@samba.org>, April 2006.
+== License ==
+
+GNU General Public License, v2 or later.
+
+== Unit testing ==
+
+Simply run 'bzr selftest svn'
+
+== Author ==
+
+Jelmer Vernooij <jelmer@samba.org>
index c1306c3416b2c4f17c95344ae49f7ebf7342dee7..c5bbf5916a880a6992bbbfac642ec56538b380df 100644 (file)
@@ -16,7 +16,7 @@
 
 from bzrlib.config import config_dir
 from bzrlib.errors import NoSuchRevision
-from bzrlib.progress import ProgressBar
+from bzrlib.progress import ProgressBar, DummyProgress
 from bzrlib.trace import mutter
 
 from svn.core import SubversionException
@@ -29,7 +29,7 @@ from cStringIO import StringIO
 cache_dir = os.path.join(config_dir(), 'svn-cache')
 
 class LogWalker(object):
-    def __init__(self, ra=None, uuid=None, last_revnum=None, repos_url=None):
+    def __init__(self, ra=None, uuid=None, last_revnum=None, repos_url=None, pb=ProgressBar()):
         if not ra:
             callbacks = svn.ra.callbacks2_t()
             ra = svn.ra.open2(repos_url.encode('utf8'), callbacks, None, None)
@@ -55,13 +55,13 @@ class LogWalker(object):
             self.saved_revnum = 0
 
         if self.saved_revnum < last_revnum:
-            self.fetch_revisions(self.saved_revnum, last_revnum)
+            self.fetch_revisions(self.saved_revnum, last_revnum, pb)
         else:
             self.last_revnum = self.saved_revnum
 
-    def fetch_revisions(self, from_revnum, to_revnum):
+    def fetch_revisions(self, from_revnum, to_revnum, pb=ProgressBar()):
         def rcvr(orig_paths, rev, author, date, message, pool):
-            self.pb.update('fetching svn revision info', rev, to_revnum)
+            pb.update('fetching svn revision info', rev, to_revnum)
             paths = {}
             if orig_paths is None:
                 orig_paths = {}
@@ -79,9 +79,8 @@ class LogWalker(object):
 
         mutter('log -r %r:%r /' % (self.saved_revnum, to_revnum))
         self.last_revnum = to_revnum
-        self.pb = ProgressBar()
         svn.ra.get_log(self.ra, ["/"], self.saved_revnum, to_revnum, 0, True, True, rcvr)
-        self.pb.clear()
+        pb.clear()
 
     def __del__(self):
         if self.saved_revnum != self.last_revnum:
index 7dc699dbcf4554cb94925e69719abf197080ccbd..94b531279b6953a02242626f1f76b40095afc4d0 100644 (file)
@@ -253,11 +253,14 @@ class SvnRepository(Repository):
         (path, revnum) = self.parse_revision_id(revision_id)
 
         # TODO: Use get_file_revs()
-        # TODO: Read 'bzr:parents' from the revprops
-        def rcvr((paths, rev, a, b, c)):
-            return self.generate_revision_id(rev, path)
 
-        parent_ids = map(rcvr, self._log.get_branch_log(path, revnum - 1, 0, 1, False))
+        parent_ids = []
+
+        for (paths, rev, a, b, c) in self._log.get_branch_log(path, revnum - 1, 0, 1, False):
+            parent_ids.append(self.generate_revision_id(rev, path))
+            ghosts = svn.ra.rev_prop(self.ra, rev, "bzr:parents")
+            if ghosts is not None:
+                parent_ids.extend(ghosts.splitlines())
 
         return parent_ids
 
index 0ad0694a40136fe46951b7bfd70f545c87407866..39445d1c597ccf2db75f159ad73bdf60eff9eb78 100644 (file)
@@ -41,6 +41,12 @@ class TestCaseWithSubversionRepository(TestCaseInTempDir):
 
         repos = svn.repos.create(abspath, '', '', None, None)
 
+        revprop_hook = os.path.join(abspath, "hooks", "pre-revprop-change")
+
+        open(revprop_hook, 'w').write("#!/bin/sh")
+
+        os.chmod(revprop_hook, os.stat(revprop_hook).st_mode | 0111)
+
         return repos_url
 
     def make_remote_bzrdir(self, relpath):
index 7dc44a441963fc5f5cac0246ff3e0204332d1cf0..d09da99fd99a8722da04b61ef0232e11c24edb59 100644 (file)
@@ -92,7 +92,7 @@ class TestWorkingTree(TestCaseWithSubversionRepository):
         tree = WorkingTree.open("dc")
         tree.rename_one("bl", "bloe")
         
-        basis_inv = tree.basis_tree()
+        basis_inv = tree.basis_tree().inventory
         inv = tree.read_working_inventory()
         self.assertFalse(inv.has_filename("bl"))
         self.assertTrue(inv.has_filename("bloe"))
@@ -111,7 +111,7 @@ class TestWorkingTree(TestCaseWithSubversionRepository):
         tree = WorkingTree.open("dc")
         tree.move(["bl", "a"], "dir")
         
-        basis_inv = tree.basis_tree()
+        basis_inv = tree.basis_tree().inventory
         inv = tree.read_working_inventory()
         self.assertFalse(inv.has_filename("bl"))
         self.assertFalse(inv.has_filename("a"))
index c85634a826f1abc0009521533cdee483841f2916..6dbad544f6c24ba423d8ae5960498c9c08416419 100644 (file)
@@ -19,7 +19,7 @@ from bzrlib.bzrdir import BzrDirFormat
 from bzrlib.errors import NotBranchError, NoSuchFile
 from bzrlib.inventory import Inventory, InventoryDirectory, InventoryFile
 from bzrlib.lockable_files import TransportLock
-from bzrlib.osutils import rand_bytes
+from bzrlib.osutils import rand_bytes, fingerprint_file
 from bzrlib.progress import DummyProgress
 from bzrlib.workingtree import WorkingTree, WorkingTreeFormat
 
@@ -35,10 +35,9 @@ from svn.core import SubversionException
 class SvnWorkingTree(WorkingTree):
     """Implementation of WorkingTree that uses a Subversion 
     Working Copy for storage."""
-    def __init__(self, bzrdir, wc, branch, base_revid):
+    def __init__(self, bzrdir, local_path, branch, base_revid):
         self._format = SvnWorkingTreeFormat()
-        self.wc = wc
-        self.basedir = svn.wc.adm_access_path(self.wc)
+        self.basedir = local_path
         self.base_revid = base_revid
         self.bzrdir = bzrdir
         self._branch = branch
@@ -63,9 +62,20 @@ class SvnWorkingTree(WorkingTree):
         raise NotImplementedError(self.get_file_lines)
 
     def remove(self, files, verbose=False, to_file=None):
-        for file in files:
-            svn.wc.delete2(os.path.join(self.basedir, file), self.wc, None, 
-                           None, None)
+        wc = self._get_wc(write_lock=True)
+        try:
+            for file in files:
+                svn.wc.delete2(os.path.join(self.basedir, file), wc, None, None, None)
+        finally:
+            svn.wc.adm_close(wc)
+
+    def _get_wc(self, relpath="", write_lock=False):
+        return svn.wc.adm_open3(None, os.path.join(self.basedir, relpath).rstrip("/"), write_lock, 0, None)
+
+    def _get_rel_wc(self, relpath, write_lock=False):
+        dir = os.path.dirname(relpath)
+        file = os.path.basename(relpath)
+        return (self._get_wc(dir, write_lock), file)
 
     def revert(self, files, old_tree=None, backups=True, pb=DummyProgress()):
         if old_tree is not None:
@@ -73,27 +83,37 @@ class SvnWorkingTree(WorkingTree):
             super(SvnWorkingTree, self).revert(files, old_tree, backups, pb)
             return
         
-        for f in files:
-            svn.wc.revert(os.path.join(self.basedir, f),
-                      self.wc, False, False, None, None)
+        wc = self._get_wc(write_lock=True)
+        try:
+            for f in files:
+                svn.wc.revert(os.path.join(self.basedir, f),
+                      wc, False, False, None, None)
+        finally:
+            svn.wc.adm_close(wc)
 
     def move(self, from_paths, to_name):
         revt = svn.core.svn_opt_revision_t()
         revt.kind = svn.core.svn_opt_revision_working
+        to_wc = self._get_wc(to_name, write_lock=True)
+        try:
+            for entry in from_paths:
+                svn.wc.copy(os.path.join(self.basedir, entry), to_wc, os.path.basename(entry), None, None)
+        finally:
+            svn.wc.adm_close(to_wc)
+
         for entry in from_paths:
-            old_path = os.path.join(self.basedir, entry)
-            new_path = os.path.join(self.basedir, to_name, entry)
-            svn.wc.copy(old_path, self.wc, new_path, None, None)
             self.remove([entry])
 
     def rename_one(self, from_rel, to_rel):
         revt = svn.core.svn_opt_revision_t()
         revt.kind = svn.core.svn_opt_revision_unspecified
-        svn.wc.copy(os.path.join(self.basedir, from_rel), 
-                    self.wc,
-                    os.path.join(self.basedir, to_rel),
-                    None, None)
-        self.remove([from_rel])
+        (to_wc, to_file) = self._get_rel_wc(to_rel, write_lock=True)
+        try:
+            svn.wc.copy(os.path.join(self.basedir, from_rel), 
+                        to_wc, to_file, None, None)
+            svn.wc.delete2(os.path.join(self.basedir, from_rel), to_wc, None, None, None)
+        finally:
+            svn.wc.adm_close(to_wc)
 
     def read_working_inventory(self):
         basis_inv = self.basis_tree().inventory
@@ -127,31 +147,42 @@ class SvnWorkingTree(WorkingTree):
                     add_dir_to_inv(os.path.join(relpath, entry), subwc)
                     svn.wc.adm_close(subwc)
                 else:
-                    from bzrlib.osutils import fingerprint_file
-                    data = fingerprint_file(open(abspath))
                     file = InventoryFile(subid, entry, id)
-                    file.text_sha1 = data['sha1']
-                    file.text_size = data['size']
-                    inv.add(file)
-
-        add_dir_to_inv("", self.wc)
+                    try:
+                        data = fingerprint_file(open(abspath))
+                        file.text_sha1 = data['sha1']
+                        file.text_size = data['size']
+                        inv.add(file)
+                    except IOError:
+                        # Ignore non-existing files
+                        pass
+
+        wc = self._get_wc() 
+        try:
+            add_dir_to_inv("", wc)
+        finally:
+            svn.wc.adm_close(wc)
 
         return inv
 
     def add(self, files, ids=None):
-        for f in files:
-            try:
-                svn.wc.add2(os.path.join(self.basedir, f), self.wc, None, 0, None, None, None)
-            except SubversionException, (_, num):
-                if num == svn.core.SVN_ERR_ENTRY_EXISTS:
-                    continue
-                if num == svn.core.SVN_ERR_WC_PATH_NOT_FOUND:
-                    raise NoSuchFile(path=f)
-                raise
-            if ids:
-                id = ids.pop()
-                if id:
-                    svn.wc.prop_set2('bzr:fileid', id, f, False)
+        wc = self._get_wc(write_lock=True)
+        try:
+            for f in files:
+                try:
+                    svn.wc.add2(os.path.join(self.basedir, f), wc, None, 0, None, None, None)
+                except SubversionException, (_, num):
+                    if num == svn.core.SVN_ERR_ENTRY_EXISTS:
+                        continue
+                    if num == svn.core.SVN_ERR_WC_PATH_NOT_FOUND:
+                        raise NoSuchFile(path=f)
+                    raise
+                if ids:
+                    id = ids.pop()
+                    if id:
+                        svn.wc.prop_set2('bzr:fileid', id, f, False)
+        finally:
+            svn.wc.adm_close(wc)
 
     def pending_merges(self):
         return []
@@ -171,6 +202,13 @@ class SvnWorkingTree(WorkingTree):
     def extras(self):
         raise NotImplementedError(self.extras)
 
+    def get_file_sha1(self, file_id, path=None):
+        if not path:
+            path = self._inventory.id2path(file_id)
+
+        return fingerprint_file(open(os.path.join(self.basedir, path)))['sha1']
+
+
 class SvnWorkingTreeFormat(WorkingTreeFormat):
     def get_format_description(self):
         return "Subversion Working Copy"
@@ -194,29 +232,25 @@ class OptimizedRepository(SvnRepository):
 
 class SvnLocalAccess(SvnRemoteAccess):
     def __init__(self, transport, format):
-        self.wc = None
         self.local_path = transport.base.rstrip("/")
         if self.local_path.startswith("file://"):
             self.local_path = self.local_path[len("file://"):]
         
-        self.wc = svn.wc.adm_open3(None, self.local_path, True, 0, None)
+        wc = svn.wc.adm_open3(None, self.local_path, True, 0, None)
         self.transport = transport
 
         # Open related remote repository + branch
-        url, revno = svn.wc.get_ancestry(self.local_path, self.wc)
+        url, revno = svn.wc.get_ancestry(self.local_path, wc)
         if not url.startswith("svn"):
             url = "svn+" + url
 
-        self.base_revno = svn.wc.status2(self.local_path, self.wc).ood_last_cmt_rev
+        self.base_revno = svn.wc.status2(self.local_path, wc).ood_last_cmt_rev
 
         remote_transport = SvnRaTransport(url)
 
         super(SvnLocalAccess, self).__init__(remote_transport, format)
 
-    def __del__(self):
-        if self.wc is not None:
-            svn.wc.adm_close(self.wc)
-            self.wc = None
+        svn.wc.adm_close(wc)
 
     def open_repository(self):
         repos = OptimizedRepository(self, self.root_transport)
@@ -231,7 +265,7 @@ class SvnLocalAccess(SvnRemoteAccess):
 
     # Working trees never exist on Subversion repositories
     def open_workingtree(self, _unsupported=False):
-        return SvnWorkingTree(self, self.wc, self.open_branch(), 
+        return SvnWorkingTree(self, self.local_path, self.open_branch(), 
                 self.open_repository().generate_revision_id(
                     self.base_revno, self.branch_path))