295 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			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()
 |