clarity.main

  1# coding: utf-8
  2# Main dev: alextoutcourt72
  3# New dev: MJVhack
  4import os
  5import sys
  6import argparse
  7from platform import system
  8from time import sleep
  9from typing import List
 10import pkgutil
 11import importlib
 12import inspect
 13
 14# imports robustes
 15from clarity.core import (
 16    Colors, ClarityToolsCollection, ClarityTool, hr, menu, 
 17    expand_path, ensure_dir, clear, AppConfig
 18)
 19def build_tools() -> List:
 20    """Charge dynamiquement tous les outils depuis le package clarity.tools."""
 21    tools = []
 22    # Chemin vers le package des outils
 23    import clarity.tools
 24    package = clarity.tools
 25    package_path = package.__path__
 26    package_name = package.__name__
 27
 28    # Parcourt tous les modules dans le package des outils
 29    for _, module_name, _ in pkgutil.walk_packages(package_path, package_name + '.'):
 30        try:
 31            # Importe le module dynamiquement
 32            module = importlib.import_module(module_name)
 33            
 34            # Inspecte le module à la recherche de classes d'outils
 35            for name, obj in inspect.getmembers(module, inspect.isclass):
 36                # Vérifie si la classe est une sous-classe de ClarityTool(sCollection) 
 37                # et si elle vient bien de notre module (pas une classe importée)
 38                if (issubclass(obj, ClarityTool) or issubclass(obj, ClarityToolsCollection)) and obj.__module__ == module_name:
 39                    # Ignore les classes de base elles-mêmes
 40                    if obj not in [ClarityTool, ClarityToolsCollection]:
 41                        # Instancie l'outil et l'ajoute à la liste
 42                        tools.append(obj())
 43                        print(f"{Colors.GREEN}[+] Outil chargé: {obj.TITLE}{Colors.RESET}")
 44
 45        except ImportError as e:
 46            print(f"{Colors.YELLOW}[!] Module d'outil ignoré (erreur d'import): {module_name}. {e}{Colors.RESET}")
 47        except Exception as e:
 48            print(f"{Colors.RED}[X] Erreur critique en chargeant {module_name}: {e}{Colors.RESET}")
 49            
 50    # Trie les outils par leur titre pour un affichage cohérent
 51    tools.sort(key=lambda x: x.TITLE)
 52    return tools
 53
 54all_tools = build_tools()
 55
 56class AllTools(ClarityToolsCollection):
 57    TITLE = "All tools"
 58    TOOLS = all_tools
 59    def show_info(self):
 60        clear()
 61        menu()
 62
 63# -------- Gestion du chemin d’installation -----------------------------------
 64def platform_pathfile() -> str:
 65    plat = system()
 66    if plat == 'Windows':
 67        return expand_path(r"~\claritytoolpath.txt")
 68    elif plat in ('Linux', 'Darwin'):
 69        return expand_path("~/.claritytoolpath")
 70    else:
 71        print("Your Platform is not supported")
 72        sys.exit(0)
 73
 74def default_home() -> str:
 75    return expand_path("~/.clarity-tool") if system() != 'Windows' else expand_path(r"~\Clarity-Tool")
 76
 77def load_home(set_to: str | None = None, reset=False) -> str:
 78    env = os.environ.get("CLARITY_HOME")
 79    pathfile = platform_pathfile()
 80
 81    if reset and os.path.exists(pathfile):
 82        try: os.remove(pathfile)
 83        except OSError: pass
 84
 85    if set_to:
 86        home = expand_path(set_to)
 87        with open(pathfile, "w", encoding="utf-8") as f:
 88            f.write(home)
 89        return home
 90
 91    if env:
 92        return expand_path(env)
 93
 94    if os.path.exists(pathfile):
 95        try:
 96            with open(pathfile, "r", encoding="utf-8") as f:
 97                return expand_path(f.readline().strip())
 98        except Exception:
 99            pass
