Rev 4499: merge bzr.dev at 4492 resolving conflicts in file:///home/vila/src/bzr/experimental/cleanup-strict/

Vincent Ladeuil v.ladeuil+lp at free.fr
Tue Jun 30 09:30:09 BST 2009


At file:///home/vila/src/bzr/experimental/cleanup-strict/

------------------------------------------------------------
revno: 4499 [merge]
revision-id: v.ladeuil+lp at free.fr-20090630083008-foex07e8ol983c95
parent: v.ladeuil+lp at free.fr-20090630081555-jq9devz6h8rsd856
parent: pqm at pqm.ubuntu.com-20090630063506-f7wlyoa0ldu816g0
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: cleanup-strict
timestamp: Tue 2009-06-30 10:30:08 +0200
message:
  merge bzr.dev at 4492 resolving conflicts
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/groupcompress.py        groupcompress.py-20080705181503-ccbxd6xuy1bdnrpu-8
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/repofmt/groupcompress_repo.py repofmt.py-20080715094215-wp1qfvoo7093c8qr-1
  bzrlib/tests/test_groupcompress.py test_groupcompress.p-20080705181503-ccbxd6xuy1bdnrpu-13
  bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
  bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
  bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
  bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2009-06-30 08:15:55 +0000
+++ b/NEWS	2009-06-30 08:30:08 +0000
@@ -36,6 +36,9 @@
 Bug Fixes
 *********
 
