4 コミット 1ed9c9effd ... 25902e0c4a

作者 SHA1 メッセージ 日付
  Kapustlo 25902e0c4a Updated version to 3.3.0 1 年間 前
  Kapustlo c7c9033fee Added git config support 1 年間 前
  Kapustlo 8e1614ba6b Optimized process.py module 1 年間 前
  Kapustlo 6b50c08fdf Added pytest to deps 1 年間 前

+ 5 - 1
build_django/__init__.py

@@ -2,7 +2,7 @@ from argparse import ArgumentParser
 
 __author__ = 'Kapustlo'
 
-__version__ = '3.2.0'
+__version__ = '3.3.0'
 
 parser: ArgumentParser = ArgumentParser(description='Build Django project')
 
@@ -31,3 +31,7 @@ parser.add_argument('--packages', dest='packages', nargs='+', help='Additional p
 parser.add_argument('--no-compile', dest='no_compile', action='store_true', required=False, help='pip: Do not compile Python source files to bytecode')
 
 parser.add_argument('--use-ssl', dest='us_ssl', action='store_true', required=False, help='Enable SSL support for reverse proxy')
+
+parser.add_argument('--email', dest='email', required=False, default='', type=str, help='Git email if no global is specified')
+
+parser.add_argument('--username', dest='username', required=False, default='', type=str, help='Git name if no global is specified')

+ 7 - 2
build_django/__main__.py

@@ -1,6 +1,7 @@
 import sys
 import venv
 import asyncio
+from typing import cast
 from pathlib import Path
 from shlex import quote
 
@@ -26,8 +27,6 @@ async def exec():
     else:
         print('Project directory found')
 
-    repo = Repo(project_path)
-
     name = args.name
 
     print('Creating Django project...')
@@ -86,7 +85,11 @@ async def exec():
         )
     ]
 
+    repo = cast(Repo, None)  # In order to fix linter errors
+
     if args.git:
+        repo = Repo(project_path)
+
         tasks.append(repo.init())
 
     print('Creating files...')
@@ -98,6 +101,8 @@ async def exec():
     tasks = []
 
     if args.git and args.commit:
+        await repo.setup(args.email, args.username)
+
         await repo.add(('.',), _v=True)
 
         task = repo.commit(args.commit_message, _v=True)

+ 54 - 10
build_django/utils/git.py

@@ -1,27 +1,71 @@
-from typing import Union, Iterable
+import asyncio
 from shlex import quote
-from pathlib import Path
+from subprocess import SubprocessError
+from dataclasses import dataclass
 from asyncio.subprocess import Process
+from typing import Iterable, Any, cast
 
 from .shell import Shell
 
 
-class Repo(Shell):
-    pwd: Path
+class GitShell(Shell):
+    async def cmd(self, args, **kwargs) -> Process:
+        params = self._kwargs_to_params(**kwargs)
+
+        return await self.run(('git', *args, *params))
+
+
+@dataclass
+class ConfigSection(GitShell):
+    section: str
+    
+    async def value(self, name: str) -> str:
+        try:
+            process = await self.cmd(('config', '--get', f'{self.section}.{name}'))
+        except SubprocessError:
+            return ''
 
-    def __init__(self, path: Union[str, Path]):
-        super().__init__()
+        return cast(str, process.stdout)
 
-        self.cd(path)
+    async def set(self, name: str, value: Any) -> Any:
+        await self.cmd(('config', f'{self.section}.{name}', quote(value)))
 
+        return self
+
+
+class Config(GitShell):
+    def section(self, name: str) -> ConfigSection:
+        return ConfigSection(self.pwd, name)
+
+
+class Repo(GitShell):
     @property
     def initialized(self) -> bool:
         return (self.pwd / '.git').exists()
 
-    async def cmd(self, args, **kwargs) -> Process:
-        params = self._kwargs_to_params(**kwargs)
+    @property
+    def config(self) -> Config:
+        return Config(self.pwd)
+
+    async def setup(self, email: str = '', name: str = ''):
+        tasks = []
+
+        section = self.config.section('user')
+
+        cur_name = await section.value('name')
+
+        if not cur_name:
+            tasks.append(section.set('name', name))
+
+        cur_email = await section.value('email')
+
+        if not cur_email:
+            tasks.append(section.set('email', email))
+
+        await asyncio.gather(*tasks)
+
+        return self
 
