Rev 18: Handle deletions. Robust implementation. in http://code.launchpad.net/%7Ev-ladeuil/bzr/upload
Vincent Ladeuil
v.ladeuil+lp at free.fr
Sun Mar 23 12:00:34 GMT 2008
At http://code.launchpad.net/%7Ev-ladeuil/bzr/upload
------------------------------------------------------------
revno: 18
revision-id: v.ladeuil+lp at free.fr-20080323120026-lz48rknjd3ii2ywm
parent: v.ladeuil+lp at free.fr-20080322181335-8aphm9mh68tgfvn8
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: upload
timestamp: Sun 2008-03-23 13:00:26 +0100
message:
Handle deletions. Robust implementation.
* test_upload.py:
(TestIncrementalUpload.test_delete_dir_and_subdir,
TestIncrementalUpload.test_delete_one_file_rename_to_deleted,
TestIncrementalUpload.test_rename_outside_dir_delete_dir): Make
the trivial deletion fails.
* __init__.py:
Use lazy_import.
(cmd_upload.delete_remote_file, cmd_upload.delete_remote_dir,
cmd_upload.delete_remote_dir_maybe, cmd_upload.finish_deletions):
Better deletion handling.
(cmd_upload.upload_tree): Handle dir deletions.
modified:
__init__.py __init__.py-20080307145942-xx1xgifrreovahgz-1
test_upload.py test_upload.py-20080307145942-xx1xgifrreovahgz-2
-------------- next part --------------
=== modified file '__init__.py'
--- a/__init__.py 2008-03-22 18:13:35 +0000
+++ b/__init__.py 2008-03-23 12:00:26 +0000
@@ -37,9 +37,17 @@
from bzrlib import (
commands,
+ lazy_import,
option,
)
-
+lazy_import.lazy_import(globals(), """
+from bzrlib import (
+ branch,
+ errors,
+ revisionspec,
+ transport,
+ )
+""")
class cmd_upload(commands.Command):
"""Upload a working tree, as a whole or incrementally.
@@ -63,15 +71,6 @@
def run(self, location, full=False, revision=None, remember=None,
directory=None,
):
- # Import the needed modules but only once we are required to run to
- # avoid degrading bzr startup time
- from bzrlib import (
- branch,
- errors,
- revisionspec,
- transport,
- )
-
if directory is None:
directory = u'.'
self.branch = branch.Branch.open_containing(directory)[0]
@@ -99,6 +98,7 @@
self.tree = self.branch.repository.revision_tree(rev_id)
self.rev_id = rev_id
self._pending_renames = []
+ self._pending_deletions = []
if full:
self.upload_full_tree()
else:
@@ -130,9 +130,31 @@
# XXX: handle mode
self.to_transport.mkdir(relpath)
- def delete_remote_any(self, relpath):
+ def delete_remote_file(self, relpath):
self.to_transport.delete(relpath)
+ def delete_remote_dir(self, relpath):
+ self.to_transport.rmdir(relpath)
+
+ def delete_remote_dir_maybe(self, relpath):
+ """Try to delete relpath, keeping failures to retry later."""
+ try:
+ self.to_transport.rmdir(relpath)
+ # any kind of PathError would be OK, though we normally expect
+ # DirectoryNotEmpty
+ except errors.PathError:
+ self._pending_deletions.append(relpath)
+
+ def finish_deletions(self):
+ if self._pending_deletions:
+ # Process the previously failed deletions in reverse order to
+ # delete children before parents
+ for relpath in reversed(self._pending_deletions):
+ self.to_transport.rmdir(relpath)
+ # The following shouldn't be needed since we use it once per
+ # upload, but better safe than sorry ;-)
+ self._pending_deletions = []
+
def rename_remote(self, old_relpath, new_relpath):
"""Rename a remote file or directory taking care of collisions.
@@ -203,14 +225,17 @@
# XXX: handle kind_changed
for (path, id, kind) in changes.removed:
if kind is 'file':
- self.delete_remote_any(path)
- # XXX: handle dirs
+ self.delete_remote_file(path)
+ elif kind is 'directory':
+ self.delete_remote_dir_maybe(path)
else:
raise NotImplementedError
+
for (old_path, new_path, id, kind,
content_change, exec_change) in changes.renamed:
self.rename_remote(old_path, new_path)
self.finish_renames()
+ self.finish_deletions()
for (path, id, kind) in changes.added:
if kind is 'file':
@@ -219,6 +244,7 @@
self.make_remote_dir(path)
else:
raise NotImplementedError
+
# XXX: Add a test for exec_change
for (path, id, kind,
content_change, exec_change) in changes.modified:
@@ -226,6 +252,7 @@
self.upload_file(path, id)
else:
raise NotImplementedError
+
self.set_uploaded_revid(self.rev_id)
finally:
self.tree.unlock()
=== modified file 'test_upload.py'
--- a/test_upload.py 2008-03-22 18:13:35 +0000
+++ b/test_upload.py 2008-03-23 12:00:26 +0000
@@ -293,6 +293,50 @@
self.do_upload()
self.failIfUpFileExists('hello')
+ def test_delete_dir_and_subdir(self):
+ self.make_local_branch()
+ self.add_dir('dir')
+ self.add_dir('dir/subdir')
+ self.add_file('dir/subdir/a', 'foo')
+ self.do_full_upload()
+ self.rename_any('dir/subdir/a', 'a')
+ self.delete_any('dir/subdir')
+ self.delete_any('dir')
+
+ self.assertUpFileEqual('foo', 'dir/subdir/a')
+ self.do_upload()
+ self.failIfUpFileExists('dir/subdir/a')
+ self.failIfUpFileExists('dir/subdir')
+ self.failIfUpFileExists('dir')
+ self.assertUpFileEqual('foo', 'a')
+
+ def test_delete_one_file_rename_to_deleted(self):
+ self.make_local_branch()
+ self.add_file('a', 'foo')
+ self.add_file('b', 'bar')
+ self.do_full_upload()
+ self.delete_any('a')
+ self.rename_any('b', 'a')
+
+ self.assertUpFileEqual('foo', 'a')
+ self.do_upload()
+ self.failIfUpFileExists('b')
+ self.assertUpFileEqual('bar', 'a')
+
+ def test_rename_outside_dir_delete_dir(self):
+ self.make_local_branch()
+ self.add_dir('dir')
+ self.add_file('dir/a', 'foo')
+ self.do_full_upload()
+ self.rename_any('dir/a', 'a')
+ self.delete_any('dir')
+
+ self.assertUpFileEqual('foo', 'dir/a')
+ self.do_upload()
+ self.failIfUpFileExists('dir/a')
+ self.failIfUpFileExists('dir')
+ self.assertUpFileEqual('foo', 'a')
+
class TestBranchUploadLocations(branch_implementations.TestCaseWithBranch):
More information about the bazaar-commits
mailing list