+* Accept uppercase "Y/N" to prompts such as from break lock. 
+  (#335182, Tim Powell, Martin Pool)
+
 * Add documentation about diverged branches and how to fix them in the
   centralized workflow with local commits.  Mention ``bzr help
   diverged-branches`` when a push fails because the branches have
@@ -57,6 +60,13 @@
 * ``bzr ls DIR --from-root`` now shows only things in DIR, not everything.
   (Ian Clatworthy)
 
+* Fetch between repositories does not error if they have inconsistent data
+  that should be irrelevant to the fetch operation. (Aaron Bentley)
+
+* Force deletion of readonly files during merge, update and other tree
+  transforms.
+  (Craig Hewetson, Martin Pool, #218206)
+
 * Progress bars are now suppressed again when the environment variable
   ``BZR_PROGRESS_BAR`` is set to ``none``.
   (Martin Pool, #339385)

=== modified file 'bzrlib/groupcompress.py'
--- a/bzrlib/groupcompress.py	2009-06-23 15:27:50 +0000
+++ b/bzrlib/groupcompress.py	2009-06-29 14:51:13 +0000
@@ -942,7 +942,7 @@
         self.endpoint = endpoint
 
 
-def make_pack_factory(graph, delta, keylength):
+def make_pack_factory(graph, delta, keylength, inconsistency_fatal=True):
     """Create a factory for creating a pack based groupcompress.
 
     This is only functional enough to run interface tests, it doesn't try to
@@ -963,7 +963,8 @@
         writer = pack.ContainerWriter(stream.write)
         writer.begin()
         index = _GCGraphIndex(graph_index, lambda:True, parents=parents,
-            add_callback=graph_index.add_nodes)
+            add_callback=graph_index.add_nodes,
+            inconsistency_fatal=inconsistency_fatal)
         access = knit._DirectPackAccess({})
         access.set_writer(writer, graph_index, (transport, 'newpack'))
         result = GroupCompressVersionedFiles(index, access, delta)
@@ -1610,7 +1611,8 @@
     """Mapper from GroupCompressVersionedFiles needs into GraphIndex storage."""
 
     def __init__(self, graph_index, is_locked, parents=True,
-        add_callback=None, track_external_parent_refs=False):
+        add_callback=None, track_external_parent_refs=False,
+        inconsistency_fatal=True):
         """Construct a _GCGraphIndex on a graph_index.
 
         :param graph_index: An implementation of bzrlib.index.GraphIndex.
@@ -1624,12 +1626,17 @@
         :param track_external_parent_refs: As keys are added, keep track of the
             keys they reference, so that we can query get_missing_parents(),
             etc.
+        :param inconsistency_fatal: When asked to add records that are already
+            present, and the details are inconsistent with the existing
+            record, raise an exception instead of warning (and skipping the
+            record).
         """
         self._add_callback = add_callback
         self._graph_index = graph_index
         self._parents = parents
         self.has_graph = parents
         self._is_locked = is_locked
+        self._inconsistency_fatal = inconsistency_fatal
         if track_external_parent_refs:
             self._key_dependencies = knit._KeyRefs()
         else:
@@ -1671,8 +1678,14 @@
             present_nodes = self._get_entries(keys)
             for (index, key, value, node_refs) in present_nodes:
                 if node_refs != keys[key][1]:
-                    raise errors.KnitCorrupt(self, "inconsistent details in add_records"
-                        ": %s %s" % ((value, node_refs), keys[key]))
+                    details = '%s %s %s' % (key, (value, node_refs), keys[key])
+                    if self._inconsistency_fatal:
+                        raise errors.KnitCorrupt(self, "inconsistent details"
+                                                 " in add_records: %s" %
+                                                 details)
+                    else:
+                        trace.warning("inconsistent details in skipped"
+                                      " record: %s", details)
                 del keys[key]
                 changed = True
         if changed:

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2009-06-10 06:25:56 +0000
+++ b/bzrlib/osutils.py	2009-06-30 04:08:12 +0000
@@ -927,13 +927,31 @@
         shutil.copyfile(src, dest)
 
 
-# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
-# Forgiveness than Permission (EAFP) because:
-# - root can damage a solaris file system by using unlink,
-# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
-#   EACCES, OSX: EPERM) when invoked on a directory.
 def delete_any(path):
-    """Delete a file or directory."""
+    """Delete a file, symlink or directory.  
+    
+    Will delete even if readonly.
+    """
+    try:
+       _delete_file_or_dir(path)
+    except (OSError, IOError), e:
+        if e.errno in (errno.EPERM, errno.EACCES):
+            # make writable and try again
+            try:
+                make_writable(path)
+            except (OSError, IOError):
+                pass
+            _delete_file_or_dir(path)
+        else:
+            raise
+
+
+def _delete_file_or_dir(path):
+    # Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
+    # Forgiveness than Permission (EAFP) because:
+    # - root can damage a solaris file system by using unlink,
+    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
+    #   EACCES, OSX: EPERM) when invoked on a directory.
     if isdir(path): # Takes care of symlinks
         os.rmdir(path)
     else:

=== modified file 'bzrlib/repofmt/groupcompress_repo.py'
--- a/bzrlib/repofmt/groupcompress_repo.py	2009-06-26 09:24:34 +0000
+++ b/bzrlib/repofmt/groupcompress_repo.py	2009-06-29 14:51:13 +0000
@@ -622,7 +622,8 @@
         self.inventories = GroupCompressVersionedFiles(
             _GCGraphIndex(self._pack_collection.inventory_index.combined_index,
                 add_callback=self._pack_collection.inventory_index.add_callback,
-                parents=True, is_locked=self.is_locked),
+                parents=True, is_locked=self.is_locked,
+                inconsistency_fatal=False),
             access=self._pack_collection.inventory_index.data_access)
         self.revisions = GroupCompressVersionedFiles(
             _GCGraphIndex(self._pack_collection.revision_index.combined_index,
@@ -634,19 +635,22 @@
         self.signatures = GroupCompressVersionedFiles(
             _GCGraphIndex(self._pack_collection.signature_index.combined_index,
                 add_callback=self._pack_collection.signature_index.add_callback,
-                parents=False, is_locked=self.is_locked),
+                parents=False, is_locked=self.is_locked,
+                inconsistency_fatal=False),
             access=self._pack_collection.signature_index.data_access,
             delta=False)
         self.texts = GroupCompressVersionedFiles(
             _GCGraphIndex(self._pack_collection.text_index.combined_index,
                 add_callback=self._pack_collection.text_index.add_callback,
-                parents=True, is_locked=self.is_locked),
+                parents=True, is_locked=self.is_locked,
+                inconsistency_fatal=False),
             access=self._pack_collection.text_index.data_access)
         # No parents, individual CHK pages don't have specific ancestry
         self.chk_bytes = GroupCompressVersionedFiles(
             _GCGraphIndex(self._pack_collection.chk_index.combined_index,
                 add_callback=self._pack_collection.chk_index.add_callback,
-                parents=False, is_locked=self.is_locked),
+                parents=False, is_locked=self.is_locked,
+                inconsistency_fatal=False),
             access=self._pack_collection.chk_index.data_access)
         # True when the repository object is 'write locked' (as opposed to the
         # physical lock only taken out around changes to the pack-names list.)

=== modified file 'bzrlib/tests/test_groupcompress.py'
--- a/bzrlib/tests/test_groupcompress.py	2009-06-22 18:30:08 +0000
+++ b/bzrlib/tests/test_groupcompress.py	2009-06-29 14:51:13 +0000
@@ -25,6 +25,7 @@
     index as _mod_index,
     osutils,
     tests,
+    trace,
     versionedfile,
     )
 from bzrlib.osutils import sha_string
@@ -474,11 +475,12 @@
 class TestCaseWithGroupCompressVersionedFiles(tests.TestCaseWithTransport):
 
     def make_test_vf(self, create_graph, keylength=1, do_cleanup=True,
-                     dir='.'):
+                     dir='.', inconsistency_fatal=True):
         t = self.get_transport(dir)
         t.ensure_base()
         vf = groupcompress.make_pack_factory(graph=create_graph,
-            delta=False, keylength=keylength)(t)
+            delta=False, keylength=keylength,
+            inconsistency_fatal=inconsistency_fatal)(t)
         if do_cleanup:
             self.addCleanup(groupcompress.cleanup_pack_group, vf)
         return vf
@@ -658,6 +660,47 @@
             frozenset([('parent-1',), ('parent-2',)]),
             index.get_missing_parents())
 
+    def make_source_with_b(self, a_parent, path):
+        source = self.make_test_vf(True, dir=path)
+        source.add_lines(('a',), (), ['lines\n'])
+        if a_parent:
+            b_parents = (('a',),)
+        else:
+            b_parents = ()
+        source.add_lines(('b',), b_parents, ['lines\n'])
+        return source
+
+    def do_inconsistent_inserts(self, inconsistency_fatal):
+        target = self.make_test_vf(True, dir='target',
+                                   inconsistency_fatal=inconsistency_fatal)
+        for x in range(2):
+            source = self.make_source_with_b(x==1, 'source%s' % x)
+            target.insert_record_stream(source.get_record_stream(
+                [('b',)], 'unordered', False))
+
+    def test_inconsistent_redundant_inserts_warn(self):
+        """Should not insert a record that is already present."""
+        warnings = []
+        def warning(template, args):
+            warnings.append(template % args)
+        _trace_warning = trace.warning
+        trace.warning = warning
+        try:
+            self.do_inconsistent_inserts(inconsistency_fatal=False)
+        finally:
+            trace.warning = _trace_warning
+        self.assertEqual(["inconsistent details in skipped record: ('b',)"
+                          " ('42 32 0 8', ((),)) ('74 32 0 8', ((('a',),),))"],
+                         warnings)
+
+    def test_inconsistent_redundant_inserts_raises(self):
+        e = self.assertRaises(errors.KnitCorrupt, self.do_inconsistent_inserts,
+                              inconsistency_fatal=True)
+        self.assertContainsRe(str(e), "Knit.* corrupt: inconsistent details"
+                              " in add_records:"
+                              " \('b',\) \('42 32 0 8', \(\(\),\)\) \('74 32"
+                              " 0 8', \(\(\('a',\),\),\)\)")
+
 
 class TestLazyGroupCompress(tests.TestCaseWithTransport):
 

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2009-06-10 03:56:49 +0000
+++ b/bzrlib/tests/test_osutils.py	2009-06-30 04:13:19 +0000
@@ -240,6 +240,18 @@
         self.failIfExists('dir')
 
 
+class TestDeleteAny(tests.TestCaseInTempDir):
+
+    def test_delete_any_readonly(self):
+        # from <https://bugs.launchpad.net/bzr/+bug/218206>
+        self.build_tree(['d/', 'f'])
+        osutils.make_readonly('d')
+        osutils.make_readonly('f')
+
+        osutils.delete_any('f')
+        osutils.delete_any('d')
+
+
 class TestKind(tests.TestCaseInTempDir):
 
     def test_file_kind(self):

=== modified file 'bzrlib/tests/test_repository.py'
--- a/bzrlib/tests/test_repository.py	2009-06-26 09:24:34 +0000
+++ b/bzrlib/tests/test_repository.py	2009-06-29 15:07:51 +0000
@@ -797,6 +797,14 @@
         self.assertEqual(257, len(full_chk_records))
         self.assertSubset(simple_chk_records, full_chk_records)
 
+    def test_inconsistency_fatal(self):
+        repo = self.make_repository('repo', format='2a')
+        self.assertTrue(repo.revisions._index._inconsistency_fatal)
+        self.assertFalse(repo.texts._index._inconsistency_fatal)
+        self.assertFalse(repo.inventories._index._inconsistency_fatal)
+        self.assertFalse(repo.signatures._index._inconsistency_fatal)
+        self.assertFalse(repo.chk_bytes._index._inconsistency_fatal)
+
 
 class TestKnitPackStreamSource(tests.TestCaseWithMemoryTransport):
 

=== modified file 'bzrlib/tests/test_ui.py'
--- a/bzrlib/tests/test_ui.py	2009-06-29 13:01:20 +0000
+++ b/bzrlib/tests/test_ui.py	2009-06-30 08:30:08 +0000
@@ -174,17 +174,29 @@
         pb1.finished()
 
     def assert_get_bool_acceptance_of_user_input(self, factory):
-        factory.stdin = StringIO("y\nyes with garbage\nY\nI'm sure!\nyes\n"
-                                 "n\nnot an answer\nno\nNO\n"
+        factory.stdin = StringIO("y\n" # True
+                                 "n\n" # False
+                                 "yes with garbage\nY\n" # True
+                                 "not an answer\nno\n" # False
+                                 "I'm sure!\nyes\n" # True
+                                 "NO\n" # False
+                                 "1\n" # True
+                                 "0\n" # False
+                                 "on\n" # True
+                                 "off\n" # False
                                  "foo\n")
         factory.stdout = StringIO()
         factory.stderr = StringIO()
         # there is no output from the base factory
         self.assertEqual(True, factory.get_boolean(""))
-        self.assertEqual(True, factory.get_boolean(""))
-        self.assertEqual(True, factory.get_boolean(""))
-        self.assertEqual(False, factory.get_boolean(""))
-        self.assertEqual(False, factory.get_boolean(""))
+        self.assertEqual(False, factory.get_boolean(""))
+        self.assertEqual(True, factory.get_boolean(""))
+        self.assertEqual(False, factory.get_boolean(""))
+        self.assertEqual(True, factory.get_boolean(""))
+        self.assertEqual(False, factory.get_boolean(""))
+        self.assertEqual(True, factory.get_boolean(""))
+        self.assertEqual(False, factory.get_boolean(""))
+        self.assertEqual(True, factory.get_boolean(""))
         self.assertEqual(False, factory.get_boolean(""))
         self.assertEqual("foo\n", factory.stdin.read())
         # stdin should be empty

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2009-06-17 03:41:33 +0000
+++ b/bzrlib/transform.py	2009-06-30 04:08:12 +0000
@@ -995,18 +995,15 @@
                        self._new_contents.iteritems()]
             entries.sort(reverse=True)
             for path, trans_id, kind in entries:
-                if kind == "directory":
-                    os.rmdir(path)
-                else:
-                    os.unlink(path)
+                delete_any(path)
             try:
-                os.rmdir(self._limbodir)
+                delete_any(self._limbodir)
             except OSError:
                 # We don't especially care *why* the dir is immortal.
                 raise ImmortalLimbo(self._limbodir)
             try:
                 if self._deletiondir is not None:
-                    os.rmdir(self._deletiondir)
+                    delete_any(self._deletiondir)
             except OSError:
                 raise errors.ImmortalPendingDeletion(self._deletiondir)
         finally:



More information about the bazaar-commits mailing list