100
101    home = default_home()
102    with open(pathfile, "w", encoding="utf-8") as f:
103        f.write(home)
104    return home
105
106# -------- CLI ----------------------------------------------------------------
107def parse_args():
108    p = argparse.ArgumentParser(description="Clarity Tool – modern CLI/UX")
109    p.add_argument("--list", action="store_true", help="Lister tous les outils disponibles")
110    p.add_argument("--run", type=str, help="Nom EXACT d’un outil à ouvrir")
111    p.add_argument("--action", type=str, help="Nom EXACT d’une action de l’outil (ex: Update)")
112    p.add_argument("--set-path", type=str, help="Définir le répertoire d’installation")
113    p.add_argument("--reset-path", action="store_true", help="Réinitialiser le répertoire d’installation")
114    return p.parse_args()
115
116def find_tool_by_title(title: str):
117    for t in all_tools:
118        if t.TITLE == title:
119            return t
120    return None
121
122def main():
123    args = parse_args()
124
125    # ---- Gestion du chemin d'installation ----
126    try:
127        home = load_home(set_to=args.set_path, reset=args.reset_path)
128        ensure_dir(home) # S'assure que le dossier existe, avec gestion d'erreur
129        AppConfig.HOME_PATH = home # Stocke le chemin dans la config globale
130        print(f"{Colors.DIM}Répertoire de travail des outils : {home}{Colors.RESET}")
131    except Exception as e:
132        print(f"{Colors.RED}Erreur critique avec le répertoire d'installation: {e}{Colors.RESET}")
133        sys.exit(1)
134
135    # ---- Chargement et exécution ----
136    # Le reste du code fonctionne sans changer de répertoire de travail.
137
138    # Mode liste
139    if args.list:
140        print(hr())
141        print(f"{Colors.BOLD}Outils disponibles:{Colors.RESET}")
142        for t in all_tools:
143            print(f" - {t.TITLE}")
144        print(hr())
145        sys.exit(0)
146
147    # Mode run non interactif
148    if args.run:
149        tool = find_tool_by_title(args.run)
150        if not tool:
151            print(f"{Colors.RED}Outil introuvable: {args.run}{Colors.RESET}")
152            sys.exit(2)
153        if args.action:
154            # chercher une option qui matche
155            for label, fn in getattr(tool, "OPTIONS", []):
156                if label == args.action:
157                    ret = fn()
158                    sys.exit(0 if ret in (None, 0) else ret)
159            print(f"{Colors.RED}Action introuvable sur {tool.TITLE}: {args.action}{Colors.RESET}")
160            sys.exit(3)
161        else:
162            # ouvre le menu de l’outil
163            tool.show_options(parent=AllTools())
164            sys.exit(0)
165
166    # Mode interactif
167    AllTools().show_options()
168
169if __name__ == "__main__":
170    try:
171        main()
172    except KeyboardInterrupt:
173        print(f"\n{Colors.GRAY}Fermeture demandée. À bientôt!{Colors.RESET}")
174        sleep(0.5)
def build_tools() -> List:
20def build_tools() -> List:
21    """Charge dynamiquement tous les outils depuis le package clarity.tools."""
22    tools = []
23    # Chemin vers le package des outils
24    import clarity.tools
25    package = clarity.tools
26    package_path = package.__path__
27    package_name = package.__name__
28
29    # Parcourt tous les modules dans le package des outils
30    for _, module_name, _ in pkgutil.walk_packages(package_path, package_name + '.'):
31        try:
32            # Importe le module dynamiquement
33            module = importlib.import_module(module_name)
34            
35            # Inspecte le module à la recherche de classes d'outils
36            for name, obj in inspect.getmembers(module, inspect.isclass):
37                # Vérifie si la classe est une sous-classe de ClarityTool(sCollection) 
38                # et si elle vient bien de notre module (pas une classe importée)
39                if (issubclass(obj, ClarityTool) or issubclass(obj, ClarityToolsCollection)) and obj.__module__ == module_name:
40                    # Ignore les classes de base elles-mêmes
41                    if obj not in [ClarityTool, ClarityToolsCollection]:
42                        # Instancie l'outil et l'ajoute à la liste
43                        tools.append(obj())
44                        print(f"{Colors.GREEN}[+] Outil chargé: {obj.TITLE}{Colors.RESET}")
45
46        except ImportError as e:
47            print(f"{Colors.YELLOW}[!] Module d'outil ignoré (erreur d'import): {module_name}. {e}{Colors.RESET}")
48        except Exception as e:
49            print(f"{Colors.RED}[X] Erreur critique en chargeant {module_name}: {e}{Colors.RESET}")
50            
51    # Trie les outils par leur titre pour un affichage cohérent
52    tools.sort(key=lambda x: x.TITLE)
53    return tools

Charge dynamiquement tous les outils depuis le package clarity.tools.

