From 48f8b2d5a9a911ab8255dfdf619f694afabfbb5c Mon Sep 17 00:00:00 2001 From: shmyga Date: Sat, 1 Aug 2026 21:06:30 +0300 Subject: [PATCH] feat: add docker preset --- README.md | 4 +-- poetry.lock | 31 ++++++++++++++++++- project_manager/{ => common}/command.py | 0 .../{logging_custom.py => logging_colored.py} | 2 +- project_manager/entry.py | 2 +- project_manager/manager.py | 2 +- project_manager/pipe/type/file.py | 28 +++++++---------- project_manager/preset/default/docker.toml | 16 ++++++++++ project_manager/preset/default/python.toml | 15 ++++++--- project_manager/preset/resolve.py | 4 +-- project_manager/runner.py | 4 +-- pyproject.toml | 1 + tests/__init__.py | 2 +- 13 files changed, 80 insertions(+), 31 deletions(-) rename project_manager/{ => common}/command.py (100%) rename project_manager/common/{logging_custom.py => logging_colored.py} (98%) create mode 100644 project_manager/preset/default/docker.toml diff --git a/README.md b/README.md index ec979f7..2dacd7f 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ pm [-v] [-vv] ## Presets locations - default presets `$PROJECT_MANAGER/project_manager/preset/default/*.toml` -- user preset `$HOME/.preset.toml` -- project preset `./.preset.toml` +- user preset `$HOME/.pm.toml` +- project preset `./.pm.toml` ## Preset format diff --git a/poetry.lock b/poetry.lock index 615401b..ee0e518 100644 --- a/poetry.lock +++ b/poetry.lock @@ -119,6 +119,20 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "dotenv" +version = "0.9.9" +description = "Deprecated package" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9"}, +] + +[package.dependencies] +python-dotenv = "*" + [[package]] name = "iniconfig" version = "2.0.0" @@ -448,6 +462,21 @@ pygments = ">=2.7.2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] +[[package]] +name = "python-dotenv" +version = "1.2.2" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pytokens" version = "0.4.1" @@ -617,4 +646,4 @@ typing-extensions = ">=4.12.0" [metadata] lock-version = "2.1" python-versions = ">=3.14,<4.0" -content-hash = "4d19fc54b607d98b8ae277fa031223daac3cdda07545cb03ed5875688018936e" +content-hash = "df515ec4294fec745964e448a08d5fd797ae3a096208330ae9ccb1d2ea82276a" diff --git a/project_manager/command.py b/project_manager/common/command.py similarity index 100% rename from project_manager/command.py rename to project_manager/common/command.py diff --git a/project_manager/common/logging_custom.py b/project_manager/common/logging_colored.py similarity index 98% rename from project_manager/common/logging_custom.py rename to project_manager/common/logging_colored.py index 7a34358..96ebf5c 100644 --- a/project_manager/common/logging_custom.py +++ b/project_manager/common/logging_colored.py @@ -59,7 +59,7 @@ def addLoggingLevel(levelName, levelNum, methodName=None): addLoggingLevel("TRACE", logging.DEBUG - 5) -class CustomFormatter(logging.Formatter): +class ColoredFormatter(logging.Formatter): def __init__(self, fmt): super().__init__() self.fmt = fmt diff --git a/project_manager/entry.py b/project_manager/entry.py index 082141d..02d6e6a 100644 --- a/project_manager/entry.py +++ b/project_manager/entry.py @@ -2,7 +2,7 @@ import logging from pathlib import Path from typing import Iterable -from .command import CommandExecutor +from .common.command import CommandExecutor __all__ = ( "EntryTaskNotImplementedError", diff --git a/project_manager/manager.py b/project_manager/manager.py index e395ba3..268a83f 100644 --- a/project_manager/manager.py +++ b/project_manager/manager.py @@ -3,7 +3,7 @@ from collections import Counter from pathlib import Path from typing import Iterable -from .command import CommandError +from .common.command import CommandError from .entry import Entry, EntryResolver, EntryTaskNotImplementedError from .preset.entry import PresetEntryDetector diff --git a/project_manager/pipe/type/file.py b/project_manager/pipe/type/file.py index 768ddc4..3f876e3 100644 --- a/project_manager/pipe/type/file.py +++ b/project_manager/pipe/type/file.py @@ -1,7 +1,10 @@ +import json from pathlib import Path from typing import Any -from ...util import reflect +import dotenv +import tomli + from ..core import Pipe __all__ = ( @@ -11,31 +14,24 @@ __all__ = ( class FileData: - _LOADERS = { - ".toml": "tomli:load", - ".json": "json:load", - } def __init__(self, filepath: Path, loader: str | None = None): self._filepath = filepath self._loader = loader self._data = None - def _resolve_loader(self, filepath: Path): - loader = self._loader or self._LOADERS.get(filepath.suffix) - return reflect(loader) if loader else None - def _load_data(self): - loader = self._resolve_loader(self._filepath) - with open(self._filepath, "rb") as fd: - if loader: - self._data = loader(fd) - else: - self._data = fd.read() + if self._filepath.suffix == ".toml": + return tomli.loads(self._filepath.read_text()) + elif self._filepath.suffix == ".json": + return json.loads(self._filepath.read_text()) + elif self._filepath.suffix == ".env" or self._filepath.name == ".env": + return dotenv.dotenv_values(self._filepath) + return self._filepath.read_text() def get(self, key: str): if self._data is None and self._filepath.exists(): - self._load_data() + self._data = self._load_data() if self._data: return self._data.get(key) return None diff --git a/project_manager/preset/default/docker.toml b/project_manager/preset/default/docker.toml new file mode 100644 index 0000000..184e091 --- /dev/null +++ b/project_manager/preset/default/docker.toml @@ -0,0 +1,16 @@ +[presets.docker] +conditions = ["file(Dockerfile)"] + +# build +[presets.docker.tasks.build.default] +variables.docker_target = "file(.env) | get(DOCKER_PROJECTS)" +variables.docker_name = "file(pyproject.toml) | get(project.name)" +variables.docker_group = "file(.env) | get(DOCKER_GROUP)" +commands = [ + # "docker build --target {docker_target} -t {docker_group}/{docker_name} . -f Dockerfile", + "docker build -t {docker_group}/{docker_name} . -f Dockerfile", +] + +# publish +[presets.docker.tasks.publish.default] +commands = ["docker publish"] diff --git a/project_manager/preset/default/python.toml b/project_manager/preset/default/python.toml index 114be3e..b5c5ac8 100644 --- a/project_manager/preset/default/python.toml +++ b/project_manager/preset/default/python.toml @@ -1,6 +1,7 @@ [presets.python] conditions = ["file(pyproject.toml)"] +# setup [presets.python.tasks.setup.poetry] conditions = [ "file(pyproject.toml) | get(build-system.build-backend) | equal(poetry.core.masonry.api)", @@ -11,12 +12,14 @@ commands = [ "poetry install", ] +# build [presets.python.tasks.build.poetry] conditions = [ "file(pyproject.toml) | get(build-system.build-backend) | equal(poetry.core.masonry.api)", ] commands = ["poetry build"] +# publish [presets.python.tasks.publish.poetry] conditions = [ "file(pyproject.toml) | get(build-system.build-backend) | equal(poetry.core.masonry.api)", @@ -25,10 +28,12 @@ conditions = [ variables.python_repository = "file(poetry.toml) | get(repositories) | key(0)" commands = ["poetry publish -r {python_repository}"] +# test [presets.python.tasks.test.pytest] conditions = ["file(.venv/bin/pytest)"] commands = [".venv/bin/python -m pytest"] +# lint [presets.python.tasks.lint.pylint] conditions = ["file(.venv/bin/pylint)"] commands = [".venv/bin/pylint ./"] @@ -37,18 +42,20 @@ commands = [".venv/bin/pylint ./"] 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 --profile black ./"] - [presets.python.tasks.lint.black] conditions = ["file(.venv/bin/black)"] commands = [".venv/bin/black --check --diff ./"] +# format +[presets.python.tasks.format.isort] +conditions = ["file(.venv/bin/isort)"] +commands = [".venv/bin/isort --profile black ./"] + [presets.python.tasks.format.black] conditions = ["file(.venv/bin/black)"] commands = [".venv/bin/black ./"] +# clean [presets.python.tasks.clean.venv] conditions = ["file(.venv)"] commands = ["rm -rf .venv"] diff --git a/project_manager/preset/resolve.py b/project_manager/preset/resolve.py index 0c3de51..6ee61a7 100644 --- a/project_manager/preset/resolve.py +++ b/project_manager/preset/resolve.py @@ -31,13 +31,13 @@ class PresetResolver: if self._config.default: yield from (Path(__file__).parent / "default").iterdir() if self._config.user: - user_preset = Path.home() / ".preset.toml" + user_preset = Path.home() / ".pm.toml" if user_preset.exists(): yield user_preset if self._config.project: projectpath = self._basepath while projectpath.exists(): - project_preset = projectpath / ".preset.toml" + project_preset = projectpath / ".pm.toml" if project_preset.exists(): yield project_preset if projectpath.parent == projectpath: diff --git a/project_manager/runner.py b/project_manager/runner.py index 9aa8cb5..5d8f478 100644 --- a/project_manager/runner.py +++ b/project_manager/runner.py @@ -4,7 +4,7 @@ from argparse import ArgumentParser from pathlib import Path from typing import Self -from .common.logging_custom import CustomFormatter +from .common.logging_colored import ColoredFormatter from .manager import ProjectManager @@ -27,7 +27,7 @@ class ProjectManagerRunner: logging_level = logging.CRITICAL stdout_handler = logging.StreamHandler() - stdout_handler.setFormatter(CustomFormatter("%(message)s")) + stdout_handler.setFormatter(ColoredFormatter("%(message)s")) logging.basicConfig( level=logging_level, diff --git a/pyproject.toml b/pyproject.toml index 6d2a6ab..f0831b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ dependencies = [ "termcolor (>=3.3.0,<4.0.0)", "pydantic (>=2.13.4,<3.0.0)", "tomli (>=2.4.1,<3.0.0)", + "dotenv (>=0.9.9,<0.10.0)", ] [dependency-groups] diff --git a/tests/__init__.py b/tests/__init__.py index 340b29e..ff5c0e0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1 @@ -import project_manager.common.logging_custom +import project_manager.common.logging_colored