From 3f649b30627848d0927a8e989c99b4b5c8b2aedc Mon Sep 17 00:00:00 2001 From: rambros3d Date: Mon, 30 Mar 2026 01:26:04 +0530 Subject: [PATCH] improve log outputs --- disco-reaper.py | 22 +++++++++++++--------- src/fluxer/writer.py | 18 ++++++++++++++++++ src/stoat/writer.py | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/disco-reaper.py b/disco-reaper.py index 6b8b233..33d1212 100644 --- a/disco-reaper.py +++ b/disco-reaper.py @@ -1,17 +1,18 @@ import sys import logging +from logging.handlers import RotatingFileHandler from src.ui.main_app import run_disco_reaper_tui from src.core.configuration import load_config def setup_logging(): try: config = load_config(create_if_missing=False) - log_level_str = config.migration.log_level.upper() + log_level_str = config.log_level.upper() level = getattr(logging, log_level_str, logging.INFO) except Exception: level = logging.INFO - handlers = [logging.FileHandler('.reaper.log', mode='a')] + handlers = [RotatingFileHandler('.reaper.log', mode='a', maxBytes=10*1024*1024, backupCount=3)] logging.basicConfig( format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', datefmt='%H:%M:%S', @@ -92,18 +93,21 @@ def cleanup_old_update(): """Removes the .old executable left behind by a Windows update.""" import os import sys + from pathlib import Path if sys.platform != "win32": return - - current_exe = sys.executable if getattr(sys, 'frozen', False) else sys.argv[0] - old_exe = current_exe + ".old" - if os.path.exists(old_exe): + # In frozen (PyInstaller) builds, sys.executable points to the temp _MEIxxxxx dir. + # sys.argv[0] always points to the real .exe on disk, so use that and resolve() it. + current_exe = Path(sys.argv[0]).resolve() + old_exe = current_exe.with_suffix(current_exe.suffix + ".old") + + if old_exe.exists(): try: - os.remove(old_exe) - except Exception: - pass + old_exe.unlink() + except Exception as e: + logging.getLogger(__name__).debug(f"Could not remove old update file {old_exe}: {e}") def main(): import os diff --git a/src/fluxer/writer.py b/src/fluxer/writer.py index dffa111..d271a7c 100644 --- a/src/fluxer/writer.py +++ b/src/fluxer/writer.py @@ -36,6 +36,7 @@ class FluxerWriter: guilds_list.append((label, str(g.id))) return guilds_list except Exception as e: + print(f"Failed to fetch Fluxer communities via HTTP: {e}") logger.error(f"Failed to fetch Fluxer communities via HTTP: {e}") raise @@ -61,6 +62,7 @@ class FluxerWriter: return w except Exception as e: print(f"Failed to manage webhook for channel {channel_id}: {e}") + logger.error(f"Failed to manage webhook for channel {channel_id}: {e}") return None async def start(self): @@ -322,6 +324,7 @@ class FluxerWriter: logger.debug(f"Fluxer: Webhook send complete, msg_id={msg.id if msg else 'None'}") return str(msg.id) if msg else None except asyncio.TimeoutError: + print(f"Fluxer: Webhook send timed out after 45s for channel {channel_id}") logger.error(f"Fluxer: Webhook send timed out after 45s for channel {channel_id}") return None else: @@ -353,6 +356,7 @@ class FluxerWriter: logger.debug(f"Fluxer: Bot send complete, msg_id={msg_data.get('id') if msg_data else 'None'}") return str(msg_data["id"]) if msg_data else None except asyncio.TimeoutError: + print(f"Fluxer: Bot send timed out after 45s for channel {channel_id}") logger.error(f"Fluxer: Bot send timed out after 45s for channel {channel_id}") return None except Exception as e: @@ -386,6 +390,7 @@ class FluxerWriter: return str(msg_data["id"]) if msg_data else None except Exception as e: print(f"Failed to send marker: {e}") + logger.error(f"Failed to send marker: {e}") return None async def create_role(self, name: str, color: int, hoist: bool, mentionable: bool, permissions: int, position: Optional[int] = None) -> str: @@ -408,6 +413,7 @@ class FluxerWriter: return str(role["id"]) except Exception as e: print(f"Failed to copy role {name}: {e}") + logger.error(f"Failed to copy role {name}: {e}") return "" async def create_emoji(self, name: str, image_bytes: bytes) -> str: @@ -473,6 +479,7 @@ class FluxerWriter: ) except Exception as e: print(f"Failed to update community metadata: {e}") + logger.error(f"Failed to update community metadata: {e}") async def remove_community_logo_and_banner(self) -> dict: """ @@ -503,6 +510,7 @@ class FluxerWriter: ) except Exception as e: print(f"Failed to remove community icon: {e}") + logger.error(f"Failed to remove community icon: {e}") # 3. Remove banner if set if has_banner: @@ -513,6 +521,7 @@ class FluxerWriter: ) except Exception as e: print(f"Failed to remove community banner: {e}") + logger.error(f"Failed to remove community banner: {e}") return { "icon": "REMOVED" if has_icon else "SKIP", @@ -544,6 +553,7 @@ class FluxerWriter: await progress_callback(ch.get("name", "Unknown"), deleted, total) except Exception as e: print(f"Failed to delete channel {ch.get('name')}: {e}") + logger.error(f"Failed to delete channel {ch.get('name')}: {e}") return deleted async def reset_channel_permissions(self, progress_callback=None) -> int: @@ -576,12 +586,14 @@ class FluxerWriter: ) ) except Exception as e: + print(f"Failed to delete overwrite {ow['id']} for channel {ch['id']}: {e}") logger.error(f"Failed to delete overwrite {ow['id']} for channel {ch['id']}: {e}") processed += 1 if progress_callback: await progress_callback(ch.get("name", "Unknown"), processed, total) except Exception as e: print(f"Failed to reset permissions for channel {ch.get('name')}: {e}") + logger.error(f"Failed to reset permissions for channel {ch.get('name')}: {e}") return processed async def set_channel_permission(self, channel_id: str, overwrite_id: str, allow: int, deny: int, is_role: bool = True): @@ -603,6 +615,7 @@ class FluxerWriter: type=0 if is_role else 1 ) except Exception as e: + print(f"Failed to set permission on channel {channel_id} for overwrite {overwrite_id}: {e}") logger.error(f"Failed to set permission on channel {channel_id} for overwrite {overwrite_id}: {e}") @@ -644,6 +657,7 @@ class FluxerWriter: await progress_callback(role.get("name", "Unknown"), deleted, total) except Exception as e: print(f"Failed to delete role {role.get('name')}: {e}") + logger.error(f"Failed to delete role {role.get('name')}: {e}") return deleted async def delete_all_emojis_and_stickers(self, progress_callback=None) -> dict: @@ -667,8 +681,10 @@ class FluxerWriter: await progress_callback(emoji.get("name", "Unknown"), "Emoji", emoji_deleted, emoji_total) except Exception as e: print(f"Failed to delete emoji {emoji.get('name')}: {e}") + logger.error(f"Failed to delete emoji {emoji.get('name')}: {e}") except Exception as e: print(f"Failed to fetch emojis: {e}") + logger.error(f"Failed to fetch emojis: {e}") # Delete stickers try: @@ -682,8 +698,10 @@ class FluxerWriter: await progress_callback(sticker.get("name", "Unknown"), "Sticker", sticker_deleted, sticker_total) except Exception as e: print(f"Failed to delete sticker {sticker.get('name')}: {e}") + logger.error(f"Failed to delete sticker {sticker.get('name')}: {e}") except Exception as e: print(f"Failed to fetch stickers: {e}") + logger.error(f"Failed to fetch stickers: {e}") return {"emojis": emoji_deleted, "stickers": sticker_deleted} diff --git a/src/stoat/writer.py b/src/stoat/writer.py index 77ed74e..d3a8c2c 100644 --- a/src/stoat/writer.py +++ b/src/stoat/writer.py @@ -58,6 +58,7 @@ class StoatWriter: else: raise asyncio.TimeoutError("Timed out waiting for Stoat to be ready") except Exception as e: + print(f"Failed to fetch Stoat servers: {e}") logger.error(f"Failed to fetch Stoat servers: {e}") raise finally: @@ -88,6 +89,7 @@ class StoatWriter: try: self._me = await self.client.fetch_user("@me") except Exception as e: + print(f"Failed to fetch bot user in StoatWriter: {e}") logger.error(f"Failed to fetch bot user in StoatWriter: {e}") self.client = None # Reset if we can't even fetch @me @@ -235,6 +237,7 @@ class StoatWriter: return results except Exception as e: + print(f"Failed to fetch Stoat channels: {e}") logger.error(f"Failed to fetch Stoat channels: {e}") return [] @@ -272,6 +275,7 @@ class StoatWriter: self._server = None # Clear cache return str(ch.id) except Exception as e: + print(f"Failed to create Stoat channel {name}: {e}") logger.error(f"Failed to create Stoat channel {name}: {e}") return "" @@ -297,6 +301,7 @@ class StoatWriter: # clone_server.py now handles all parenting bulk logic return True except Exception as e: + print(f"Failed to modify Stoat channel {channel_id}: {e}") logger.error(f"Failed to modify Stoat channel {channel_id}: {e}") return False @@ -419,6 +424,7 @@ class StoatWriter: return str(msg.id) if msg else None raise # Re-raise MissingPermission and other errors except Exception as e: + print(f"Failed to send Stoat message to {channel_id}: {e}") logger.error(f"Failed to send Stoat message to {channel_id}: {e}") raise # Let caller handle (migration loop will stop for permission errors) @@ -442,6 +448,7 @@ class StoatWriter: ) return str(msg.id) except Exception as e: + print(f"Failed to send Stoat marker to {channel_id}: {e}") logger.error(f"Failed to send Stoat marker to {channel_id}: {e}") return None @@ -470,6 +477,7 @@ class StoatWriter: return str(role.id) except Exception as e: + print(f"Failed to create Stoat role {name}: {e}") logger.error(f"Failed to create Stoat role {name}: {e}") return "" @@ -526,6 +534,7 @@ class StoatWriter: await server.set_default_permissions(s_perms) return True except Exception as e: + print(f"Failed to update Stoat default permissions: {e}") logger.error(f"Failed to update Stoat default permissions: {e}") return False @@ -536,6 +545,7 @@ class StoatWriter: emoji = await server.create_server_emoji(name=name, image=image_bytes) return str(emoji.id) except Exception as e: + print(f"Failed to create Stoat emoji {name}: {e}") logger.error(f"Failed to create Stoat emoji {name}: {e}") return "" @@ -551,6 +561,7 @@ class StoatWriter: banner=banner if banner is not None else stoat.UNDEFINED ) except Exception as e: + print(f"Failed to update Stoat guild metadata: {e}") logger.error(f"Failed to update Stoat guild metadata: {e}") async def remove_community_logo_and_banner(self) -> dict: @@ -562,12 +573,14 @@ class StoatWriter: try: await server.edit(icon=None) except Exception as e: + print(f"Failed to remove Stoat community icon: {e}") logger.error(f"Failed to remove Stoat community icon: {e}") if has_banner: try: await server.edit(banner=None) except Exception as e: + print(f"Failed to remove Stoat community banner: {e}") logger.error(f"Failed to remove Stoat community banner: {e}") return { @@ -594,6 +607,7 @@ class StoatWriter: if progress_callback: await progress_callback(name, i, total) except Exception as e: + print(f"Failed to delete Stoat channel {ch.id}: {e}") logger.error(f"Failed to delete Stoat channel {ch.id}: {e}") # To delete categories, we can wipe the categories array via server.edit to avoid 404 endpoint @@ -618,6 +632,7 @@ class StoatWriter: await progress_callback(name, j, total) j += 1 except Exception as e: + print(f"Failed to wipe Stoat categories via edit: {e}") logger.error(f"Failed to wipe Stoat categories via edit: {e}") return count @@ -634,17 +649,23 @@ class StoatWriter: logger.info(f"Danger Zone: Skipping permission reset for audit channel {name}") total -= 1 continue - # In Stoat, clearing overrides might involve setting them to default or explicitly removing the role_permissions/default_permissions - # Since we don't know an explicit "clear_overrides" method, we'll wipe them by setting empty/none if possible. - # Actually Stoat allows overwriting. Setting allow=0 deny=0 for role overrides isn't explicitly clear. - # For safety, we will just pass. If the user expects it, we'd iterate over roles and set empty. - # A quick way is to edit the channel permissions to empty state if possible. - # Let's count them anyway. - # (Fluxer writer does a loop over existing overrides, we can just return 0 for now until we inspect Stoat `PermissionOverride` deletion) + + # Fetch fresh channel to get current role_permissions + fresh_ch = await self.client.fetch_channel(ch.id) + # Clear default permissions + if hasattr(fresh_ch, "default_permissions") and fresh_ch.default_permissions is not None: + await fresh_ch.set_default_permissions(None) + + # Clear all role overrides + if hasattr(fresh_ch, "role_permissions"): + for role_id in list(fresh_ch.role_permissions.keys()): + await fresh_ch.set_role_permissions(str(role_id), allow=stoat.Permissions.none(), deny=stoat.Permissions.none()) + count += 1 if progress_callback: await progress_callback(name, i, total) except Exception as e: + print(f"Failed to reset Stoat channel permissions for {ch.id}: {e}") logger.error(f"Failed to reset Stoat channel permissions for {ch.id}: {e}") return count @@ -671,6 +692,7 @@ class StoatWriter: if "MissingPermission" in err_msg and "ViewChannel" in err_msg: logger.error(f"Stoat LOCKOUT: Bot lacks 'ViewChannel' to edit {channel_id}. " "Ensure the bot has 'Manage Server' or a role with 'Allow View Channel' rank higher than @everyone.") + print(f"Failed to set Stoat channel permission for {overwrite_id} on {channel_id}: {e}") logger.error(f"Failed to set Stoat channel permission for {overwrite_id} on {channel_id}: {e}") @@ -712,6 +734,7 @@ class StoatWriter: await emoji.delete() count += 1 except Exception as e: + print(f"Failed to delete Stoat emoji {emoji.name}: {e}") logger.error(f"Failed to delete Stoat emoji {emoji.name}: {e}") return {"emojis": count, "stickers": 0}