class AllTools(clarity.core.ClarityToolsCollection):
57class AllTools(ClarityToolsCollection):
58    TITLE = "All tools"
59    TOOLS = all_tools
60    def show_info(self):
61        clear()
62        menu()
TITLE = 'All tools'
def show_info(self):
60    def show_info(self):
61        clear()
62        menu()
def platform_pathfile() -> str:
65def platform_pathfile() -> str:
66    plat = system()
67    if plat == 'Windows':
68        return expand_path(r"~\claritytoolpath.txt")
69    elif plat in ('Linux', 'Darwin'):
70        return expand_path("~/.claritytoolpath")
71    else:
72        print("Your Platform is not supported")
73        sys.exit(0)
def default_home() -> str:
75def default_home() -> str:
76    return expand_path("~/.clarity-tool") if system() != 'Windows' else expand_path(r"~\Clarity-Tool")
def load_home(set_to: str | None = None, reset=False) -> str:
 78def load_home(set_to: str | None = None, reset=False) -> str:
 79    env = os.environ.get("CLARITY_HOME")
 80    pathfile = platform_pathfile()
 81
 82    if reset and os.path.exists(pathfile):
 83        try: os.remove(pathfile)
 84        except OSError: pass
 85
 86    if set_to:
 87        home = expand_path(set_to)
 88        with open(pathfile, "w", encoding="utf-8") as f:
 89            f.write(home)
 90        return home
 91
 92    if env:
 93        return expand_path(env)
 94
 95    if os.path.exists(pathfile):
 96        try:
 97            with open(pathfile, "r", encoding="utf-8") as f:
 98                return expand_path(f.readline().strip())
 99        except Exception:
100            pass
101
102    home = default_home()
103    with open(pathfile, "w", encoding="utf-8") as f:
104        f.write(home)
105    return home
def parse_args():
108def parse_args():
109    p = argparse.ArgumentParser(description="Clarity Tool – modern CLI/UX")
110    p.add_argument("--list", action="store_true", help="Lister tous les outils disponibles")
111    p.add_argument("--run", type=str, help="Nom EXACT d’un outil à ouvrir")
112    p.add_argument("--action", type=str, help="Nom EXACT d’une action de l’outil (ex: Update)")
113    p.add_argument("--set-path", type=str, help="Définir le répertoire d’installation")
114    p.add_argument("--reset-path", action="store_true", help="Réinitialiser le répertoire d’installation")
115    return p.parse_args()
def find_tool_by_title(title: str):
117def find_tool_by_title(title: str):
118    for t in all_tools:
119        if t.TITLE == title:
120            return t
121    return None
def main():
123def main():
124    args = parse_args()
125
126    # ---- Gestion du chemin d'installation ----
127    try:
128        home = load_home(set_to=args.set_path, reset=args.reset_path)
129        ensure_dir(home) # S'assure que le dossier existe, avec gestion d'erreur
130        AppConfig.HOME_PATH = home # Stocke le chemin dans la config globale
131        print(f"{Colors.DIM}Répertoire de travail des outils : {home}{Colors.RESET}")
132    except Exception as e:
133        print(f"{Colors.RED}Erreur critique avec le répertoire d'installation: {e}{Colors.RESET}")
134        sys.exit(1)
135
136    # ---- Chargement et exécution ----
137    # Le reste du code fonctionne sans changer de répertoire de travail.
138
139    # Mode liste
140    if args.list:
141        print(hr())
142        print(f"{Colors.BOLD}Outils disponibles:{Colors.RESET}")
143        for t in all_tools:
144            print(f" - {t.TITLE}")
145        print(hr())
146        sys.exit(0)
147
148    # Mode run non interactif
149    if args.run:
150        tool = find_tool_by_title(args.run)
151        if not tool:
152            print(f"{Colors.RED}Outil introuvable: {args.run}{Colors.RESET}")
153            sys.exit(2)
154        if args.action:
155            # chercher une option qui matche
156            for label, fn in getattr(tool, "OPTIONS", []):
157                if label == args.action:
158                    ret = fn()
159                    sys.exit(0 if ret in (None, 0) else ret)
160            print(f"{Colors.RED}Action introuvable sur {tool.TITLE}: {args.action}{Colors.RESET}")
161            sys.exit(3)
162        else:
163            # ouvre le menu de l’outil
164            tool.show_options(parent=AllTools())
165            sys.exit(0)
166
167    # Mode interactif
168    AllTools().show_options()