# HG changeset patch # User hodgestar # Date 1266659314 0 # Node ID 5f95a6f38490402f1a49414bab9a43d05cb0d1e2 # Parent 90903d6cc932308dcff3f80b79c30cb889fdfab0 Add upgrade method that cleans up .log.levels files which at one point where not properly deleted when builds were removed (with test). Fix fix_log_levels_misnaming test to not rely on the order of logging messages (log message order reflects the directory listing order which can vary). diff --git a/bitten/tests/upgrades.py b/bitten/tests/upgrades.py --- a/bitten/tests/upgrades.py +++ b/bitten/tests/upgrades.py @@ -286,7 +286,6 @@ self.assertEqual(rows, [(str(model.schema_version),)]) def test_fix_log_levels_misnaming(self): - logfiles = { "1.log": "", "2.log": "", @@ -318,24 +317,60 @@ path = os.path.join(self.logs_dir, filename) origfile = filename in logfiles and filename or filename.replace("levels", "level") self.assertEqual(logfiles[origfile], open(path).read()) + self.assertTrue(filename not in expected_deletions) self.assertEqual(len(filenames), len(logfiles) - len(expected_deletions)) - warns = [rec for rec in logwatch.records if rec.levelname == 'WARNING'] - self.assertEqual(len(warns), 1) - for warn in warns: - self.assertTrue(warn.getMessage().startswith("Error renaming")) + logs = sorted(logwatch.records, key=lambda rec: rec.getMessage()) + self.assertEqual(len(logs), 5) + self.assertTrue(logs[0].getMessage().startswith( + "Deleted 1 stray log level (0 errors)")) + self.assertTrue(logs[1].getMessage().startswith( + "Deleted stray log level file 4.log.level")) + self.assertTrue(logs[2].getMessage().startswith( + "Error renaming")) + self.assertTrue(logs[3].getMessage().startswith( + "Renamed 1 incorrectly named log level files from previous migrate (1 errors)")) + self.assertTrue(logs[4].getMessage().startswith( + "Renamed incorrectly named log level file")) - infos = [rec for rec in logwatch.records if rec.levelname == 'INFO'] - self.assertEqual(len(infos), 4) - for info in infos[:1]: - self.assertTrue(info.getMessage().startswith("Renamed incorrectly named log level file")) - self.assertTrue(infos[1].getMessage().startswith( - "Deleted stray log level file 4.log.level")) - self.assertTrue(infos[2].getMessage().startswith( - "Renamed 1 incorrectly named log level files from previous migrate (1 errors)")) - self.assertTrue(infos[3].getMessage().startswith( - "Deleted 1 stray log level (0 errors)")) + def test_remove_stray_log_levels_files(self): + logfiles = { + "1.log": "", + "1.log.levels": "info\n", + "2.log.levels": "info\ninfo\n", + } + expected_deletions = [ + "2.log.levels", + ] + + for filename, data in logfiles.items(): + path = os.path.join(self.logs_dir, filename) + logfile = open(path, "w") + logfile.write(data) + logfile.close() + + logwatch = LogWatcher(logging.INFO) + self.env.log.setLevel(logging.INFO) + self.env.log.addHandler(logwatch) + + upgrades.remove_stray_log_levels_files(self.env, None) + + filenames = sorted(os.listdir(self.logs_dir)) + for filename in filenames: + path = os.path.join(self.logs_dir, filename) + self.assertEqual(logfiles[filename], open(path).read()) + self.assertTrue(filename not in expected_deletions) + + self.assertEqual(len(filenames), len(logfiles) - len(expected_deletions)) + + logs = sorted(logwatch.records, key=lambda rec: rec.getMessage()) + self.assertEqual(len(logs), 2) + self.assertTrue(logs[0].getMessage().startswith( + "Deleted 1 stray log levels (0 errors)")) + self.assertTrue(logs[1].getMessage().startswith( + "Deleted stray log levels file 2.log.levels")) + def suite(): suite = unittest.TestSuite() diff --git a/bitten/upgrades.py b/bitten/upgrades.py --- a/bitten/upgrades.py +++ b/bitten/upgrades.py @@ -451,6 +451,36 @@ env.log.info("Renamed %d incorrectly named log level files from previous migrate (%d errors)", rename_count, rename_error_count) env.log.info("Deleted %d stray log level (%d errors)", delete_count, delete_error_count) +def remove_stray_log_levels_files(env, db): + """Remove *.log.levels files without a matching *.log file (old Bitten versions did not delete .log.levels files when builds were deleted)""" + logs_dir = env.config.get("bitten", "logs_dir", "log/bitten") + if not os.path.isabs(logs_dir): + logs_dir = os.path.join(env.path, logs_dir) + if not os.path.isdir(logs_dir): + return + + delete_count = 0 + delete_error_count = 0 + + for filename in os.listdir(logs_dir): + if not filename.endswith('.log.levels'): + continue + + log_filename = os.path.splitext(filename)[0] + full_log_filename = os.path.join(logs_dir, log_filename) + full_filename = os.path.join(logs_dir, filename) + + if not os.path.exists(full_log_filename): + try: + os.remove(full_filename) + delete_count += 1 + env.log.info("Deleted stray log levels file %s", filename) + except Exception, e: + delete_error_count += 1 + env.log.warning("Error removing stray log levels file %s: %s", filename, e) + + env.log.info("Deleted %d stray log levels (%d errors)", delete_count, delete_error_count) + def recreate_rule_with_int_id(env, db): """Recreates the bitten_rule table with an integer id column rather than a text one.""" from bitten.model import TargetPlatform @@ -531,5 +561,5 @@ 8: [add_filename_to_logs,migrate_logs_to_files], 9: [recreate_rule_with_int_id], 10: [add_config_platform_rev_index_to_build, fix_sequences], - 11: [fix_log_levels_misnaming], + 11: [fix_log_levels_misnaming, remove_stray_log_levels_files], }