feat: add preset resolver
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
[presets.nodejs]
|
||||
conditions = ["file(package.json)"]
|
||||
|
||||
[presets.nodejs.tasks.setup.npm]
|
||||
conditions = ["file(package-lock.json)"]
|
||||
commands = ["npm install-clean --legacy-peer-deps"]
|
||||
|
||||
[presets.nodejs.tasks.setup.npm-legacy]
|
||||
conditions = ["file(package-lock.json) | not"]
|
||||
commands = ["npm install --legacy-peer-deps"]
|
||||
|
||||
[presets.nodejs.tasks.test.jest]
|
||||
conditions = ["file(node_modules/jest)"]
|
||||
commands = ["npx jest"]
|
||||
|
||||
[presets.nodejs.tasks.clean.node_modules]
|
||||
conditions = ["file(node_modules)"]
|
||||
commands = ["rm -rf node_modules"]
|
||||
@@ -0,0 +1,33 @@
|
||||
[presets.python]
|
||||
conditions = ["file(pyproject.toml)"]
|
||||
|
||||
[presets.python.tasks.setup.poetry]
|
||||
conditions = [
|
||||
"file(pyproject.toml) | get(build-system.build-backend) | equal(poetry.core.masonry.api)",
|
||||
]
|
||||
variables.python_version = "file(pyproject.toml) | get(tool.poetry.dependencies.python) | search((\\d.\\d))"
|
||||
commands = ["poetry env use {python_version}", "poetry install"]
|
||||
|
||||
[presets.python.tasks.test.pytest]
|
||||
conditions = ["file(.venv/bin/pytest)"]
|
||||
commands = [".venv/bin/pytest -p no:warnings"]
|
||||
|
||||
[presets.python.tasks.lint.isort]
|
||||
conditions = ["file(.venv/bin/isort)"]
|
||||
commands = [".venv/bin/isort --profile black --check-only ./"]
|
||||
|
||||
[presets.python.tasks.format.isort]
|
||||
conditions = ["file(.venv/bin/isort)"]
|
||||
commands = [".venv/bin/isort ./"]
|
||||
|
||||
[presets.python.tasks.lint.black]
|
||||
conditions = ["file(.venv/bin/black)"]
|
||||
commands = [".venv/bin/black --check --diff ./"]
|
||||
|
||||
[presets.python.tasks.format.black]
|
||||
conditions = ["file(.venv/bin/black)"]
|
||||
commands = [".venv/bin/black ./"]
|
||||
|
||||
[presets.python.tasks.clean.venv]
|
||||
conditions = ["file(.venv)"]
|
||||
commands = ["rm -rf .venv"]
|
||||
@@ -5,7 +5,7 @@ from typing import Optional
|
||||
|
||||
from ..entry import Entry, EntryDetector
|
||||
from ..pipe.core import PipeParser, PipeRunner
|
||||
from .util import PresetUtil
|
||||
from .resolve import PresetResolver
|
||||
|
||||
__all__ = ("PresetEntryDetector",)
|
||||
|
||||
@@ -14,28 +14,28 @@ class PresetEntryDetector(EntryDetector):
|
||||
_PIPE_PARSER = PipeParser()
|
||||
|
||||
def __init__(self, filename: Path):
|
||||
self._preset = PresetUtil.resolve_preset(filename)
|
||||
self._pipeparser = PipeParser()
|
||||
|
||||
def detect_entry(self, basepath: Path) -> Optional["Entry"]:
|
||||
preset = PresetResolver(basepath).resolve_preset()
|
||||
piperunner = PipeRunner(basepath)
|
||||
tasks = defaultdict(list)
|
||||
for preset_name, preset in self._preset.presets.items():
|
||||
filename = basepath / preset.filename
|
||||
if filename.exists():
|
||||
for task_name, task_pack in preset.tasks.items():
|
||||
for task_item_name, task in task_pack.items():
|
||||
if piperunner.check_conditions(task.conditions):
|
||||
variables = (
|
||||
{
|
||||
k: piperunner.resolve_value(v)
|
||||
for k, v in task.variables.items()
|
||||
}
|
||||
if task.variables
|
||||
else {}
|
||||
)
|
||||
tasks[task_name] += [
|
||||
command.format(**variables) for command in task.commands
|
||||
]
|
||||
for preset_name, preset in preset.presets.items():
|
||||
if not piperunner.check_conditions(preset.conditions):
|
||||
continue
|
||||
for task_name, task_pack in preset.tasks.items():
|
||||
for task_item_name, task in task_pack.items():
|
||||
if piperunner.check_conditions(task.conditions):
|
||||
variables = (
|
||||
{
|
||||
k: piperunner.resolve_value(v)
|
||||
for k, v in task.variables.items()
|
||||
}
|
||||
if task.variables
|
||||
else {}
|
||||
)
|
||||
tasks[task_name] += [
|
||||
command.format(**variables) for command in task.commands
|
||||
]
|
||||
if tasks:
|
||||
return Entry(tasks, basepath)
|
||||
|
||||
@@ -2,19 +2,19 @@ from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
__all__ = ("TaskPreset", "FilePreset", "Preset")
|
||||
__all__ = ("TaskPreset", "EntryPreset", "Preset")
|
||||
|
||||
|
||||
class TaskPreset(BaseModel):
|
||||
conditions: List[str]
|
||||
conditions: Optional[List[str]]
|
||||
variables: Optional[Dict[str, str]]
|
||||
commands: List[str]
|
||||
|
||||
|
||||
class FilePreset(BaseModel):
|
||||
filename: str
|
||||
class EntryPreset(BaseModel):
|
||||
conditions: Optional[List[str]]
|
||||
tasks: Dict[str, Dict[str, TaskPreset]]
|
||||
|
||||
|
||||
class Preset(BaseModel):
|
||||
presets: Dict[str, FilePreset]
|
||||
presets: Dict[str, EntryPreset]
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
__all__ = ("PresetResolver",)
|
||||
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable
|
||||
|
||||
import tomli
|
||||
|
||||
from ..util import merge_dicts
|
||||
from .model import Preset
|
||||
|
||||
|
||||
class PresetResolver:
|
||||
_source_cache: Dict[Path, dict] = {}
|
||||
|
||||
def __init__(self, basepath: Path):
|
||||
self._basepath = basepath
|
||||
|
||||
def iter_sources(self) -> Iterable[Path]:
|
||||
for filepath in (Path(__file__).parent / "default").iterdir():
|
||||
yield filepath
|
||||
user_preset = Path.home() / ".preset.toml"
|
||||
if user_preset.exists():
|
||||
yield user_preset
|
||||
projectpath = self._basepath
|
||||
while projectpath.exists():
|
||||
project_preset = projectpath / ".preset.toml"
|
||||
if project_preset.exists():
|
||||
yield project_preset
|
||||
if projectpath.parent == projectpath:
|
||||
break
|
||||
projectpath = projectpath.parent
|
||||
|
||||
def resolve_preset(self) -> Preset:
|
||||
result_preset_data = {}
|
||||
for filepath in self.iter_sources():
|
||||
if filepath not in self._source_cache:
|
||||
with open(filepath, "rb") as fd:
|
||||
self._source_cache[filepath] = tomli.load(fd)
|
||||
merge_dicts(result_preset_data, self._source_cache[filepath])
|
||||
return Preset(**result_preset_data)
|
||||
@@ -1,15 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
import tomli
|
||||
|
||||
from .model import Preset
|
||||
|
||||
__all__ = ("PresetUtil",)
|
||||
|
||||
|
||||
class PresetUtil:
|
||||
@classmethod
|
||||
def resolve_preset(cls, filename: Path) -> Preset:
|
||||
with open(filename, "rb") as fd:
|
||||
preset_data = tomli.load(fd)
|
||||
return Preset(**preset_data)
|
||||
Reference in New Issue
Block a user