-        return await self.run(('git', *args, *params))
 
     async def init(self) -> Process:
         if self.initialized:

+ 7 - 13
build_django/utils/process.py

@@ -1,12 +1,10 @@
-import sys
 import asyncio
 from pathlib import Path
-from shlex import quote
 from subprocess import SubprocessError
 from asyncio.subprocess import PIPE, Process
 from typing import Union, Iterable
 
-SYS_ENCODING = sys.getdefaultencoding()
+from . import system
 
 
 async def run_cmd(
@@ -15,18 +13,14 @@ async def run_cmd(
     **kwargs
 ) -> Process:
     if cwd:
-        args = (
-            'cd',
-            quote(str(cwd)),
-            '&&',
-            *args
-        )
+        cwd = str(cwd)
 
     cmd = ' '.join(args)
 
     kwargs = {
         'stdout': PIPE,
         'stderr': PIPE,
+        'cwd': cwd,
         **kwargs
     }
 
@@ -34,10 +28,7 @@ async def run_cmd(
 
     result = await process.communicate()
 
-    out, err = [
-        item.decode(SYS_ENCODING)
-        if isinstance(item, bytes) else item for item in result
-    ]
+    out, err = result
 
     code = process.returncode
 
@@ -45,6 +36,9 @@ async def run_cmd(
         raise SubprocessError(f'{code}: {err}')
 
     if out:
+        if isinstance(out, bytes):
+            out = system.decode(out)
+
         print(out)
 
     return process

+ 8 - 2
build_django/utils/shell.py

@@ -1,12 +1,18 @@
 from pathlib import Path
+from dataclasses import dataclass
 from typing import Union, Iterable
 from asyncio.subprocess import Process
 
 from .process import run_cmd
 
 
+@dataclass
 class Shell:
-    pwd: Union[Path, None] = None
+    _pwd: Union[str, Path, None]
+    
+    @property
+    def pwd(self) -> Path:
+        return Path('./' if self._pwd is None else self._pwd).absolute()
 
     def _kwargs_to_params(self, **kwargs: dict[str, str]) -> list[str]:
         result = []
@@ -29,7 +35,7 @@ class Shell:
         if path.is_file():
             raise ValueError(f'{path} is a file')
 
-        self.pwd = path
+        self._pwd = path
 
         return self
 

+ 6 - 0
build_django/utils/system.py

@@ -0,0 +1,6 @@
+from sys import getdefaultencoding
+
+SYS_ENCODING = getdefaultencoding()
+
+def decode(b: bytes) -> str:
+    return b.decode(SYS_ENCODING)

+ 9 - 1
requirements.txt

@@ -1,6 +1,6 @@
-wheel
 aiofiles==22.1.0
 asgiref==3.5.0
+attrs==22.1.0
 bleach==5.0.0
 certifi==2021.10.8
 cffi==1.15.0
@@ -9,13 +9,20 @@ commonmark==0.9.1
 cryptography==36.0.2
 Django==4.0.4
 docutils==0.18.1
+exceptiongroup==1.0.4
 idna==3.3
 importlib-metadata==4.11.3
+iniconfig==1.1.1
 jeepney==0.8.0
 keyring==23.5.0
+packaging==21.3
 pkginfo==1.8.2
+pluggy==1.0.0
 pycparser==2.21
 Pygments==2.11.2
+pyparsing==3.0.9
+pytest==7.2.0
+pytest-asyncio==0.20.2
 readme-renderer==35.0
 requests==2.27.1
 requests-toolbelt==0.9.1
@@ -24,6 +31,7 @@ rich==12.2.0
 SecretStorage==3.3.2
 six==1.16.0
 sqlparse==0.4.2
+tomli==2.0.1
 twine==4.0.0
 urllib3==1.26.9
 webencodings==0.5.1

+ 1 - 1
tests/manage.sh

@@ -11,7 +11,7 @@ then
 
   if [[ $2 = "" ]]
   then
-    time python -m build_django --dir "./tests/test_projects/$(openssl rand -hex 20)" --git --commit --debug --migrate --no-compile --use-ssl --commit-message "Test commit"  test_project
+    time python -m build_django --dir "./tests/test_projects/$(openssl rand -hex 20)" --git --commit --debug --migrate --no-compile --use-ssl --commit-message "Test commit" --email "test@example.com" --username "Kapustlo"  test_project
   fi
 elif [[ $1 = "clear" ]]
 then