feat: add structure analysis tool for reorganizing app directory

This commit is contained in:
2026-01-11 20:28:14 +00:00
parent 59ff14eb99
commit 3b4a8b3e5b
2 changed files with 745 additions and 0 deletions

476
STRUCTURE_ANALYSIS.json Normal file
View File

@@ -0,0 +1,476 @@
{
"analysis": {
"total_files": 4372,
"packages": {
"com.efiAnalytics.apps.ts.dashboard": 103,
"com.efiAnalytics.apps.ts.dashboard.renderers": 24,
"com.efiAnalytics.apps.ts.tuningViews": 51,
"com.efiAnalytics.apps.ts.tuningViews.tuneComps": 16,
"com.efiAnalytics.dialogs": 7,
"com.efiAnalytics.remotefileaccess": 8,
"com.efiAnalytics.remotefileaccess.http": 4,
"com.efiAnalytics.simulators": 4,
"com.efiAnalytics.testers": 2,
"com.efiAnalytics.tunerStudio.panels": 77,
"com.efiAnalytics.tunerStudio.search": 33,
"com.efiAnalytics.tuningwidgets.panels": 99,
"com.efiAnalytics.tuningwidgets.portEditor": 33,
"com.efiAnalytics.ui": 349,
"com.efiAnalytics.ui.calculators.calculator": 10,
"com.efiAnalytics.xcp.master.responseProcessors": 14,
"com.ha.common.windows": 3,
"A": 25,
"B": 19,
"C": 6,
"D": 4,
"E": 10,
"F": 4,
"G": 224,
"H": 5,
"I": 18,
"J": 10,
"K": 9,
"L": 56,
"M": 2,
"N": 4,
"O": 11,
"P": 3,
"Q": 4,
"R": 14,
"S": 15,
"T": 5,
"U": 2,
"V": 10,
"W": 83,
"X": 4,
"Y": 4,
"Z": 6,
"b": 1,
"c": 6,
"d": 13,
"e": 5,
"ExceptionInDPackage": 1,
"f": 9,
"g": 11,
"AkGolfImpl": 1,
"PropertiesExtensionInHPackage": 1,
"h": 8,
"AkComponentHotel": 2,
"i": 10,
"j": 3,
"k": 6,
"l": 1,
"m": 10,
"n": 14,
"AyComponentNovember": 1,
"o": 7,
"p": 45,
"q": 9,
"r": 16,
"s": 10,
"t": 120,
"u": 11,
"v": 7,
"w": 3,
"x": 2,
"y": 6,
"z": 14,
"aA": 11,
"aB": 3,
"aC": 4,
"aD": 6,
"aE": 7,
"aF": 1,
"aG": 8,
"aH": 4,
"aI": 24,
"aJ": 3,
"aK": 8,
"aL": 6,
"aM": 10,
"aN": 5,
"aO": 26,
"aP": 549,
"aQ": 1,
"aR": 29,
"aS": 12,
"aT": 1,
"aU": 5,
"aV": 27,
"aW": 18,
"aX": 13,
"aY": 29,
"aZ": 14,
"bA": 6,
"bB": 18,
"bC": 16,
"bD": 41,
"bE": 17,
"bF": 42,
"bG": 33,
"bI": 9,
"bJ": 3,
"bK": 3,
"bL": 18,
"bM": 5,
"bN": 21,
"bO": 13,
"bP": 2,
"bQ": 25,
"bR": 5,
"bS": 18,
"bT": 30,
"bU": 8,
"bV": 5,
"bW": 6,
"aa": 6,
"ab": 1,
"ac": 26,
"SerializableImplExceptionprintstacktrace": 4,
"ad": 4,
"ae": 24,
"af": 15,
"ag": 3,
"ah": 3,
"ai": 9,
"aj": 13,
"ak": 88,
"al": 6,
"am": 11,
"an": 5,
"ap": 4,
"aq": 7,
"ar": 12,
"as": 14,
"at": 5,
"au": 3,
"IOExceptioninvpackageInWPackage": 1,
"av": 15,
"aw": 7,
"ax": 64,
"ay": 16,
"az": 20,
"ba": 1,
"bb": 38,
"bc": 13,
"bd": 1,
"be": 49,
"bf": 13,
"bg": 20,
"bh": 25,
"bi": 8,
"bj": 2,
"bk": 18,
"bl": 18,
"bm": 5,
"bn": 5,
"bo": 12,
"bp": 3,
"bq": 4,
"br": 54,
"GInterfaceBr": 1,
"bs": 30,
"GComponentBs": 1,
"bt": 155,
"GInterfaceBt": 2,
"bu": 1,
"bv": 1,
"bw": 10,
"bx": 25,
"by": 14,
"bz": 2,
"bH": 57,
"ao": 467,
"linear_algebra": 3
},
"mismatches": 539,
"obfuscated_packages": [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"aA",
"aB",
"aC",
"aD",
"aE",
"aF",
"aG",
"aH",
"aI",
"aJ",
"aK",
"aL",
"aM",
"aN",
"aO",
"aP",
"aQ",
"aR",
"aS",
"aT",
"aU",
"aV",
"aW",
"aX",
"aY",
"aZ",
"bA",
"bB",
"bC",
"bD",
"bE",
"bF",
"bG",
"bI",
"bJ",
"bK",
"bL",
"bM",
"bN",
"bO",
"bP",
"bQ",
"bR",
"bS",
"bT",
"bU",
"bV",
"bW",
"aa",
"ab",
"ac",
"ad",
"ae",
"af",
"ag",
"ah",
"ai",
"aj",
"ak",
"al",
"am",
"an",
"ap",
"aq",
"ar",
"as",
"at",
"au",
"av",
"aw",
"ax",
"ay",
"az",
"ba",
"bb",
"bc",
"bd",
"be",
"bf",
"bg",
"bh",
"bi",
"bj",
"bk",
"bl",
"bm",
"bn",
"bo",
"bp",
"bq",
"br",
"bs",
"bt",
"bu",
"bv",
"bw",
"bx",
"by",
"bz",
"bH",
"ao"
],
"proper_packages": [
"com.efiAnalytics.apps.ts.dashboard",
"com.efiAnalytics.apps.ts.dashboard.renderers",
"com.efiAnalytics.apps.ts.tuningViews",
"com.efiAnalytics.apps.ts.tuningViews.tuneComps",
"com.efiAnalytics.dialogs",
"com.efiAnalytics.remotefileaccess",
"com.efiAnalytics.remotefileaccess.http",
"com.efiAnalytics.simulators",
"com.efiAnalytics.testers",
"com.efiAnalytics.tunerStudio.panels",
"com.efiAnalytics.tunerStudio.search",
"com.efiAnalytics.tuningwidgets.panels",
"com.efiAnalytics.tuningwidgets.portEditor",
"com.efiAnalytics.ui",
"com.efiAnalytics.ui.calculators.calculator",
"com.efiAnalytics.xcp.master.responseProcessors",
"com.ha.common.windows"
],
"other_packages": [
"ExceptionInDPackage",
"AkGolfImpl",
"PropertiesExtensionInHPackage",
"AkComponentHotel",
"AyComponentNovember",
"SerializableImplExceptionprintstacktrace",
"IOExceptioninvpackageInWPackage",
"GInterfaceBr",
"GComponentBs",
"GInterfaceBt",
"linear_algebra"
]
},
"sample_mismatches": [
{
"file": "obfuscated_packages/e/EComponentFoxtrot.java",
"declared": "ExceptionInDPackage",
"location": "e"
},
{
"file": "obfuscated_packages/g/ThreadExtensionInGPackage.java",
"declared": "AkGolfImpl",
"location": "g"
},
{
"file": "obfuscated_packages/g/GInterfaceDelta.java",
"declared": "PropertiesExtensionInHPackage",
"location": "g"
},
{
"file": "obfuscated_packages/h/ThreadExtensionInHPackage.java",
"declared": "AkComponentHotel",
"location": "h"
},
{
"file": "obfuscated_packages/h/ThreadedInHPackage.java",
"declared": "AkComponentHotel",
"location": "h"
},
{
"file": "obfuscated_packages/n/NInterfaceKilo.java",
"declared": "AyComponentNovember",
"location": "n"
},
{
"file": "obfuscated_packages/ac/AbstractUsingArrayList.java",
"declared": "SerializableImplExceptionprintstacktrace",
"location": "ac"
},
{
"file": "obfuscated_packages/ac/AcInterfaceQuebec.java",
"declared": "SerializableImplExceptionprintstacktrace",
"location": "ac"
},
{
"file": "obfuscated_packages/ac/AcInterfaceRomeo.java",
"declared": "SerializableImplExceptionprintstacktrace",
"location": "ac"
},
{
"file": "obfuscated_packages/ac/AcInterfaceXray.java",
"declared": "SerializableImplExceptionprintstacktrace",
"location": "ac"
},
{
"file": "obfuscated_packages/av/AvComponentAlpha.java",
"declared": "IOExceptioninvpackageInWPackage",
"location": "av"
},
{
"file": "obfuscated_packages/br/UIWindowClose.java",
"declared": "GInterfaceBr",
"location": "br"
},
{
"file": "obfuscated_packages/bs/UIWindowCloseUsingContainer.java",
"declared": "GComponentBs",
"location": "bs"
},
{
"file": "obfuscated_packages/bt/IndicatorReadoutPanel.java",
"declared": "GInterfaceBt",
"location": "bt"
},
{
"file": "obfuscated_packages/bt/ExceptionEqualsinaipackage.java",
"declared": "GInterfaceBt",
"location": "bt"
},
{
"file": "obfuscated_packages/utils_logging/DebugLogger.java",
"declared": "bH",
"location": "utils_logging"
},
{
"file": "obfuscated_packages/utils_logging/OSDetector.java",
"declared": "bH",
"location": "utils_logging"
},
{
"file": "obfuscated_packages/utils_logging/DeadlockDetector.java",
"declared": "bH",
"location": "utils_logging"
},
{
"file": "obfuscated_packages/utils_logging/FileUtils.java",
"declared": "bH",
"location": "utils_logging"
},
{
"file": "obfuscated_packages/utils_logging/StringUtils.java",
"declared": "bH",
"location": "utils_logging"
}
]
}

269
reorganize_structure.py Normal file
View File

@@ -0,0 +1,269 @@
#!/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
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():
"""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)}")
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
if '--execute-option-1' in sys.argv or '--option-1' in sys.argv:
execute_option1()
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()