diff options
author | Matt Schulte <matsch@google.com> | 2023-11-30 11:00:16 -0800 |
---|---|---|
committer | LUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-11-30 22:36:41 +0000 |
commit | 0dd0a830b055e177a713bbc81fc7ecdda1605643 (patch) | |
tree | ec8edb979c4ef993e21eb2418686a4e8be6ff17a | |
parent | 9f0ef5d926b29cabf8509be1b777c24c192c5e21 (diff) | |
download | git-repo-0dd0a830b055e177a713bbc81fc7ecdda1605643.tar.gz |
sync: Fix partial sync false positive
In the case of a project being removed from the manifest, and in the
path in which the project used to exist, and symlink is place to another
project repo will start to warn about partial syncs when a partial sync
did not occur.
Repro steps:
1) Create a manifest with two projects. Project a -> a/ and project b -> b/
2) Run `repo sync`
3) Remove project b from the manifest.
4) Use `link` in the manifest to link all of Project a to b/
Bug: 314161804
Change-Id: I4a4ac4f70a7038bc7e0c4e0e51ae9fc942411a34
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/395640
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Matt Schulte <matsch@google.com>
Commit-Queue: Gavin Mak <gavinmak@google.com>
-rw-r--r-- | subcmds/sync.py | 2 | ||||
-rw-r--r-- | tests/test_subcmds_sync.py | 38 |
2 files changed, 39 insertions, 1 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py index 02c1d3ae..b7236629 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -2011,7 +2011,7 @@ class LocalSyncState: | |||
2011 | delete = set() | 2011 | delete = set() |
2012 | for path in self._state: | 2012 | for path in self._state: |
2013 | gitdir = os.path.join(self._manifest.topdir, path, ".git") | 2013 | gitdir = os.path.join(self._manifest.topdir, path, ".git") |
2014 | if not os.path.exists(gitdir): | 2014 | if not os.path.exists(gitdir) or os.path.islink(gitdir): |
2015 | delete.add(path) | 2015 | delete.add(path) |
2016 | if not delete: | 2016 | if not delete: |
2017 | return | 2017 | return |
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py index 71e40489..af6bbef7 100644 --- a/tests/test_subcmds_sync.py +++ b/tests/test_subcmds_sync.py | |||
@@ -265,6 +265,44 @@ class LocalSyncState(unittest.TestCase): | |||
265 | self.assertIsNone(self.state.GetFetchTime(projA)) | 265 | self.assertIsNone(self.state.GetFetchTime(projA)) |
266 | self.assertEqual(self.state.GetFetchTime(projB), 7) | 266 | self.assertEqual(self.state.GetFetchTime(projB), 7) |
267 | 267 | ||
268 | def test_prune_removed_and_symlinked_projects(self): | ||
269 | """Removed projects that still exists on disk as symlink are pruned.""" | ||
270 | with open(self.state._path, "w") as f: | ||
271 | f.write( | ||
272 | """ | ||
273 | { | ||
274 | "projA": { | ||
275 | "last_fetch": 5 | ||
276 | }, | ||
277 | "projB": { | ||
278 | "last_fetch": 7 | ||
279 | } | ||
280 | } | ||
281 | """ | ||
282 | ) | ||
283 | |||
284 | def mock_exists(path): | ||
285 | return True | ||
286 | |||
287 | def mock_islink(path): | ||
288 | if "projB" in path: | ||
289 | return True | ||
290 | return False | ||
291 | |||
292 | projA = mock.MagicMock(relpath="projA") | ||
293 | projB = mock.MagicMock(relpath="projB") | ||
294 | self.state = self._new_state() | ||
295 | self.assertEqual(self.state.GetFetchTime(projA), 5) | ||
296 | self.assertEqual(self.state.GetFetchTime(projB), 7) | ||
297 | with mock.patch("os.path.exists", side_effect=mock_exists): | ||
298 | with mock.patch("os.path.islink", side_effect=mock_islink): | ||
299 | self.state.PruneRemovedProjects() | ||
300 | self.assertIsNone(self.state.GetFetchTime(projB)) | ||
301 | |||
302 | self.state = self._new_state() | ||
303 | self.assertIsNone(self.state.GetFetchTime(projB)) | ||
304 | self.assertEqual(self.state.GetFetchTime(projA), 5) | ||
305 | |||
268 | 306 | ||
269 | class GetPreciousObjectsState(unittest.TestCase): | 307 | class GetPreciousObjectsState(unittest.TestCase): |
270 | """Tests for _GetPreciousObjectsState.""" | 308 | """Tests for _GetPreciousObjectsState.""" |