feat: add presets
This commit is contained in:
Generated
+160
-3
@@ -1,5 +1,24 @@
|
|||||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attrs"
|
||||||
|
version = "22.2.0"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
|
||||||
|
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
|
||||||
|
dev = ["attrs[docs,tests]"]
|
||||||
|
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
|
||||||
|
tests = ["attrs[tests-no-zope]", "zope.interface"]
|
||||||
|
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "black"
|
name = "black"
|
||||||
version = "23.1.0"
|
version = "23.1.0"
|
||||||
@@ -77,6 +96,51 @@ files = [
|
|||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exceptiongroup"
|
||||||
|
version = "1.1.1"
|
||||||
|
description = "Backport of PEP 654 (exception groups)"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
|
||||||
|
{file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["pytest (>=6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.0.0"
|
||||||
|
description = "brain-dead simple config-ini parsing"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||||
|
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "isort"
|
||||||
|
version = "5.12.0"
|
||||||
|
description = "A Python utility / library to sort Python imports."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
|
||||||
|
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colors = ["colorama (>=0.4.3)"]
|
||||||
|
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
|
||||||
|
plugins = ["setuptools"]
|
||||||
|
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -129,6 +193,99 @@ files = [
|
|||||||
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
|
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||||
|
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "1.10.6"
|
||||||
|
description = "Data validation and settings management using python type hints"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"},
|
||||||
|
{file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"},
|
||||||
|
{file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"},
|
||||||
|
{file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"},
|
||||||
|
{file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"},
|
||||||
|
{file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"},
|
||||||
|
{file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"},
|
||||||
|
{file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = ">=4.2.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||||
|
email = ["email-validator (>=1.0.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "7.2.2"
|
||||||
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"},
|
||||||
|
{file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
attrs = ">=19.2.0"
|
||||||
|
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||||
|
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||||
|
iniconfig = "*"
|
||||||
|
packaging = "*"
|
||||||
|
pluggy = ">=0.12,<2.0"
|
||||||
|
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@@ -148,7 +305,7 @@ tests = ["pytest", "pytest-cov"]
|
|||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
description = "A lil' TOML parser"
|
description = "A lil' TOML parser"
|
||||||
category = "dev"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@@ -160,7 +317,7 @@ files = [
|
|||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.5.0"
|
version = "4.5.0"
|
||||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||||
category = "dev"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@@ -171,4 +328,4 @@ files = [
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "95dd14e87750e4830d773cac5ea2f5b810d406fb34b1913243c8ba6a2145db54"
|
content-hash = "6482f7b9919f0671ca3ece7b69a1783b8b7284cc54f6b0e1b390613806965f7b"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
"CommandError",
|
"CommandError",
|
||||||
"Command",
|
"CommandExecutor",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ import logging
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
logger = logging.getLogger(">")
|
logger = logging.getLogger("command")
|
||||||
|
|
||||||
|
|
||||||
class CommandError(RuntimeError):
|
class CommandError(RuntimeError):
|
||||||
@@ -17,18 +17,16 @@ class CommandError(RuntimeError):
|
|||||||
return self.args[0].decode("utf-8").strip()
|
return self.args[0].decode("utf-8").strip()
|
||||||
|
|
||||||
|
|
||||||
class Command:
|
class CommandExecutor:
|
||||||
_logger = logger
|
_logger = logger
|
||||||
|
|
||||||
def __init__(self, executor: str, *args: str) -> None:
|
def __init__(self, command: str) -> None:
|
||||||
self._executor = executor
|
self._command = command
|
||||||
self._args = args
|
|
||||||
|
|
||||||
def run(self, basepath: Path):
|
def run(self, basepath: Path):
|
||||||
args = [self._executor, *self._args]
|
self._logger.debug(self._command)
|
||||||
self._logger.debug(" ".join(args))
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
args,
|
self._command.split(" "),
|
||||||
cwd=basepath,
|
cwd=basepath,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
[presets.python]
|
||||||
|
filename = "pyproject.toml"
|
||||||
|
loader = "tomli:load"
|
||||||
|
|
||||||
|
[presets.python.tasks.setup.poetry]
|
||||||
|
conditions = { "build-system.build-backend" = "poetry.core.masonry.api" }
|
||||||
|
commands = ["poetry env use 3.8", "poetry install"]
|
||||||
|
|
||||||
|
[presets.python.tasks.test.pytest]
|
||||||
|
conditions = { "tool.poetry.group.dev.dependencies.pytest" = "*" }
|
||||||
|
commands = ["poetry run pytest -p no:warnings"]
|
||||||
|
|
||||||
|
[presets.python.tasks.lint.black]
|
||||||
|
conditions = { "tool.poetry.group.dev.dependencies.black" = "*" }
|
||||||
|
commands = ["poetry run black --check --diff ./"]
|
||||||
|
|
||||||
|
[presets.python.tasks.format.black]
|
||||||
|
conditions = { "tool.poetry.group.dev.dependencies.black" = "*" }
|
||||||
|
commands = ["poetry run black ./"]
|
||||||
|
|
||||||
|
[presets.python.tasks.lint.isort]
|
||||||
|
conditions = { "tool.poetry.group.dev.dependencies.isort" = "*" }
|
||||||
|
commands = ["poetry run isort --profile black --check-only ./"]
|
||||||
|
|
||||||
|
[presets.python.tasks.format.isort]
|
||||||
|
conditions = { "tool.poetry.group.dev.dependencies.isort" = "*" }
|
||||||
|
commands = ["poetry run isort ./"]
|
||||||
|
|
||||||
|
[presets.nodejs]
|
||||||
|
filename = "package.json"
|
||||||
|
loader = "json:load"
|
||||||
|
|
||||||
|
[presets.nodejs.tasks.setup.npm]
|
||||||
|
conditions = {}
|
||||||
|
commands = ["npm install-clean"]
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from ..entry import Entry
|
|
||||||
|
|
||||||
|
|
||||||
class NodejsEntry(Entry):
|
|
||||||
TYPE: str = "nodejs"
|
|
||||||
COMMANDS = {
|
|
||||||
"setup": [
|
|
||||||
["npm", "install-clean"],
|
|
||||||
],
|
|
||||||
"test": [
|
|
||||||
["npm", "test"],
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, basepath: Path):
|
|
||||||
super().__init__(self.TYPE, self.COMMANDS, basepath)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def detect(cls, basepath: Path) -> Optional["NodejsEntry"]:
|
|
||||||
if (basepath / "package.json").exists():
|
|
||||||
return cls(basepath)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from ..entry import Entry
|
|
||||||
|
|
||||||
|
|
||||||
class PythonEntry(Entry):
|
|
||||||
TYPE: str = "python"
|
|
||||||
COMMANDS = {
|
|
||||||
"setup": [
|
|
||||||
["poetry", "env", "use", "3.8"],
|
|
||||||
["poetry", "install"],
|
|
||||||
],
|
|
||||||
"lint": [
|
|
||||||
["poetry", "run", "black", "--check", "--diff", "./"],
|
|
||||||
["poetry", "run", "isort", "--profile", "black", "--check-only", "./"],
|
|
||||||
],
|
|
||||||
"format": [
|
|
||||||
["poetry", "run", "isort", "./"],
|
|
||||||
["poetry", "run", "black", "./"],
|
|
||||||
],
|
|
||||||
"test": [
|
|
||||||
["poetry", "run", "pytest", "-p", "no:warnings"],
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, basepath: Path):
|
|
||||||
super().__init__(self.TYPE, self.COMMANDS, basepath)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def detect(cls, basepath: Path) -> Optional["PythonEntry"]:
|
|
||||||
if (basepath / "pyproject.toml").exists():
|
|
||||||
return cls(basepath)
|
|
||||||
+47
-23
@@ -1,19 +1,20 @@
|
|||||||
__all__ = (
|
|
||||||
"EntryCommandNotImplementedError",
|
|
||||||
"Entry",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, Iterable, List, Optional
|
||||||
|
|
||||||
from .command import Command
|
from .command import CommandExecutor
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"EntryTaskNotImplementedError",
|
||||||
|
"Entry",
|
||||||
|
"EntryDetector",
|
||||||
|
"EntryResolver",
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger("entry")
|
logger = logging.getLogger("entry")
|
||||||
|
|
||||||
|
|
||||||
class EntryCommandNotImplementedError(NotImplementedError):
|
class EntryTaskNotImplementedError(NotImplementedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -22,27 +23,50 @@ class Entry:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
entry_type: str,
|
tasks: Dict[str, List[str]],
|
||||||
commands: Dict[str, List[List[str]]],
|
|
||||||
basepath: Path,
|
basepath: Path,
|
||||||
):
|
):
|
||||||
self._type = entry_type
|
self._tasks = tasks
|
||||||
self._commands = commands
|
|
||||||
self._basepath = basepath
|
self._basepath = basepath
|
||||||
|
|
||||||
def run_command(self, command_name: str):
|
def show(self):
|
||||||
if command_name == "show":
|
|
||||||
self._logger.info(f"{self}")
|
self._logger.info(f"{self}")
|
||||||
|
for task_name, commands in self._tasks.items():
|
||||||
|
self._logger.debug(f" {task_name}")
|
||||||
|
for command in commands:
|
||||||
|
self._logger.trace(f" {command}")
|
||||||
|
|
||||||
|
def run_task(self, task_name: str):
|
||||||
|
if task_name == "show":
|
||||||
|
self.show()
|
||||||
return
|
return
|
||||||
self._logger.info(f"{command_name} {self}")
|
if task_name not in self._tasks:
|
||||||
if command_name not in self._commands:
|
raise EntryTaskNotImplementedError(task_name)
|
||||||
raise EntryCommandNotImplementedError(command_name)
|
self._logger.info(f"{task_name} {self}")
|
||||||
for command in self._commands[command_name]:
|
for command in self._tasks[task_name]:
|
||||||
Command(*command).run(self._basepath)
|
CommandExecutor(command).run(self._basepath)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self._type} {str(self._basepath)}"
|
return f"{str(self._basepath)}"
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def detect(cls, basepath: Path) -> Optional["Entry"]:
|
class EntryDetector:
|
||||||
|
def detect_entry(self, basepath: Path) -> Optional["Entry"]:
|
||||||
raise NotImplemented
|
raise NotImplemented
|
||||||
|
|
||||||
|
|
||||||
|
class EntryResolver:
|
||||||
|
def __init__(self, detector: EntryDetector, ignore: List[str]):
|
||||||
|
self._detector = detector
|
||||||
|
self._ignore = ignore
|
||||||
|
|
||||||
|
def resolve(self, basepath: Path, depth: int = 128) -> Iterable[Entry]:
|
||||||
|
if basepath.is_dir():
|
||||||
|
if basepath.name in self._ignore:
|
||||||
|
return
|
||||||
|
entry = self._detector.detect_entry(basepath)
|
||||||
|
if entry:
|
||||||
|
yield entry
|
||||||
|
if depth > 0 and basepath.is_dir():
|
||||||
|
for path in basepath.iterdir():
|
||||||
|
yield from self.resolve(path, depth - 1)
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ class CustomFormatter(logging.Formatter):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def format(self, record: logging.LogRecord):
|
def format(self, record: logging.LogRecord):
|
||||||
log_fmt = colored(record.name, "green") + " " + self.FORMATS.get(record.levelno)
|
log_fmt = self.FORMATS.get(record.levelno)
|
||||||
formatter = logging.Formatter(log_fmt)
|
formatter = logging.Formatter(log_fmt)
|
||||||
return formatter.format(record)
|
return formatter.format(record)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from ast import arg
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from project_manager.logging import CustomFormatter
|
from project_manager.logging import CustomFormatter
|
||||||
@@ -43,7 +42,7 @@ def run():
|
|||||||
|
|
||||||
basepath = Path(args.path)
|
basepath = Path(args.path)
|
||||||
manager = ProjectManager(basepath)
|
manager = ProjectManager(basepath)
|
||||||
result = manager.run_command(args.task)
|
result = manager.run_task(args.task)
|
||||||
if result["failed"] > 0:
|
if result["failed"] > 0:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ from pathlib import Path
|
|||||||
from typing import Dict, Iterable
|
from typing import Dict, Iterable
|
||||||
|
|
||||||
from .command import CommandError
|
from .command import CommandError
|
||||||
from .entries.nodejs import NodejsEntry
|
from .entry import Entry, EntryResolver, EntryTaskNotImplementedError
|
||||||
from .entries.python import PythonEntry
|
from .preset.entry import PresetEntryDetector
|
||||||
from .entry import Entry, EntryCommandNotImplementedError
|
|
||||||
from .resolver import EntryDetector, EntryResolver
|
|
||||||
|
|
||||||
__all__ = ("ProjectManager",)
|
__all__ = ("ProjectManager",)
|
||||||
|
|
||||||
@@ -20,20 +18,21 @@ class ProjectManager:
|
|||||||
def __init__(self, basepath: Path):
|
def __init__(self, basepath: Path):
|
||||||
self._basepaht = basepath
|
self._basepaht = basepath
|
||||||
self._resolver = EntryResolver(
|
self._resolver = EntryResolver(
|
||||||
EntryDetector(PythonEntry, NodejsEntry), ["node_modules", ".venv", ".git"]
|
PresetEntryDetector(Path(__file__).parent / "default_preset.toml"),
|
||||||
|
["node_modules", ".venv", ".git"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def _iter_entries(self) -> Iterable[Entry]:
|
def _iter_entries(self) -> Iterable[Entry]:
|
||||||
return self._resolver.resolve(self._basepaht)
|
return self._resolver.resolve(self._basepaht)
|
||||||
|
|
||||||
def run_command(self, command_name: str) -> Dict[str, int]:
|
def run_task(self, task_name: str) -> Dict[str, int]:
|
||||||
counter = Counter()
|
counter = Counter()
|
||||||
for entry in self._iter_entries():
|
for entry in self._iter_entries():
|
||||||
try:
|
try:
|
||||||
entry.run_command(command_name)
|
entry.run_task(task_name)
|
||||||
counter["success"] += 1
|
counter["success"] += 1
|
||||||
except EntryCommandNotImplementedError:
|
except EntryTaskNotImplementedError:
|
||||||
self._logger.warn(f"{command_name} {entry}")
|
self._logger.warn(f"{task_name} {entry}")
|
||||||
counter["skipped"] += 1
|
counter["skipped"] += 1
|
||||||
except CommandError as error:
|
except CommandError as error:
|
||||||
self._logger.error(f"{entry}\n{error.output}")
|
self._logger.error(f"{entry}\n{error.output}")
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ..entry import Entry, EntryDetector
|
||||||
|
from .util import PresetUtil
|
||||||
|
|
||||||
|
__all__ = ("PresetEntryDetector",)
|
||||||
|
|
||||||
|
|
||||||
|
class PresetEntryDetector(EntryDetector):
|
||||||
|
def __init__(self, filename: Path):
|
||||||
|
self._preset = PresetUtil.resolve_preset(filename)
|
||||||
|
|
||||||
|
def detect_entry(self, basepath: Path) -> Optional["Entry"]:
|
||||||
|
tasks = defaultdict(list)
|
||||||
|
for preset_name, preset in self._preset.presets.items():
|
||||||
|
filename = basepath / preset.filename
|
||||||
|
if filename.exists():
|
||||||
|
loader = PresetUtil.resolve_loader(preset.loader)
|
||||||
|
with open(filename, "rb") as fd:
|
||||||
|
data = loader(fd)
|
||||||
|
for task_name, task_pack in preset.tasks.items():
|
||||||
|
for task_item_name, task in task_pack.items():
|
||||||
|
if PresetUtil.check_conditions(data, task.conditions):
|
||||||
|
tasks[task_name] += task.commands
|
||||||
|
if tasks:
|
||||||
|
return Entry(tasks, basepath)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
__all__ = ("TaskPreset", "FilePreset", "Preset")
|
||||||
|
|
||||||
|
|
||||||
|
class TaskPreset(BaseModel):
|
||||||
|
conditions: Dict[str, str]
|
||||||
|
commands: List[str]
|
||||||
|
|
||||||
|
|
||||||
|
class FilePreset(BaseModel):
|
||||||
|
filename: str
|
||||||
|
loader: str
|
||||||
|
tasks: Dict[str, Dict[str, TaskPreset]]
|
||||||
|
|
||||||
|
|
||||||
|
class Preset(BaseModel):
|
||||||
|
presets: Dict[str, FilePreset]
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
__all__ = ("PresetUtil",)
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
import tomli
|
||||||
|
|
||||||
|
from .model import Preset
|
||||||
|
|
||||||
|
|
||||||
|
class PresetUtil:
|
||||||
|
@classmethod
|
||||||
|
def resolve_loader(cls, loader: str) -> Any:
|
||||||
|
module_name, item_name = loader.split(":")
|
||||||
|
module = importlib.import_module(module_name)
|
||||||
|
return getattr(module, item_name)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_key_path_value(cls, key_path: str, data: dict):
|
||||||
|
path = key_path.split(".")
|
||||||
|
value = data.get(path[0])
|
||||||
|
for key in path[1:]:
|
||||||
|
if value:
|
||||||
|
value = value.get(key)
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def match_condition_value(cls, value: Any, pattern: str) -> bool:
|
||||||
|
if pattern == "*":
|
||||||
|
return bool(value)
|
||||||
|
return value == pattern
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_conditions(cls, data: dict, conditions: Dict[str, str]) -> bool:
|
||||||
|
for key, value in conditions.items():
|
||||||
|
if not cls.match_condition_value(cls.get_key_path_value(key, data), value):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_preset(cls, filename: Path) -> Preset:
|
||||||
|
with open(filename, "rb") as fd:
|
||||||
|
preset_data = tomli.load(fd)
|
||||||
|
return Preset(**preset_data)
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from typing import Iterable, List, Optional, Type
|
|
||||||
|
|
||||||
from .entry import Entry
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"EntryDetector",
|
|
||||||
"EntryResolver",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class EntryDetector:
|
|
||||||
def __init__(self, *entry_types: Type[Entry]):
|
|
||||||
self._entry_types = entry_types
|
|
||||||
|
|
||||||
def detect(self, basepath: Path) -> Optional[Entry]:
|
|
||||||
for entry_type in self._entry_types:
|
|
||||||
entry = entry_type.detect(basepath)
|
|
||||||
if entry:
|
|
||||||
return entry
|
|
||||||
|
|
||||||
|
|
||||||
class EntryResolver:
|
|
||||||
def __init__(self, detector: EntryDetector, ignore: List[str]):
|
|
||||||
self._detector = detector
|
|
||||||
self._ignore = ignore
|
|
||||||
|
|
||||||
def resolve(self, basepath: Path, depth: int = 128) -> Iterable[Entry]:
|
|
||||||
if basepath.is_dir():
|
|
||||||
if basepath.name in self._ignore:
|
|
||||||
return
|
|
||||||
entry = self._detector.detect(basepath)
|
|
||||||
if entry:
|
|
||||||
yield entry
|
|
||||||
if depth > 0 and basepath.is_dir():
|
|
||||||
for path in basepath.iterdir():
|
|
||||||
yield from self.resolve(path, depth - 1)
|
|
||||||
@@ -9,9 +9,13 @@ packages = [{ include = "project_manager" }]
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.8"
|
||||||
termcolor = "^2.2.0"
|
termcolor = "^2.2.0"
|
||||||
|
pydantic = "^1.10.6"
|
||||||
|
tomli = "^2.0.1"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^23.1.0"
|
black = "^23.1.0"
|
||||||
|
pytest = "^7.2.2"
|
||||||
|
isort = "^5.12.0"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
pm = "project_manager.main:run"
|
pm = "project_manager.main:run"
|
||||||
|
|||||||
Reference in New Issue
Block a user