freelance-project-34-market.../python/_m.py

295 lines
4.9 KiB
Python

#!/usr/bin/env python3
# vim: set filetype=python
import logging
import json
import enum
import pathlib
import sys
import argparse
# import optparse
import dataclasses
import subprocess
import os
from typing import (
Optional,
Any,
TypeAlias,
Literal,
cast,
BinaryIO,
Generator,
ClassVar,
Self,
)
logger = logging.getLogger()
@dataclasses.dataclass
class Settings:
project_root: pathlib.Path = pathlib.Path.cwd()
env_path: pathlib.Path = project_root / 'tmp' / 'env3'
_settings: ClassVar[Optional['Settings']] = None
@classmethod
def settings(cls) -> Self:
if cls._settings is None:
cls._settings = cls()
return cls._settings
def js(argv: list[str]) -> int:
return subprocess.check_call(
[
'sudo',
'docker-compose',
'--project-directory',
Settings.settings().project_root,
'-f',
Settings.settings().project_root / 'docker' / 'js' / 'docker-compose.yml',
*argv,
]
)
def env(
argv: Optional[list[str]] = None,
mode: Literal['exec', 'subprocess'] = 'subprocess',
**kwargs: Any,
) -> Optional[subprocess.CompletedProcess[bytes]]:
env_path = Settings.settings().env_path
if not env_path.exists():
subprocess.check_call([sys.executable, '-m', 'venv', '--system-site-packages', str(env_path)])
subprocess.check_call(
[
env_path / 'bin' / 'python3',
'-m',
'pip',
'install',
'-r',
'requirements.txt',
]
)
if not argv is None:
python_path = str(env_path / 'bin' / 'python3')
if mode == 'exec':
os.execv(
python_path,
[
python_path,
*argv,
],
)
return None
elif mode == 'subprocess':
return subprocess.run(
[
python_path,
*argv,
],
**kwargs,
)
else:
raise NotImplementedError
return None
def ruff(argv: list[str]) -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
'-i',
dest='paths',
help='specify paths to check',
default=[],
action='append',
)
parser.add_argument(
'-e',
dest='exclude',
help='rules to ignore',
default=[],
action='append',
)
options, args = parser.parse_known_args(argv)
if len(options.paths) == 0:
options.paths.extend(
[
'.',
'dotfiles/.local/bin/commands',
]
)
if len(options.exclude) == 0:
options.exclude.extend(
[
'E731',
'E713',
'E714',
'E703',
]
)
res = env(
[
'-m',
'ruff',
'check',
*args,
'--output-format',
'json',
'--ignore',
','.join(options.exclude),
*options.paths,
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
assert not res is None
errors = json.loads(res.stdout.decode('utf-8'))
g: dict[str, Any] = dict()
for o in errors:
if not o['filename'] in g:
g[o['filename']] = []
g[o['filename']].append(o)
h = {k: len(v) for k, v in g.items()}
logger.info(json.dumps(errors, indent=4))
logger.info(json.dumps(h, indent=4))
def inside_env() -> bool:
try:
import numpy
return True
except Exception:
return False
# class Commands(enum.StrEnum):
# js = 'js'
# mypy = 'mypy'
# env = 'env'
# ruff = 'ruff'
# m2 = 'm2'
# def mypy(argv: list[str]) -> None:
# import online.fxreader.pr34.commands_typed.mypy as _mypy
# _mypy.run(
# argv,
# )
def host_deps(argv: list[str]) -> None:
if sys.platform in ['linux']:
subprocess.check_call(
r"""
exec yay -S $(cat requirements-archlinux.txt)
""",
shell=True,
)
else:
raise NotImplementedError
Command_args = [
'js',
'mypy',
'env',
'ruff',
'm2',
'host_deps',
]
Command: TypeAlias = Literal[
'js',
'mypy',
'env',
'ruff',
'm2',
'host_deps',
]
def run(argv: Optional[list[str]] = None) -> None:
logging.basicConfig(
level=logging.INFO,
format=('%(levelname)s:%(name)s:%(message)s:%(process)d:%(asctime)s:%(pathname)s:%(funcName)s:%(lineno)s'),
)
if argv is None:
argv = sys.argv[:]
parser = argparse.ArgumentParser()
parser.add_argument(
'command',
#'_command',
choices=[o for o in Command_args],
# required=True,
)
options, args = parser.parse_known_args(argv[1:])
assert options.command in Command_args
if len(args) > 0 and args[0] == '--':
del args[0]
# options.command = Commands(options._command)
if options.command == 'js':
js(args)
elif options.command == 'host_deps':
host_deps(args)
elif options.command == 'env':
env(
args,
mode='exec',
)
# elif options.command == 'mypy':
# if not inside_env():
# env(
# [
# pathlib.Path(__file__).parent / 'm.py',
# *argv[1:],
# ],
# mode='exec'
# )
# else:
# mypy(args)
elif options.command == 'ruff':
ruff(args)
elif options.command == 'm2':
if not inside_env():
env(['--', '_m.py', 'm2', *args])
return
import python.tasks.cython
python.tasks.cython.mypyc_build(pathlib.Path('_m.py'))
else:
raise NotImplementedError
if __name__ == '__main__':
run()