Ver código fonte

handle deleted files when getting unstaged changes

If one of the changes that hasn't been staged involves deleting a file,
blob_from_path_and_stat() throws an OSError. Trap the error and treat
the deleted file as a change by emitting the name of the file.

This bug was reported downstream against reno as
https://bugs.launchpad.net/reno/+bug/1655719

Signed-off-by: Doug Hellmann <doug@doughellmann.com>
Doug Hellmann 8 anos atrás
pai
commit
539cd289de
2 arquivos alterados com 31 adições e 2 exclusões
  1. 10 2
      dulwich/index.py
  2. 21 0
      dulwich/tests/test_index.py

+ 10 - 2
dulwich/index.py

@@ -544,9 +544,17 @@ def get_unstaged_changes(index, root_path):
 
     for tree_path, entry in index.iteritems():
         full_path = _tree_to_fs_path(root_path, tree_path)
-        blob = blob_from_path_and_stat(full_path, os.lstat(full_path))
-        if blob.id != entry.sha:
+        try:
+            blob = blob_from_path_and_stat(full_path, os.lstat(full_path))
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+            # The file was removed, so we assume that counts as
+            # different from whatever file used to exist.
             yield tree_path
+        else:
+            if blob.id != entry.sha:
+                yield tree_path
 
 
 os_sep_bytes = os.sep.encode('ascii')

+ 21 - 0
dulwich/tests/test_index.py

@@ -503,6 +503,27 @@ class GetUnstagedChangesTests(TestCase):
 
             self.assertEqual(list(changes), [b'foo1'])
 
+    def test_get_unstaged_deleted_changes(self):
+        """Unit test for get_unstaged_changes."""
+
+        repo_dir = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, repo_dir)
+        with Repo.init(repo_dir) as repo:
+
+            # Commit a dummy file then remove it
+            foo1_fullpath = os.path.join(repo_dir, 'foo1')
+            with open(foo1_fullpath, 'wb') as f:
+                f.write(b'origstuff')
+
+            repo.stage(['foo1'])
+            repo.do_commit(b'test status', author=b'', committer=b'')
+
+            os.unlink(foo1_fullpath)
+
+            changes = get_unstaged_changes(repo.open_index(), repo_dir)
+
+            self.assertEqual(list(changes), [b'foo1'])
+
 
 class TestValidatePathElement(TestCase):