diff --git a/NEWS b/NEWS index 9cbbd3d0c..cd53c1bd7 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,11 @@ * Add basic 'dulwich pull' command. (Jelmer Vernooij) + BUG FIXES + + * Cope with existing submodules during pull. + (Jelmer Vernooij, #505) + 0.17.0 2017-03-01 TEST FIXES diff --git a/dulwich/index.py b/dulwich/index.py index f8245d1a0..f793ec73b 100644 --- a/dulwich/index.py +++ b/dulwich/index.py @@ -508,10 +508,12 @@ def build_index_from_tree(root_path, index_path, object_store, tree_id, if not os.path.exists(os.path.dirname(full_path)): os.makedirs(os.path.dirname(full_path)) - # FIXME: Merge new index into working tree + # TODO(jelmer): Merge new index into working tree if S_ISGITLINK(entry.mode): - os.mkdir(full_path) + if not os.path.isdir(full_path): + os.mkdir(full_path) st = os.lstat(full_path) + # TODO(jelmer): record and return submodule paths else: obj = object_store[entry.sha] st = build_file_from_blob(obj, entry.mode, full_path, @@ -560,6 +562,7 @@ def get_unstaged_changes(index, root_path): for tree_path, entry in index.iteritems(): full_path = _tree_to_fs_path(root_path, tree_path) + # TODO(jelmer): handle S_ISGITLINK(entry.mode) here try: blob = blob_from_path_and_stat(full_path, os.lstat(full_path)) except OSError as e: @@ -568,6 +571,11 @@ def get_unstaged_changes(index, root_path): # The file was removed, so we assume that counts as # different from whatever file used to exist. yield tree_path + except IOError as e: + if e.errno != errno.EISDIR: + raise + # The file was changed to a directory, so consider it removed. + yield tree_path else: if blob.id != entry.sha: yield tree_path diff --git a/dulwich/tests/test_index.py b/dulwich/tests/test_index.py index 4fdaea3a9..f0666f306 100644 --- a/dulwich/tests/test_index.py +++ b/dulwich/tests/test_index.py @@ -512,6 +512,47 @@ def test_git_submodule(self): self.assertEqual(index[b'c'][4], S_IFGITLINK) # mode self.assertEqual(index[b'c'][8], c.id) # sha + def test_git_submodule_exists(self): + repo_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, repo_dir) + with Repo.init(repo_dir) as repo: + filea = Blob.from_string(b'file alalala') + + subtree = Tree() + subtree[b'a'] = (stat.S_IFREG | 0o644, filea.id) + + c = Commit() + c.tree = subtree.id + c.committer = c.author = b'Somebody ' + c.commit_time = c.author_time = 42342 + c.commit_timezone = c.author_timezone = 0 + c.parents = [] + c.message = b'Subcommit' + + tree = Tree() + tree[b'c'] = (S_IFGITLINK, c.id) + + os.mkdir(os.path.join(repo_dir, 'c')) + repo.object_store.add_objects( + [(o, None) for o in [tree]]) + + build_index_from_tree(repo.path, repo.index_path(), + repo.object_store, tree.id) + + # Verify index entries + index = repo.open_index() + self.assertEqual(len(index), 1) + + # filea + apath = os.path.join(repo.path, 'c/a') + self.assertFalse(os.path.exists(apath)) + + # dir c + cpath = os.path.join(repo.path, 'c') + self.assertTrue(os.path.isdir(cpath)) + self.assertEqual(index[b'c'][4], S_IFGITLINK) # mode + self.assertEqual(index[b'c'][8], c.id) # sha + class GetUnstagedChangesTests(TestCase):