summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--subcmds/sync.py31
-rw-r--r--tests/test_subcmds_sync.py37
2 files changed, 42 insertions, 26 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 85ead6c31..bfbe1937d 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -1244,14 +1244,15 @@ later is required to fix a server side protocol bug.
1244 1244
1245 return False 1245 return False
1246 1246
1247 def _SetPreciousObjectsState(self, project: Project, opt): 1247 @classmethod
1248 def _SetPreciousObjectsState(cls, project: Project, opt):
1248 """Correct the preciousObjects state for the project. 1249 """Correct the preciousObjects state for the project.
1249 1250
1250 Args: 1251 Args:
1251 project: the project to examine, and possibly correct. 1252 project: the project to examine, and possibly correct.
1252 opt: options given to sync. 1253 opt: options given to sync.
1253 """ 1254 """
1254 expected = self._GetPreciousObjectsState(project, opt) 1255 expected = cls._GetPreciousObjectsState(project, opt)
1255 actual = ( 1256 actual = (
1256 project.config.GetBoolean("extensions.preciousObjects") or False 1257 project.config.GetBoolean("extensions.preciousObjects") or False
1257 ) 1258 )
@@ -1285,7 +1286,22 @@ later is required to fix a server side protocol bug.
1285 project.config.SetString("extensions.preciousObjects", None) 1286 project.config.SetString("extensions.preciousObjects", None)
1286 project.config.SetString("gc.pruneExpire", None) 1287 project.config.SetString("gc.pruneExpire", None)
1287 1288
1288 def _GCProjects(self, projects, opt, err_event): 1289 @staticmethod
1290 def _RunOneGC(project: Project, config: Optional[dict] = None) -> None:
1291 """Run auto GC on a single project."""
1292 local_config = {}
1293 if config:
1294 local_config.update(config)
1295 local_config["gc.autoDetach"] = "false"
1296 project.bare_git.gc("--auto", config=local_config)
1297
1298 @classmethod
1299 def _GCProjects(
1300 cls,
1301 projects: List[Project],
1302 opt: optparse.Values,
1303 err_event: _threading.Event,
1304 ) -> None:
1289 """Perform garbage collection. 1305 """Perform garbage collection.
1290 1306
1291 If We are skipping garbage collection (opt.auto_gc not set), we still 1307 If We are skipping garbage collection (opt.auto_gc not set), we still
@@ -1295,7 +1311,7 @@ later is required to fix a server side protocol bug.
1295 if not opt.auto_gc: 1311 if not opt.auto_gc:
1296 # Just repair preciousObjects state, and return. 1312 # Just repair preciousObjects state, and return.
1297 for project in projects: 1313 for project in projects:
1298 self._SetPreciousObjectsState(project, opt) 1314 cls._SetPreciousObjectsState(project, opt)
1299 return 1315 return
1300 1316
1301 pm = Progress( 1317 pm = Progress(
@@ -1305,9 +1321,8 @@ later is required to fix a server side protocol bug.
1305 1321
1306 tidy_dirs = {} 1322 tidy_dirs = {}
1307 for project in projects: 1323 for project in projects:
1308 self._SetPreciousObjectsState(project, opt) 1324 cls._SetPreciousObjectsState(project, opt)
1309 1325
1310 project.config.SetString("gc.autoDetach", "false")
1311 # Only call git gc once per objdir, but call pack-refs for the 1326 # Only call git gc once per objdir, but call pack-refs for the
1312 # remainder. 1327 # remainder.
1313 if project.objdir not in tidy_dirs: 1328 if project.objdir not in tidy_dirs:
@@ -1328,7 +1343,7 @@ later is required to fix a server side protocol bug.
1328 pm.update(msg=bare_git._project.name) 1343 pm.update(msg=bare_git._project.name)
1329 1344
1330 if run_gc: 1345 if run_gc:
1331 bare_git.gc("--auto") 1346 cls._RunOneGC(bare_git._project)
1332 else: 1347 else:
1333 bare_git.pack_refs() 1348 bare_git.pack_refs()
1334 pm.end() 1349 pm.end()
@@ -1345,7 +1360,7 @@ later is required to fix a server side protocol bug.
1345 try: 1360 try:
1346 try: 1361 try:
1347 if run_gc: 1362 if run_gc:
1348 bare_git.gc("--auto", config=config) 1363 cls._RunOneGC(bare_git._project, config=config)
1349 else: 1364 else:
1350 bare_git.pack_refs(config=config) 1365 bare_git.pack_refs(config=config)
1351 except GitError: 1366 except GitError:
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py
index a6be0807f..b3726d2d1 100644
--- a/tests/test_subcmds_sync.py
+++ b/tests/test_subcmds_sync.py
@@ -552,35 +552,36 @@ class GCProjectsTest(unittest.TestCase):
552 def test_GCProjects_skip_gc(self, mock_progress): 552 def test_GCProjects_skip_gc(self, mock_progress):
553 """Test that it skips GC if opt.auto_gc is False.""" 553 """Test that it skips GC if opt.auto_gc is False."""
554 self.opt.auto_gc = False 554 self.opt.auto_gc = False
555 self.cmd._SetPreciousObjectsState = mock.Mock() 555 with mock.patch.object(
556 self.cmd._GCProjects([self.project], self.opt, None) 556 sync.Sync, "_SetPreciousObjectsState"
557 self.cmd._SetPreciousObjectsState.assert_called_once_with( 557 ) as mock_set_state:
558 self.project, self.opt 558 self.cmd._GCProjects([self.project], self.opt, None)
559 ) 559 mock_set_state.assert_called_once_with(self.project, self.opt)
560 self.assertFalse(self.project.bare_git.gc.called) 560 self.assertFalse(self.project.bare_git.gc.called)
561 561
562 @mock.patch("subcmds.sync.Progress") 562 @mock.patch("subcmds.sync.Progress")
563 def test_GCProjects_sequential(self, mock_progress): 563 def test_GCProjects_sequential(self, mock_progress):
564 """Test sequential GC (jobs < 2).""" 564 """Test sequential GC (jobs < 2)."""
565 self.cmd._SetPreciousObjectsState = mock.Mock() 565 with mock.patch.object(sync.Sync, "_SetPreciousObjectsState"):
566 self.cmd._GCProjects([self.project], self.opt, None) 566 self.cmd._GCProjects([self.project], self.opt, None)
567 self.project.config.SetString.assert_called_once_with( 567 self.project.bare_git.gc.assert_called_once_with(
568 "gc.autoDetach", "false" 568 "--auto", config={"gc.autoDetach": "false"}
569 ) 569 )
570 self.project.bare_git.gc.assert_called_once_with("--auto") 570 # Verify that gc.autoDetach was not permanently set in config.
571 for call in self.project.config.SetString.call_args_list:
572 self.assertNotEqual(call.args[0], "gc.autoDetach")
571 573
572 @mock.patch("subcmds.sync.Progress") 574 @mock.patch("subcmds.sync.Progress")
573 def test_GCProjects_parallel(self, mock_progress): 575 def test_GCProjects_parallel(self, mock_progress):
574 """Test parallel GC (jobs >= 2).""" 576 """Test parallel GC (jobs >= 2)."""
575 self.opt.jobs = 2 577 self.opt.jobs = 2
576 self.cmd._SetPreciousObjectsState = mock.Mock() 578 with mock.patch.object(sync.Sync, "_SetPreciousObjectsState"):
577 579 with mock.patch("subcmds.sync._threading.Thread") as mock_thread:
578 with mock.patch("subcmds.sync._threading.Thread") as mock_thread: 580 mock_t = mock.MagicMock()
579 mock_t = mock.MagicMock() 581 mock_thread.return_value = mock_t
580 mock_thread.return_value = mock_t 582 err_event = mock.Mock()
581 err_event = mock.Mock() 583 err_event.is_set.return_value = False
582 err_event.is_set.return_value = False 584 self.cmd._GCProjects([self.project], self.opt, err_event)
583 self.cmd._GCProjects([self.project], self.opt, err_event)
584 585
585 self.assertTrue(mock_thread.called) 586 self.assertTrue(mock_thread.called)
586 587