ソースを参照

- Add command and subcommand argument

fanch 1 年間 前
コミット
9aa5f75a16

+ 1 - 1
setup.py

@@ -29,7 +29,7 @@ def get_files(path):
 
 setup(
     name="djangotools",
-    version="0.1.3",
+    version="0.1.4",
     description="A short description of the project.",
     author="François GAUTRAIS",
     install_requires=install_requires,

+ 54 - 0
src/djangotools/cmdline/commands/install/__init__.py

@@ -0,0 +1,54 @@
+from collections import defaultdict
+
+from djangotools.cmdline import Command, CronManager, Argument, CommandData
+
+from djangotools.cmdline import tasks
+from djangotools.config import get_settings
+from djangotools.run import Migrate
+
+
+class InstallCommand(Command):
+    NAME = "install"
+    ALIASES = ["i"]
+
+    HELP = "Lance le script d'installation"
+    ARGUMENT = [
+        Argument("--no-interative", "-I", action="store_true", help="Ne demande pas d'inforamtion à l'utilisateur"),
+        Argument("--user", "-u", help="Le nom d'utilisateur s'il n'existe aucun utilisateur"),
+        Argument("--mail", "-m", help="Le mail s'il n'existe aucun utilisateur"),
+        Argument("--password", "-p", help="Le mot de passe s'il n'existe aucun utilisateur"),
+    ]
+
+
+    def migrate(self, data):
+        handler = Migrate()
+        handler.handle()
+
+    def _prompt(self, prompt, required):
+        while True:
+            ret = input(f"{prompt}: ")
+            ret = ret.split("\n")[0] if isinstance(ret, str) else ret
+            if not ret:
+                if required: continue
+                else: return ret
+            return ret
+
+    def prompt(self, data, name, prompt, required):
+        return getattr(data, name) or self._prompt(prompt, required)
+
+    def create_user(self, data):
+        from django.contrib.auth.models import User
+        if len(User.objects.all()) > 0: return
+        username = self.prompt(data, "user", "Nom d'utilisateur", True)
+        password = self.prompt(data, "password", "Mot de passe", True)
+        email = self.prompt(data, "mail", "Mail", False)
+        print(f"Création du super utilisateur {username}")
+
+        User.objects.create_user(username=username, password=password, email=email, is_superuser=True, is_staff=True)
+
+
+    def run(self, data):
+        self.migrate(data)
+        self.create_user(data)
+
+

+ 1 - 1
src/djangotools/cmdline/commands/migrate/__init__.py

@@ -8,7 +8,7 @@ class MigrateCommand(Command):
 
     NAME = "migrate"
     HELP = "Lance les migrations"
-
+    ALIASES = "m"
     ARGUMENT = [
     ]
 

+ 1 - 1
src/djangotools/cmdline/commands/run/__init__.py

@@ -15,7 +15,7 @@ class RunCommand(Command):
 
     NAME = "run"
     HELP = "Lance le serveur avec la config de production"
-
+    ALIASES = "r"
     ARGUMENT = [
         Argument("-p", "--pid-file", help="Chemin du ficher PID" ),
         Argument("-o", "--stdout", nargs=1, help="Crée le server dans un autre processus"),

+ 156 - 0
src/djangotools/cmdline/commands/user/__init__.py

@@ -0,0 +1,156 @@
+import sys
+from collections import defaultdict
+
+from django.contrib.auth.hashers import make_password
+from djangotools.cmdline import Command, CronManager, Argument, CommandData
+
+from djangotools.cmdline import tasks
+from djangotools.cmdline.common.command import SubCommand
+from djangotools.config import get_settings
+from djangotools.run import Migrate
+
+
+
+
+def User():
+
+    from django.contrib.auth.models import User
+    return User
+
+def _prompt(prompt, required, is_bool):
+    if is_bool:
+        prompt = f"{prompt} (o/n)"
+    while True:
+        ret = input(f"{prompt}: ")
+        ret = ret.split("\n")[0] if isinstance(ret, str) else ret
+        if not ret or is_bool and ret.lower() not in "on":
+            if required or is_bool:
+                continue
+            else:
+                return ret
+        if is_bool:
+            return ret.lower() == "o"
+        return ret
+
+
+def prompt(data, name, prompt, required, is_bool=False):
+    return getattr(data, name) or _prompt(prompt, required, is_bool)
+
+class CreateUser(SubCommand):
+    NAME = "create"
+    ALIASES = "c"
+    HELP = "Création d'utilisateur"
+    ARGUMENT = [
+        Argument("name"),
+        Argument("--password", "-p", help="Mot de passe"),
+        Argument("--email", "-e", help="E mail"),
+        Argument("--staff", "-s", help="Staff", action="store_true", default=False),
+        Argument("--root", "-r", help="Superutilisateur", action="store_true", default=False),
+        Argument("--ask", "-a", help="Demander via la console les informations", action="store_true")
+    ]
+
+    def run(self, data):
+        password = data.password if not data.ask else prompt(data, "password", "Mot de passe", False)
+        email = data.email if not data.ask else prompt(data, "email", "Email", False)
+        staff = data.staff if not data.ask else prompt(data, "staff", "Est staff", False, True)
+        root = data.root if not data.ask else prompt(data, "root", "Est root", False, True)
+        try:
+            User().objects.create_user(username=data.name, password=password, email=email,
+                                     is_staff=staff, is_superuser=root)
+        except Exception as err:
+            print(f"Erreur: {err}", file=sys.stderr)
+            return
+
+class EditUser(SubCommand):
+    NAME = "edit"
+    ALIASES = "e"
+    HELP = "Edition d'utilisateur"
+    ARGUMENT = [
+        Argument("name"),
+        Argument("--name", "-n", help="Nouveau nom", dest="new_name"),
+        Argument("--password", "-p", help="Mot de passe"),
+        Argument("--email", "-e", help="E mail"),
+        Argument("--staff", "-s", help="Staff", action="store_true", default=None),
+        Argument("--root", "-r", help="Superutilisateur", action="store_true", default=None),
+        Argument("--ask", "-a", help="Demander via la console les informations", action="store_true")
+    ]
+
+    def run(self, data):
+        try:
+            user = User().objects.get(username=data.name)
+        except User().DoesNotExist as err:
+            print(f"L'utlisateur {data.name} n'existe pas", file=sys.stderr)
+            return
+
+        if data.ask:
+            user.username = prompt(data, "new_name", "Nouveau nom", False)
+            user.email = prompt(data, "email", "Email", False)
+            user.password = make_password(prompt(data, "password", "password", True))
+            user.is_staff = prompt(data, "staff", "Est staff", False, True)
+            user.is_superuser = prompt(data, "root", "Est root", False, True)
+        else:
+            if data.new_name is not None: user.username = data.new_name
+            if data.email is not None: user.username = data.email
+            if data.password is not None: user.password = make_password(data.password)
+            if data.staff is not None: user.is_staff = data.staff
+            if data.root is not None: user.is_superuser = data.root
+        try:
+            user.save()
+        except Exception as err:
+            print(f"Erreur: {err}", file=sys.stderr)
+            return
+
+class RemoveUser(SubCommand):
+    NAME = "remove"
+    ALIASES = "r"
+    HELP = "Suppression d'utilisateurs"
+    ARGUMENT = [
+        Argument("names", nargs='+')
+    ]
+
+    def run(self, data):
+        for name in data.names:
+            try:
+                user = User().objects.get(username=name)
+            except User().DoesNotExist:
+                print(f"Erreur l'utilisateur {name} n'existe pas", file=sys.stderr)
+                continue
+
+
+            try:
+                user.delete()
+            except Exception as err:
+                print(f"Erreur pour l'utilisateur {name}: {err}", file=sys.stderr)
+
+
+
+class ListUser(SubCommand):
+    NAME = "list"
+    ALIASES = "l"
+    HELP = "Liste les utilisateur"
+    ARGUMENT = [
+        Argument("search", nargs='?')
+    ]
+
+    def run(self, data):
+        content = [x.username for x in User().objects.all()]
+        if data.search:
+            search = data.search.lower()
+            content = [x for x in content if search in x.lower()]
+        print(f"Liste des utilisateurs:\n","  "+"  ".join(content))
+
+
+class UserCommand(Command):
+    NAME = "user"
+    ALIASES = ["u"]
+
+    HELP = "Gère les utilisateur"
+    ARGUMENT = [
+        CreateUser(),
+        EditUser(),
+        RemoveUser(),
+        ListUser()
+    ]
+
+    def run(self, data):
+        self.print_help()

+ 24 - 9
src/djangotools/cmdline/common/args.py

@@ -2,7 +2,7 @@ import argparse
 import os
 import sys
 
-from djangotools.cmdline.common.command import Command
+from djangotools.cmdline.common.command import Command, Argument, SubCommand
 from djangotools.config import load_app
 from django.conf import settings
 
@@ -19,17 +19,32 @@ class ArgsParser(argparse.ArgumentParser):
         self.add_argument("-s", "--settings",  help="Module de settings à utiliser")
         from djangotools.cmdline import commands
         for cmd in Command.load([commands, *commands_dirs]):
-            kwargs = {}
-            if cmd.HELP: kwargs["help"] = cmd.HELP
-            if cmd.ALIASES: kwargs["aliases"] = cmd.ALIASES
-            p = parser.add_parser(cmd.NAME, **kwargs)
-            for x in cmd.ARGUMENT or []:
+            self._load_command(parser, cmd)
+
+    def _load_command(self, parser, cmd):
+        kwargs = {}
+        if cmd.HELP: kwargs["help"] = cmd.HELP
+        if cmd.ALIASES: kwargs["aliases"] = cmd.ALIASES
+
+
+        p = parser.add_parser(cmd.NAME, **kwargs)
+        cmd.parser = p
+        sub_parser = None
+        for x in cmd.ARGUMENT or []:
+            if isinstance(x, Argument):
                 p.add_argument(*x.args, **x.kwargs)
-            p.set_defaults(classe = cmd)
+            elif isinstance(x, SubCommand):
+                if sub_parser is None:
+                    if not hasattr(cmd, "current_subparsers"):
+                        cmd.current_subparsers = p.add_subparsers()
+                    self._load_command(cmd.current_subparsers, x)
+
+
+        p.set_defaults(classe = cmd)
 
-    def parse(self, args):
+    def parse(self, args, settings_module=None):
         ret = self.parse_args(args=args)
-        settings = ret.settings or self.default_settings_module
+        settings = ret.settings or settings_module or self.default_settings_module
 
         if settings:
             os.environ["DJANGO_SETTINGS_MODULE"] = settings

+ 22 - 2
src/djangotools/cmdline/common/command.py

@@ -18,6 +18,9 @@ class Argument:
         self.args = args
         self.kwargs = kwargs
 
+
+
+
 class ThreadWrapper(threading.Thread):
 
     def __init__(self, fct):
@@ -28,13 +31,14 @@ class ThreadWrapper(threading.Thread):
         return self.fct()
 
 
-class Command:
+class BaseCommandMxin:
+
     NAME = None
     HELP = None
     ALIASES = []
 
     ARGUMENT=None
-
+    parser = None
     def __init__(self):
         pass
 
@@ -44,6 +48,11 @@ class Command:
     def run(self, data):
         raise NotImplementedError()
 
+    def print_help(self):
+        self.parser.print_help()
+
+class Command(BaseCommandMxin):
+
     @classmethod
     def thread_run(cls, data):
         cmd = cls()
@@ -65,6 +74,17 @@ class Command:
 
 
 
+class SubCommand(BaseCommandMxin):
 
+    def __init__(self, name=None, aliases=None, help=None, arguments=None, fct=None):
+        super().__init__()
+        self.NAME = name or self.NAME
+        self.HELP = help or self.HELP
+        self.ALIASES = aliases or self.ALIASES
+        self.ARGUMENT = arguments or self.ARGUMENT
+        self.fct=fct
+
+    def __call__(self, *args, **kwargs):
+        return self
 
 

+ 0 - 1
src/djangotools/config/__init__.py

@@ -39,7 +39,6 @@ def load_app(settings_module, app_dir=None, populate=True):
 
     if app_dir:
         os.environ["APP_DIR"] = str(app_dir)
-    print("Print loading app_dir ", os.environ.get("APP_DIR"))
 
     if not "DJANGO_SETTINGS_MODULE" in os.environ:
         os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)