From 8ef1ab7fec870bffaec1a516322d420c29bc54b8 Mon Sep 17 00:00:00 2001 From: Dexoron Date: Wed, 11 Feb 2026 23:54:41 +0800 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D1=83=20=D0=BE?= =?UTF-8?q?=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B8=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B8=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E,=20=D0=B2=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B0=D1=8F=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=88=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BD=D1=8B=20=D0=B8=20=D0=B8=D0=BD=D1=81?= =?UTF-8?q?=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- .vscode/settings.json | 3 --- CHANGELOG.md | 10 ++++++++++ README.md | 22 ++++++++++++++++++++++ dcr | 3 +++ src/dcr/cli/__init__.py | 3 +++ src/dcr/cli/build.py | 19 +++++++++---------- src/dcr/cli/clean.py | 20 ++++++++++++++++++++ src/dcr/cli/init.py | 37 +++++++++++++++++++++---------------- src/dcr/cli/new.py | 38 ++++++++++++++++++++++---------------- src/dcr/cli/run.py | 14 ++++---------- src/dcr/config.py | 36 ++++++++++++++++++++++++++++++++++++ src/dcr/main.py | 2 ++ src/dcr/utils/fs.py | 8 ++++++++ 14 files changed, 163 insertions(+), 56 deletions(-) delete mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100755 dcr create mode 100644 src/dcr/cli/clean.py create mode 100644 src/dcr/utils/fs.py diff --git a/.gitignore b/.gitignore index c007186..c9098eb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ dist/ wheels/ *.egg-info .venv -sandbox/* \ No newline at end of file +sandbox/* +.ruff_cache/ +.vscode/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5480842..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "kiroAgent.configureMCP": "Disabled" -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1707447 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## [0.1.0] - 2026-02-11 +Первый публичный релиз. + +Добавлено: +- Базовые команды `new`, `init`, `build`, `run`, `clean` +- Профили сборки `debug` и `release` +- Шаблоны `dcr.toml` и `src/main.c` + diff --git a/README.md b/README.md index 7153f4d..d4fdc7e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ DCR — это утилита для управления проектами н - Создание нового проекта или инициализация текущей директории - Сборка проекта в профилях `debug` и `release` - Запуск собранного бинарника +- Очистка результатов сборки - Генерация минимального шаблона C-проекта ## Быстрый старт @@ -47,6 +48,9 @@ hello/ Запуск вручную: `./target//main` +### `dcr clean` +Удаляет папку `target` в корне проекта. + ## Профили сборки Поддерживаются два профиля: - `--debug` (по умолчанию) — флаги: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG` @@ -55,6 +59,24 @@ hello/ ## Конфигурация Основной файл проекта — `dcr.toml`. Сейчас он создается автоматически и служит точкой входа для будущих настроек. +Пример `dcr.toml`: +``` +[package] +name = "hello" +version = "0.1.0" +language = "c" +compiler = "clang" + +[dependencies] +``` + +## Установка в PATH +Чтобы вызывать `dcr` из любой директории, можно сделать symlink в `~/.local/bin`: +```sh +ln -s "$PWD/dcr" ~/.local/bin/dcr +``` +Убедитесь, что `~/.local/bin` находится в `PATH`. + ## Пример проекта `src/main.c` содержит минимальный `Hello, World!`: ```c diff --git a/dcr b/dcr new file mode 100755 index 0000000..31d519d --- /dev/null +++ b/dcr @@ -0,0 +1,3 @@ +#!/bin/sh + +uv run run "$@" \ No newline at end of file diff --git a/src/dcr/cli/__init__.py b/src/dcr/cli/__init__.py index 95a7cb0..f450ff1 100644 --- a/src/dcr/cli/__init__.py +++ b/src/dcr/cli/__init__.py @@ -3,6 +3,8 @@ from .init import init from .new import new from .run import run from .build import build +from .clean import clean + __all__ = [ "help", @@ -10,4 +12,5 @@ __all__ = [ "new", "run", "build", + "clean", ] diff --git a/src/dcr/cli/build.py b/src/dcr/cli/build.py index 5f458f7..fb98260 100644 --- a/src/dcr/cli/build.py +++ b/src/dcr/cli/build.py @@ -1,13 +1,8 @@ +import time import os import subprocess from ..config import flags, profile, c_comp - - -def check_dir(dir: str | None = None) -> list[str]: - if dir in (None, ".", "./"): - return os.listdir(os.getcwd()) - else: - return os.listdir(os.getcwd() + "/" + dir) +from dcr.utils.fs import check_dir def build(args: list[str] | None = None) -> int: @@ -22,7 +17,7 @@ def build(args: list[str] | None = None) -> int: if len(args) >= 1 and args[0].startswith("--"): candidate: str = args[0][2:] if candidate in flags: - active_profile = candidate + active_profile: str = candidate else: print("Ошибка: неверный флаг сборки") return 1 @@ -33,8 +28,9 @@ def build(args: list[str] | None = None) -> int: if active_profile not in check_dir("target"): os.mkdir(f"./target/{active_profile}") if "main.c" in check_dir("src"): - print(f"Run build project as profiles {active_profile}") + print(f"Запуск сборки с профилем {active_profile}") compile_flags = flags[active_profile] + start_time: float = time.time() subprocess.run( [ c_comp, @@ -45,5 +41,8 @@ def build(args: list[str] | None = None) -> int: ], check=True, ) - print("Build complite") + end_time: float = time.time() + times: float = end_time - start_time + times: float = int(times * 100) / 100 + print(f"Сборка завершена, за {times} секунд") return 0 diff --git a/src/dcr/cli/clean.py b/src/dcr/cli/clean.py new file mode 100644 index 0000000..5c29f48 --- /dev/null +++ b/src/dcr/cli/clean.py @@ -0,0 +1,20 @@ +from dcr.utils.fs import check_dir +import os +import shutil + + +def clean(args: list[str]) -> int: + items: list[str] = check_dir() + if len(args) >= 1: + print("Ошибка: команда не поддежривает аргументы") + return 1 + if "dcr.toml" not in items: + print("Ошибка: вы находитесь не в корне проекта") + return 1 + if "target" not in items: + print("Вы уже очистили сборки") + return 0 + + shutil.rmtree("target") + print("Сборки очишены") + return 0 diff --git a/src/dcr/cli/init.py b/src/dcr/cli/init.py index 9bb2605..49e2127 100644 --- a/src/dcr/cli/init.py +++ b/src/dcr/cli/init.py @@ -1,32 +1,37 @@ +from dcr.config import ( + file_dcr_toml, + file_main_c, + project_version, + project_language, + project_compiler, +) import os +from dcr.utils.fs import check_dir - -def init(args) -> int: - items = os.listdir(os.getcwd()) +def init(args: list[str] | None = None) -> int: + if args: + print("Ошибка: команда init не поддерживает аргументы") + return 1 + items = check_dir() project_name = os.path.basename(os.getcwd()) if items: - print("ERROR: directory is not empty") + print("Ошибка: директория не пустая") return 1 os.mkdir("src") with open("./src/main.c", "w") as file: - file.write( - "#include \n\n" - "int main(void) {\n" - ' printf("Hello World!\\n");\n' - " return 0;\n" - "}\n" - ) + file.write(file_main_c) with open("./dcr.toml", "w") as file: file.write( - "[package]\n" - f'name = "{project_name}"\n' - 'version = "0.1.0"\n' - 'edition = "2026"\n\n' - "[dependencies]\n" + file_dcr_toml.format( + project_name=project_name, + project_version=project_version, + project_language=project_language, + project_compiler=project_compiler, + ) ) return 0 diff --git a/src/dcr/cli/new.py b/src/dcr/cli/new.py index a516b18..2bc0ad0 100644 --- a/src/dcr/cli/new.py +++ b/src/dcr/cli/new.py @@ -1,34 +1,40 @@ +from dcr.config import ( + file_dcr_toml, + file_main_c, + project_version, + project_language, + project_compiler, +) import os +from dcr.utils.fs import check_dir def new(args: list[str]) -> int: - items: list[str] = os.listdir(os.getcwd()) - if len(args) == 0 or len(args) > 1: - print("ERROR") + items: list[str] = check_dir() + if len(args) == 0: + print("Ошибка: не указано название проекта") + return 1 + if len(args) > 1: + print("Ошибка: команда не поддежривает аргументы") return 1 project_name: str = args[0] if project_name in items: - print("ERROR") + print(f"Ошибка: директория {project_name} занята") return 1 os.makedirs(f"./{project_name}/src") with open(f"./{project_name}/src/main.c", "w") as file: - file.write( - "#include \n\n" - "int main(void) {\n" - ' printf("Hello World!\\n");\n' - " return 0;\n" - "}\n" - ) + file.write(file_main_c) with open(f"./{project_name}/dcr.toml", "w") as file: file.write( - "[package]\n" - f'name = "{project_name}"\n' - 'version = "0.1.0"\n' - 'edition = "2026"\n\n' - "[dependencies]\n" + file_dcr_toml.format( + project_name=project_name, + project_version=project_version, + project_language=project_language, + project_compiler=project_compiler, + ) ) return 0 diff --git a/src/dcr/cli/run.py b/src/dcr/cli/run.py index 5f882e3..7d822ca 100644 --- a/src/dcr/cli/run.py +++ b/src/dcr/cli/run.py @@ -1,20 +1,14 @@ import os import subprocess +from dcr.utils.fs import check_dir from ..config import flags, profile from .build import build -def check_dir(dir: str | None = None) -> list[str]: - if dir in (None, ".", "./"): - return os.listdir(os.getcwd()) - else: - return os.listdir(os.getcwd() + "/" + dir) - - def run(args: list[str] | None = None) -> int: active_profile: str = profile - if "dcr.toml" not in os.listdir(os.getcwd()): + if "dcr.toml" not in check_dir(): print("Ошибка: не найден файл dcr.toml") return 1 @@ -22,7 +16,7 @@ def run(args: list[str] | None = None) -> int: if len(args) >= 1 and args[0].startswith("--"): candidate: str = args[0][2:] if candidate in flags: - active_profile = candidate + active_profile: str = candidate else: print("Ошибка: неверный флаг сборки") return 1 @@ -31,5 +25,5 @@ def run(args: list[str] | None = None) -> int: return 1 build(args) - print("Run project") + print("Запуск проекта") return subprocess.run([f"./target/{active_profile}/main"]).returncode diff --git a/src/dcr/config.py b/src/dcr/config.py index 6f18188..a44481c 100644 --- a/src/dcr/config.py +++ b/src/dcr/config.py @@ -1,3 +1,39 @@ +file_dcr_toml: str = """[package] +name = "{project_name}" +version = "{project_version}" +language = "{project_language}" +compiler = "{project_compiler}" + +[dependencies] +""" +file_main_c: str = """#include + +int main(void) { + printf("Hello World!\n"); + return 0; +} +""" + +file_dcr_lock: str = """# This file is automatically @generated by dcr. +# It is not intended for manual editing. +version = 1 + +[[package]] +name = "{project_name}" +version = "{project_version}" +""" + +"""[[package]] +name = "{package_name}" +version = "{package_version}" +source = "{{package_source}" +checksum = "{package_checksum}" +dependencies = [{package_dependencies}]""" + +project_version: str = "0.1.0" +project_language: str = "c" +project_compiler: str = "clang" + profile: str = "debug" c_comp: str = "clang" flags: dict[str, list[str]] = { diff --git a/src/dcr/main.py b/src/dcr/main.py index 80184dc..36ef7a9 100644 --- a/src/dcr/main.py +++ b/src/dcr/main.py @@ -19,6 +19,8 @@ def main() -> int: cli.build(args) case "run": cli.run(args) + case "clean": + cli.clean(args) case _: print("Unknown command") diff --git a/src/dcr/utils/fs.py b/src/dcr/utils/fs.py new file mode 100644 index 0000000..72ebfcf --- /dev/null +++ b/src/dcr/utils/fs.py @@ -0,0 +1,8 @@ +import os + + +def check_dir(dir: str | None = None) -> list[str]: + if dir in (None, ".", "./"): + return os.listdir(os.getcwd()) + else: + return os.listdir(os.getcwd() + "/" + dir)