#!/usr/bin/env python3 """ Reorganize the app directory structure: 1. Analyze current state (packages, dependencies, structure) 2. Propose reorganization plan 3. Execute restructuring (move files to match packages OR update package declarations) """ import os import re import json import shutil from pathlib import Path from collections import defaultdict def analyze_current_structure(): """Analyze the current app directory structure""" base_dir = '/home/rewrich/Documents/GitHub/tustu/app' analysis = { 'packages': defaultdict(list), 'mismatches': [], 'dependencies': defaultdict(set), 'total_files': 0 } print("Analyzing current structure...") for root, dirs, files in os.walk(base_dir): for file in files: if not file.endswith('.java'): continue filepath = os.path.join(root, file) rel_path = os.path.relpath(filepath, base_dir) analysis['total_files'] += 1 try: with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() # Extract package declaration pkg_match = re.search(r'package\s+([\w.]+);', content) if pkg_match: declared_pkg = pkg_match.group(1) analysis['packages'][declared_pkg].append(rel_path) # Check if location matches package dir_path = os.path.dirname(rel_path) if dir_path.startswith('obfuscated_packages/'): # Remove obfuscated_packages prefix expected_pkg = dir_path.replace('obfuscated_packages/', '').replace(os.sep, '.') else: expected_pkg = dir_path.replace(os.sep, '.') if declared_pkg != expected_pkg and expected_pkg != '.': analysis['mismatches'].append({ 'file': rel_path, 'declared': declared_pkg, 'location': expected_pkg }) # Extract imports to map dependencies imports = re.findall(r'import\s+([\w.]+);', content) if pkg_match: for imp in imports: imp_pkg = '.'.join(imp.split('.')[:-1]) # Get package part if imp_pkg: analysis['dependencies'][declared_pkg].add(imp_pkg) except Exception as e: pass return analysis def propose_reorganization(analysis): """Propose a reorganization strategy""" print(f"\n{'='*70}") print("CURRENT STATE ANALYSIS") print(f"{'='*70}") print(f"Total Java files: {analysis['total_files']}") print(f"Unique packages: {len(analysis['packages'])}") print(f"Package/location mismatches: {len(analysis['mismatches'])}") # Categorize packages obfuscated_pkgs = [p for p in analysis['packages'].keys() if len(p) <= 2 and p.isalpha()] proper_pkgs = [p for p in analysis['packages'].keys() if p.startswith('com.') or p.startswith('org.')] other_pkgs = [p for p in analysis['packages'].keys() if p not in obfuscated_pkgs and p not in proper_pkgs] print(f"\nPackage breakdown:") print(f" Obfuscated packages (1-2 letters): {len(obfuscated_pkgs)}") print(f" Proper packages (com.*, org.*): {len(proper_pkgs)}") print(f" Other packages: {len(other_pkgs)}") print(f"\n{'='*70}") print("REORGANIZATION OPTIONS") print(f"{'='*70}") print("\nOption 1: MOVE FILES (Fast, preserves package names)") print(" - Move files from obfuscated_packages/* to app/* to match package declarations") print(" - Pros: No source code changes needed") print(" - Cons: Obfuscated packages (A, B, C, etc.) remain at root level") print(f" - Files affected: {len(analysis['mismatches'])}") print("\nOption 2: RENAME PACKAGES (Clean, better organization)") print(" - Update all package declarations to include 'obfuscated_packages.' prefix") print(" - Update all imports accordingly") print(" - Pros: All obfuscated code stays in obfuscated_packages/ subdirectory") print(" - Cons: Requires modifying source code") print(f" - Files affected: {len(analysis['mismatches'])} + all importers") print("\nOption 3: HYBRID (Recommended)") print(" - Keep proper packages (com.*, org.*) where they are") print(" - Rename obfuscated packages to meaningful names") print(" - Group related obfuscated packages into logical modules") print(" - Example: A → com.efiAnalytics.core.ui") print(" - Pros: Clean structure, no short package names") print(" - Cons: Most work, but best long-term solution") return { 'obfuscated_pkgs': obfuscated_pkgs, 'proper_pkgs': proper_pkgs, 'other_pkgs': other_pkgs } def execute_option1(force=False): """Option 1: Move files to match their package declarations""" base_dir = '/home/rewrich/Documents/GitHub/tustu/app' print(f"\n{'='*70}") print("EXECUTING OPTION 1: Move files to match package declarations") print(f"{'='*70}\n") moves = [] # Find all files that need to be moved for root, dirs, files in os.walk(os.path.join(base_dir, 'obfuscated_packages')): for file in files: if not file.endswith('.java'): continue filepath = os.path.join(root, file) try: with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() # Extract package declaration pkg_match = re.search(r'package\s+([\w.]+);', content) if pkg_match: declared_pkg = pkg_match.group(1) # Calculate target path based on package target_dir = os.path.join(base_dir, declared_pkg.replace('.', os.sep)) target_path = os.path.join(target_dir, file) if filepath != target_path: moves.append({ 'from': filepath, 'to': target_path, 'package': declared_pkg }) except Exception as e: print(f"Error reading {filepath}: {e}") print(f"Found {len(moves)} files to move") if not moves: print("No files need to be moved!") return print("\nSample moves:") for move in moves[:5]: print(f" {os.path.relpath(move['from'], base_dir)}") print(f" → {os.path.relpath(move['to'], base_dir)}") if not force: response = input(f"\nProceed with moving {len(moves)} files? (yes/no): ") if response.lower() != 'yes': print("Cancelled.") return # Execute moves moved_count = 0 errors = [] for move in moves: try: # Create target directory os.makedirs(os.path.dirname(move['to']), exist_ok=True) # Check if target exists if os.path.exists(move['to']): errors.append(f"Target already exists: {move['to']}") continue # Move file shutil.move(move['from'], move['to']) moved_count += 1 if moved_count % 100 == 0: print(f" Moved {moved_count} files...") except Exception as e: errors.append(f"Error moving {move['from']}: {e}") print(f"\n✅ Moved {moved_count} files") if errors: print(f"\n⚠️ {len(errors)} errors:") for err in errors[:10]: print(f" {err}") # Clean up empty directories print("\nCleaning up empty directories...") removed_dirs = 0 for root, dirs, files in os.walk(os.path.join(base_dir, 'obfuscated_packages'), topdown=False): if not files and not dirs: try: os.rmdir(root) removed_dirs += 1 except: pass print(f"Removed {removed_dirs} empty directories") print(f"\n{'='*70}") print("MOVE COMPLETE!") print(f"{'='*70}") print(f"Files moved: {moved_count}") print(f"Errors: {len(errors)}") print("\nNext steps:") print("1. Try compiling: cd app && javac -d build/classes -sourcepath . TunerStudio.java") print("2. Review any compilation errors") print("3. Consider Option 3 for proper reorganization later") def main(): import sys force = '--force' in sys.argv if '--execute-option-1' in sys.argv or '--option-1' in sys.argv: execute_option1(force=force) return analysis = analyze_current_structure() categories = propose_reorganization(analysis) # Save analysis output = { 'analysis': { 'total_files': analysis['total_files'], 'packages': {k: len(v) for k, v in analysis['packages'].items()}, 'mismatches': len(analysis['mismatches']), 'obfuscated_packages': categories['obfuscated_pkgs'], 'proper_packages': categories['proper_pkgs'], 'other_packages': categories['other_pkgs'] }, 'sample_mismatches': analysis['mismatches'][:20] } with open('/home/rewrich/Documents/GitHub/tustu/STRUCTURE_ANALYSIS.json', 'w') as f: json.dump(output, f, indent=2) print(f"\n{'='*70}") print("Analysis saved to: STRUCTURE_ANALYSIS.json") print(f"{'='*70}") print("\nNext steps:") print("1. Review the options above") print("2. Choose reorganization strategy") print("3. Run with --execute-option-N flag to proceed") if __name__ == '__main__': main()