4 Commits

Author SHA1 Message Date
7a0ebb43a5 remove one project deps 2026-02-18 21:08:56 +08:00
4c628ff336 update CHANGELOG.md 2026-02-18 21:05:36 +08:00
95324ce199 chore: translate CLI and installer messages to English 2026-02-18 21:04:28 +08:00
d1e23a3179 Update project docs lang to Eng
Add FAQ.md and docs/
2026-02-18 19:53:39 +08:00
21 changed files with 658 additions and 301 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## [0.2.1] - 2026-02-18
Changed:
- Translated user-facing CLI messages to English
- Unified error and warning output via `utils::log::{error, warn}`
- Updated `--help` output: translated headers and examples to English, used `printc`, and applied `BOLD_*` styles
- Translated installer script messages in `install.sh` and `install.ps1` to English
## [0.2.0] - 2026-02-17 ## [0.2.0] - 2026-02-17
Изменено: Изменено:
- Проект переведен с Python на Rust - Проект переведен с Python на Rust

2
Cargo.lock generated
View File

@@ -62,7 +62,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "dcr" name = "dcr"
version = "0.2.0" version = "0.2.1"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"self-replace", "self-replace",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "dcr" name = "dcr"
version = "0.2.0" version = "0.2.1"
edition = "2024" edition = "2024"
build = "build.rs" build = "build.rs"

102
FAQ.md Normal file
View File

@@ -0,0 +1,102 @@
# FAQ
## What is this project about?
`dcr` is a tool for managing C/C++ projects and their dependencies.
It is inspired by Cargo, but it is not a direct equivalent of Makefile, CMake, or other classic build systems.
The goal is to provide a simpler and easier-to-configure development workflow.
## How is the project developed?
The project is written in Rust and is primarily developed by one maintainer, Dexoron.
AI tools are used during development, but they do not write the project end-to-end. Their role is limited to supporting specific tasks (for example, suggestions, wording checks, and translations).
## Which tools are used for development?
Main development stack:
- `RustRover` 2025 - development IDE.
- `Codex` (`GPT-5.3-Codex (medium)`) - primary AI tool, integrated via JetBrains AI Chat.
- `Rust` - main project language.
- `Cargo` - tool for building, testing, and dependency management in Rust projects.
## Is the project open source?
Yes, the project is open source.
You can propose ideas, report issues, and contribute code changes.
The project is distributed under the MIT license (see `LICENSE`).
## How can I contribute?
Thank you for contributing.
You can:
- help with code;
- help with translations;
- help with documentation;
- suggest an idea or report a bug.
### If you want to submit changes (code, translation, documentation)
1. Fork the required repository: `dexoron/dcr` (main project) or `dexoron/dcr-site` (project website).
2. Make your changes following the rules in `CONTRIBUTING.md`.
3. Push changes to your fork.
4. Open a Pull Request.
5. Wait for review.
### If you want to report a problem or suggest an idea
1. Open the relevant repository: `dexoron/dcr` or `dexoron/dcr-site`.
2. Go to the `Issues` tab.
3. Create an Issue and specify its type (bug, suggestion, question/help).
4. Describe the problem or idea clearly and concisely.
5. Wait for feedback.
## How do I install `dcr`?
Available installation methods may vary by project version.
Recommended path:
- check instructions in `README.md`;
- if there is no prebuilt package for your platform, build from source using `cargo build --release`.
## How can I get started quickly?
Minimal workflow:
1. Install `dcr`.
2. Create a project (or open an existing C/C++ project).
3. Initialize `dcr` configuration.
4. Add project dependencies.
5. Build using `dcr`.
For detailed commands and examples, see `README.md` and the project documentation.
## What is the project status?
`dcr` is under active development.
This means some interfaces and behaviors may change between versions.
Before upgrading, check the changelog and release notes.
## Which systems does `dcr` support?
`dcr` targets modern C/C++ development environments.
Actual compatibility depends on the `dcr` version, operating system, and toolchain.
Before starting, check documentation for:
- supported operating systems;
- supported compilers and linkers;
- version-specific limitations.
## How is `dcr` different from Make/CMake?
`dcr` does not aim to be a direct replacement for Make/CMake.
Its main focus is simplifying project and dependency management with a Cargo-like experience.
If you need low-level, full control over build steps, classic tools may be a better fit.
If you want a simpler and more uniform configuration model, `dcr` may be more convenient.
## Where can I find documentation and examples?
Primary sources:
- `README.md` in the repository;
- project documentation (see the project website);
- `Issues` for known problems and discussions.
## How do I report a bug properly?
To make a bug report easy to reproduce, include:
1. `dcr` version.
2. OS and compiler/toolchain version.
3. Steps to reproduce.
4. Expected behavior.
5. Actual behavior and error output.
6. Minimal project example (if possible).
Submit bugs and issues through `Issues` in the relevant repository.

102
README.md
View File

@@ -1,31 +1,31 @@
# DCR (Dexoron Cargo Realization) # DCR (Dexoron Cargo Realization)
DCR — это утилита для управления проектами на C/C++ в стиле Cargo. DCR is a utility for managing C/C++ projects in a Cargo-like style.
Текущая реализация написана на Rust. The current implementation is written in Rust.
## Зачем DCR ## Why DCR
- Единая структура проекта без ручной настройки - Unified project structure without manual setup
- Простые команды для типовых задач - Simple commands for common tasks
- Прозрачная компиляция и предсказуемые профили сборки - Transparent compilation and predictable build profiles
## Возможности ## Features
- Создание нового проекта или инициализация текущей директории - Create a new project or initialize the current directory
- Сборка проекта в профилях `debug` и `release` - Build a project with `debug` and `release` profiles
- Запуск собранного бинарника - Run the compiled binary
- Очистка результатов сборки - Clean build artifacts
- Генерация минимального шаблона C-проекта - Generate a minimal C project template
- Обновление бинарника через `dcr --update` (GitHub Releases) - Update the binary via `dcr --update` (GitHub Releases)
## Поддерживаемые платформы ## Supported Platforms
- Linux: `x86_64-unknown-linux-gnu` - Linux: `x86_64-unknown-linux-gnu`
- macOS Intel: `x86_64-apple-darwin` - macOS Intel: `x86_64-apple-darwin`
- macOS Apple Silicon: `aarch64-apple-darwin` - macOS Apple Silicon: `aarch64-apple-darwin`
- Windows: `x86_64-pc-windows-msvc` - Windows: `x86_64-pc-windows-msvc`
## Установка ## Installation
### Из исходников ### From Source
```sh ```sh
git clone https://github.com/dexoron/dcr.git git clone https://github.com/dexoron/dcr.git
@@ -35,37 +35,37 @@ mkdir -p ~/.local/bin
ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr
``` ```
### Через install.sh (Linux/macOS) ### Via `install.sh` (Linux/macOS)
```sh ```sh
curl -fsSL https://raw.githubusercontent.com/dexoron/dcr/master/install.sh | bash curl -fsSL https://dcr.dexoron.su/install.sh | bash
``` ```
### Через install.ps1 (Windows) ### Via `install.ps1` (Windows)
```powershell ```powershell
irm https://raw.githubusercontent.com/dexoron/dcr/master/install.ps1 | iex irm https://dcr.dexoron.su/install.ps1 | iex
``` ```
Оба скрипта при запуске спрашивают: When executed, both scripts ask whether to:
- скачать готовый бинарник из GitHub Release - download a prebuilt binary from GitHub Releases
- или собрать проект из `git` - or build the project from `git`
Релизные ассеты: Release assets:
- `dcr-x86_64-unknown-linux-gnu` - `dcr-x86_64-unknown-linux-gnu`
- `dcr-x86_64-apple-darwin` - `dcr-x86_64-apple-darwin`
- `dcr-aarch64-apple-darwin` - `dcr-aarch64-apple-darwin`
- `dcr-x86_64-pc-windows-msvc.exe` - `dcr-x86_64-pc-windows-msvc.exe`
## Быстрый старт ## Quick Start
Создать новый проект: Create a new project:
`dcr new hello` `dcr new hello`
Или инициализировать текущую директорию (директория должна быть пустой): Or initialize the current directory (the directory must be empty):
`dcr init` `dcr init`
Структура проекта: Project structure:
```txt ```txt
hello/ hello/
@@ -74,38 +74,38 @@ hello/
- dcr.toml - dcr.toml
``` ```
Сборка и запуск проекта: Build and run the project:
`dcr run` или `dcr run --release` `dcr run` or `dcr run --release`
## Команды ## Commands
### `dcr new <name>` ### `dcr new <name>`
Создает проект в текущей директории с указанным именем. Creates a project with the specified name in the current directory.
### `dcr init` ### `dcr init`
Создает проект в текущей директории. Имя проекта будет равно имени директории. Директория должна быть пустой. Creates a project in the current directory. The project name is taken from the directory name. The directory must be empty.
### `dcr build [profile]` ### `dcr build [profile]`
Собирает проект. Если профиль не указан, используется `--debug`. Builds the project. If no profile is specified, `--debug` is used.
### `dcr run [profile]` ### `dcr run [profile]`
Собирает проект и запускает бинарник. Если профиль не указан, используется `--debug`. Builds the project and runs the binary. If no profile is specified, `--debug` is used.
Запуск вручную: Run manually:
`./target/<profile>/main` `./target/<profile>/main`
### `dcr clean` ### `dcr clean`
Удаляет папку `target` в корне проекта. Removes the `target` directory in the project root.
## Профили сборки ## Build Profiles
Поддерживаются два профиля: Two profiles are supported:
- `--debug` (по умолчанию) — флаги: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG` - `--debug` (default) - flags: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`
- `--release` — флаги: `-O3 -DNDEBUG -march=native` - `--release` - flags: `-O3 -DNDEBUG -march=native`
## Конфигурация ## Configuration
Основной файл проекта — `dcr.toml`. The main project file is `dcr.toml`.
Пример `dcr.toml`: Example `dcr.toml`:
```toml ```toml
[package] [package]
@@ -117,12 +117,12 @@ compiler = "clang"
[dependencies] [dependencies]
``` ```
## Требования ## Requirements
- Rust toolchain (`rustc`, `cargo`) - Для ручной сборки DCR - Rust toolchain (`rustc`, `cargo`) - for building DCR from source
- C-компилятор (`clang`, `gcc` или другие) - C compiler (`clang`, `gcc`, or others)
## Релизы ## Releases
Релизы собираются автоматически через GitHub Actions (`.github/workflows/release.yml`) при пуше тега формата `v*`. Releases are built automatically via GitHub Actions (`.github/workflows/release.yml`) when a tag matching `v*` is pushed.
## Лицензия ## License
См. файл `LICENSE`. See `LICENSE`.

57
docs/CONTRIBUTING_ru.md Normal file
View File

@@ -0,0 +1,57 @@
# Вклад в проект
Спасибо за интерес к проекту.
## Требования
- Использовать Rust stable.
- Перед PR код должен проходить форматирование, линт и сборку.
## Быстрый старт
```bash
git clone https://github.com/dexoron/dcr.git
cd dcr
cargo check
```
## Стиль кода
- Форматируйте код через `cargo fmt`.
- Проверяйте предупреждения через `cargo clippy`.
- Держите функции небольшими и сфокусированными.
- Предпочитайте понятные имена вместо "хитрых".
## Проверки
Перед PR запускайте:
```bash
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo check
```
## CI/CD и релизы
- CI: `.github/workflows/ci.yml`
- Release: `.github/workflows/release.yml`
- Релиз запускается по тегу `v*` и публикует бинарники для:
- `x86_64-unknown-linux-gnu`
- `x86_64-apple-darwin`
- `aarch64-apple-darwin`
- `x86_64-pc-windows-msvc`
## Коммиты и PR
- Делайте коммиты понятными.
- В PR указывайте краткое описание и мотивацию изменений.
- Обновляйте документацию при изменении поведения.
## Вопросы
Если что-то непонятно, открой issue или задайте вопрос в PR.
Также можно задать вопрос напрямую:
- TG: @dexoron
- DS: dexoron

102
docs/FAQ_ru.md Normal file
View File

@@ -0,0 +1,102 @@
# FAQ
## В чем суть проекта?
`dcr` - это инструмент для управления C/C++ проектами и их зависимостями.
Он вдохновлен Cargo, но не является аналогом Makefile, CMake или других классических систем сборки.
Цель проекта - дать более простую и удобную в настройке среду для разработки.
## Как разрабатывается проект?
Проект написан на Rust и в основном развивается одним разработчиком - Dexoron.
В работе используются ИИ-инструменты, но они не пишут проект целиком: их роль - помощь с отдельными задачами (например, советы, проверка формулировок, переводы и т.д.).
## Какие инструменты используются для разработки?
Основной стек разработки:
- `RustRover` 2025 - IDE для разработки.
- `Codex` (`GPT-5.3-Codex (medium)`) - основной ИИ-инструмент, интегрированный через JetBrains AI Chat.
- `Rust` - основной язык проекта.
- `Cargo` - инструмент сборки, тестов и управления зависимостями Rust-проектов.
## Проект открытый?
Да, проект открыт (Open Source).
Вы можете предлагать идеи, находить ошибки и вносить изменения в код.
Проект распространяется по лицензии MIT (см. `LICENSE`).
## Как внести вклад?
Спасибо за желание помочь проекту.
Вы можете:
- помочь с кодом;
- помочь с переводом;
- помочь с документацией;
- предложить идею или сообщить о баге.
### Если вы хотите внести изменения (код, перевод, документация)
1. Сделайте форк нужного репозитория: `dexoron/dcr` (основной проект) или `dexoron/dcr-site` (сайт проекта).
2. Внесите изменения с учетом правил из `CONTRIBUTING.md`.
3. Отправьте изменения в свой форк.
4. Создайте Pull Request.
5. Дождитесь ревью.
### Если вы хотите сообщить о проблеме или предложить идею
1. Откройте нужный репозиторий: `dexoron/dcr` или `dexoron/dcr-site`.
2. Перейдите во вкладку `Issues`.
3. Создайте Issue и укажите тип (баг, предложение, вопрос/помощь).
4. Опишите проблему или идею кратко и понятно.
5. Дождитесь обратной связи.
## Как установить `dcr`?
Актуальные способы установки зависят от текущей версии проекта.
Рекомендуемый путь:
- проверьте инструкции в `README.md`;
- если готового пакета для вашей платформы нет, соберите проект из исходников через `cargo build --release`.
## Как быстро начать работу?
Минимальный сценарий:
1. Установите `dcr`.
2. Создайте проект (или перейдите в существующий C/C++ проект).
3. Инициализируйте конфигурацию `dcr`.
4. Добавьте зависимости проекта.
5. Запустите сборку через `dcr`.
Подробные команды и примеры смотрите в `README.md` и документации проекта.
## На какой стадии проект?
`dcr` активно развивается.
Это означает, что интерфейсы и поведение некоторых функций могут меняться между версиями.
Перед обновлением рекомендуется читать changelog и проверять заметки к релизу.
## С какими системами работает `dcr`?
`dcr` ориентирован на современные среды разработки C/C++.
Фактическая совместимость зависит от версии `dcr`, операционной системы и используемого toolchain.
Перед началом работы проверьте в документации:
- поддерживаемые ОС;
- поддерживаемые компиляторы и линкеры;
- ограничения конкретной версии.
## Чем `dcr` отличается от Make/CMake?
`dcr` не пытается быть прямой заменой Make/CMake.
Главный фокус `dcr` - упростить управление проектом и зависимостями в стиле, близком к опыту Cargo.
Если вам нужен низкоуровневый полный контроль над процессом сборки, классические инструменты могут быть привычнее.
Если нужна более простая и единообразная модель конфигурации - `dcr` может быть удобнее.
## Где смотреть документацию и примеры?
Основные источники:
- `README.md` в репозитории;
- документация проекта (смотреть сайт проекта);
- `Issues` для известных проблем и обсуждений;
## Как правильно сообщить о баге?
Чтобы баг-репорт можно было быстро воспроизвести, укажите:
1. Версию `dcr`.
2. ОС и версию компилятора/toolchain.
3. Шаги воспроизведения.
4. Ожидаемое поведение.
5. Фактическое поведение и текст ошибки.
6. Минимальный пример проекта (по возможности).
Баги и проблемы отправляйте через `Issues` в соответствующем репозитории.

128
docs/README_ru.md Normal file
View File

@@ -0,0 +1,128 @@
# DCR (Dexoron Cargo Realization)
DCR — это утилита для управления проектами на C/C++ в стиле Cargo.
Текущая реализация написана на Rust.
## Зачем DCR
- Единая структура проекта без ручной настройки
- Простые команды для типовых задач
- Прозрачная компиляция и предсказуемые профили сборки
## Возможности
- Создание нового проекта или инициализация текущей директории
- Сборка проекта в профилях `debug` и `release`
- Запуск собранного бинарника
- Очистка результатов сборки
- Генерация минимального шаблона C-проекта
- Обновление бинарника через `dcr --update` (GitHub Releases)
## Поддерживаемые платформы
- Linux: `x86_64-unknown-linux-gnu`
- macOS Intel: `x86_64-apple-darwin`
- macOS Apple Silicon: `aarch64-apple-darwin`
- Windows: `x86_64-pc-windows-msvc`
## Установка
### Из исходников
```sh
git clone https://github.com/dexoron/dcr.git
cd dcr
cargo build --release
mkdir -p ~/.local/bin
ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr
```
### Через install.sh (Linux/macOS)
```sh
curl -fsSL https://dcr.dexoron.su/install.sh | bash
```
### Через install.ps1 (Windows)
```powershell
irm https://dcr.dexoron.su/install.ps1 | iex
```
Оба скрипта при запуске спрашивают:
- скачать готовый бинарник из GitHub Release
- или собрать проект из `git`
Релизные ассеты:
- `dcr-x86_64-unknown-linux-gnu`
- `dcr-x86_64-apple-darwin`
- `dcr-aarch64-apple-darwin`
- `dcr-x86_64-pc-windows-msvc.exe`
## Быстрый старт
Создать новый проект:
`dcr new hello`
Или инициализировать текущую директорию (директория должна быть пустой):
`dcr init`
Структура проекта:
```txt
hello/
- src/
- - main.c
- dcr.toml
```
Сборка и запуск проекта:
`dcr run` или `dcr run --release`
## Команды
### `dcr new <name>`
Создает проект в текущей директории с указанным именем.
### `dcr init`
Создает проект в текущей директории. Имя проекта будет равно имени директории. Директория должна быть пустой.
### `dcr build [profile]`
Собирает проект. Если профиль не указан, используется `--debug`.
### `dcr run [profile]`
Собирает проект и запускает бинарник. Если профиль не указан, используется `--debug`.
Запуск вручную:
`./target/<profile>/main`
### `dcr clean`
Удаляет папку `target` в корне проекта.
## Профили сборки
Поддерживаются два профиля:
- `--debug` (по умолчанию) — флаги: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`
- `--release` — флаги: `-O3 -DNDEBUG -march=native`
## Конфигурация
Основной файл проекта — `dcr.toml`.
Пример `dcr.toml`:
```toml
[package]
name = "hello"
version = "0.1.0"
language = "c"
compiler = "clang"
[dependencies]
```
## Требования
- Rust toolchain (`rustc`, `cargo`) - Для ручной сборки DCR
- C-компилятор (`clang`, `gcc` или другие)
## Релизы
Релизы собираются автоматически через GitHub Actions (`.github/workflows/release.yml`) при пуше тега формата `v*`.
## Лицензия
См. файл `LICENSE`.

View File

@@ -13,27 +13,27 @@ function Fail($msg) { Write-Host "[ERROR] $msg" -ForegroundColor Red; exit 1 }
function Require-Cmd($name) { function Require-Cmd($name) {
if (-not (Get-Command $name -ErrorAction SilentlyContinue)) { if (-not (Get-Command $name -ErrorAction SilentlyContinue)) {
Fail "Не найдено: $name" Fail "Not found: $name"
} }
} }
function Select-Mode { function Select-Mode {
Write-Host "Выбери способ установки:" Write-Host "Choose installation mode:"
Write-Host " 1) Скачать готовый бинарник из GitHub Release (рекомендуется)" Write-Host " 1) Download prebuilt binary from GitHub Release (recommended)"
Write-Host " 2) Собрать из git" Write-Host " 2) Build from git"
$choice = Read-Host "Введите 1 или 2 [1]" $choice = Read-Host "Enter 1 or 2 [1]"
if ([string]::IsNullOrWhiteSpace($choice)) { $choice = '1' } if ([string]::IsNullOrWhiteSpace($choice)) { $choice = '1' }
switch ($choice) { switch ($choice) {
'1' { return 'release' } '1' { return 'release' }
'2' { return 'build' } '2' { return 'build' }
default { Fail 'Неизвестный вариант' } default { Fail 'Unknown option' }
} }
} }
function Get-Target { function Get-Target {
if ($env:PROCESSOR_ARCHITECTURE -ne 'AMD64') { if ($env:PROCESSOR_ARCHITECTURE -ne 'AMD64') {
Fail "Поддерживается только x86_64 Windows, текущая архитектура: $env:PROCESSOR_ARCHITECTURE" Fail "Only x86_64 Windows is supported, current architecture: $env:PROCESSOR_ARCHITECTURE"
} }
return 'x86_64-pc-windows-msvc' return 'x86_64-pc-windows-msvc'
} }
@@ -44,17 +44,17 @@ function Install-FromRelease {
New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
$assetName = "dcr-$target.exe" $assetName = "dcr-$target.exe"
Info "Получение последнего релиза..." Info "Fetching latest release..."
$release = Invoke-RestMethod -Method Get -Uri $ApiUrl $release = Invoke-RestMethod -Method Get -Uri $ApiUrl
$asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1 $asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
if (-not $asset) { if (-not $asset) {
Fail "Не найден ассет $assetName в релизе $($release.tag_name)" Fail "Asset $assetName not found in release $($release.tag_name)"
} }
Info "Скачивание $assetName..." Info "Downloading $assetName..."
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $BinaryPath Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $BinaryPath
Ok "Скачан бинарник $assetName" Ok "Binary downloaded: $assetName"
} }
function Install-FromSource { function Install-FromSource {
@@ -66,17 +66,17 @@ function Install-FromSource {
$tmp = Join-Path $env:TEMP 'dcr-install' $tmp = Join-Path $env:TEMP 'dcr-install'
if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp } if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp }
Info 'Клонирование репозитория...' Info 'Cloning repository...'
git clone --depth 1 $RepoUrl $tmp | Out-Null git clone --depth 1 $RepoUrl $tmp | Out-Null
Info 'Сборка release-бинарника...' Info 'Building release binary...'
Push-Location $tmp Push-Location $tmp
cargo build --release --target $target cargo build --release --target $target
Pop-Location Pop-Location
New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
Copy-Item (Join-Path $tmp "target\$target\release\dcr.exe") $BinaryPath -Force Copy-Item (Join-Path $tmp "target\$target\release\dcr.exe") $BinaryPath -Force
Ok 'Установлен бинарник из исходников' Ok 'Binary installed from source'
Remove-Item -Recurse -Force $tmp Remove-Item -Recurse -Force $tmp
} }
@@ -93,13 +93,13 @@ function Setup-Path {
$newPath = if ($userPath) { "$userPath;$BinPath" } else { $BinPath } $newPath = if ($userPath) { "$userPath;$BinPath" } else { $BinPath }
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User') [Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
$env:Path = "$env:Path;$BinPath" $env:Path = "$env:Path;$BinPath"
Warn "Добавлен путь в PATH: $BinPath" Warn "Added path to PATH: $BinPath"
} }
Ok "Команда dcr доступна через $linkPath" Ok "dcr command is available via $linkPath"
} }
Info 'Запуск установки DCR' Info 'Starting DCR installation'
$mode = Select-Mode $mode = Select-Mode
$target = Get-Target $target = Get-Target
@@ -110,4 +110,4 @@ if ($mode -eq 'build') {
} }
Setup-Path Setup-Path
Ok 'Установка завершена успешно' Ok 'Installation completed successfully'

View File

@@ -22,12 +22,12 @@ success() { echo -e "${GREEN}✔ $1${NC}"; }
warn() { echo -e "${YELLOW}⚠ $1${NC}"; } warn() { echo -e "${YELLOW}⚠ $1${NC}"; }
error() { echo -e "${RED}✖ $1${NC}"; } error() { echo -e "${RED}✖ $1${NC}"; }
trap 'error "Ошибка на строке $LINENO"; exit 1' ERR trap 'error "Error on line $LINENO"; exit 1' ERR
check_os() { check_os() {
case "$(uname -s)" in case "$(uname -s)" in
Linux|Darwin) ;; Linux|Darwin) ;;
*) error "Поддерживаются только Linux и macOS"; exit 1 ;; *) error "Only Linux and macOS are supported"; exit 1 ;;
esac esac
} }
@@ -40,32 +40,32 @@ detect_target() {
Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;; Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;;
Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;; Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;;
Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;; Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;;
*) error "Неподдерживаемая платформа: $os/$arch"; exit 1 ;; *) error "Unsupported platform: $os/$arch"; exit 1 ;;
esac esac
ASSET_NAME="dcr-${TARGET_TRIPLE}" ASSET_NAME="dcr-${TARGET_TRIPLE}"
} }
check_common_dependencies() { check_common_dependencies() {
command -v curl >/dev/null 2>&1 || { error "curl не установлен"; exit 1; } command -v curl >/dev/null 2>&1 || { error "curl is not installed"; exit 1; }
} }
check_build_dependencies() { check_build_dependencies() {
command -v git >/dev/null 2>&1 || { error "git не установлен"; exit 1; } command -v git >/dev/null 2>&1 || { error "git is not installed"; exit 1; }
command -v cargo >/dev/null 2>&1 || { error "cargo не установлен"; exit 1; } command -v cargo >/dev/null 2>&1 || { error "cargo is not installed"; exit 1; }
} }
prepare_sources() { prepare_sources() {
log "Получение исходников..." log "Fetching sources..."
rm -rf "$TMPDIR" rm -rf "$TMPDIR"
git clone --depth 1 "$REPO_URL" "$TMPDIR" git clone --depth 1 "$REPO_URL" "$TMPDIR"
success "Исходники получены" success "Sources fetched"
} }
build_binary() { build_binary() {
log "Сборка release-бинарника..." log "Building release binary..."
(cd "$TMPDIR" && cargo build --release) (cd "$TMPDIR" && cargo build --release)
success "Сборка завершена" success "Build completed"
} }
fetch_latest_release_json() { fetch_latest_release_json() {
@@ -73,47 +73,47 @@ fetch_latest_release_json() {
} }
download_binary() { download_binary() {
log "Получение последнего релиза..." log "Fetching latest release..."
local release_json download_url tag local release_json download_url tag
release_json="$(fetch_latest_release_json)" release_json="$(fetch_latest_release_json)"
tag="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1)" tag="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1)"
if [[ -z "$tag" ]]; then if [[ -z "$tag" ]]; then
error "Не удалось определить версию релиза" error "Failed to determine release version"
exit 1 exit 1
fi fi
download_url="$(printf '%s\n' "$release_json" | sed -n "s#.*\"browser_download_url\": \"\([^\"]*${ASSET_NAME}\)\".*#\1#p" | head -n1)" download_url="$(printf '%s\n' "$release_json" | sed -n "s#.*\"browser_download_url\": \"\([^\"]*${ASSET_NAME}\)\".*#\1#p" | head -n1)"
if [[ -z "$download_url" ]]; then if [[ -z "$download_url" ]]; then
error "Не найден ассет ${ASSET_NAME} в релизе ${tag}" error "Asset ${ASSET_NAME} not found in release ${tag}"
exit 1 exit 1
fi fi
mkdir -p "$INSTALL_PATH" mkdir -p "$INSTALL_PATH"
curl -fL "$download_url" -o "$INSTALL_PATH/dcr" curl -fL "$download_url" -o "$INSTALL_PATH/dcr"
chmod +x "$INSTALL_PATH/dcr" chmod +x "$INSTALL_PATH/dcr"
success "Скачан бинарник ${ASSET_NAME} (${tag})" success "Binary ${ASSET_NAME} downloaded (${tag})"
} }
install_built_binary() { install_built_binary() {
mkdir -p "$INSTALL_PATH" mkdir -p "$INSTALL_PATH"
cp "$TMPDIR/target/release/dcr" "$INSTALL_PATH/dcr" cp "$TMPDIR/target/release/dcr" "$INSTALL_PATH/dcr"
chmod +x "$INSTALL_PATH/dcr" chmod +x "$INSTALL_PATH/dcr"
success "Установлен бинарник из исходников" success "Binary installed from source"
} }
install_link() { install_link() {
log "Создание симлинка..." log "Creating symlink..."
mkdir -p "$BINPATH" mkdir -p "$BINPATH"
ln -sf "$INSTALL_PATH/dcr" "$BINPATH/dcr" ln -sf "$INSTALL_PATH/dcr" "$BINPATH/dcr"
success "Команда 'dcr' добавлена в $BINPATH" success "Command 'dcr' added to $BINPATH"
} }
check_path() { check_path() {
if ! echo "$PATH" | grep -q "$BINPATH"; then if ! echo "$PATH" | grep -q "$BINPATH"; then
warn "Каталог $BINPATH не найден в PATH" warn "Directory $BINPATH not found in PATH"
echo "Добавь в ~/.bashrc или ~/.zshrc:" echo "Add this to ~/.bashrc or ~/.zshrc:"
echo "export PATH=\"$BINPATH:\$PATH\"" echo "export PATH=\"$BINPATH:\$PATH\""
fi fi
} }
@@ -123,20 +123,20 @@ cleanup() {
} }
select_install_mode() { select_install_mode() {
echo "Выбери способ установки:" echo "Choose installation mode:"
echo " 1) Скачать готовый бинарник из GitHub Release (рекомендуется)" echo " 1) Download prebuilt binary from GitHub Release (recommended)"
echo " 2) Собрать из git" echo " 2) Build from git"
read -r -p "Введите 1 или 2 [1]: " choice read -r -p "Enter 1 or 2 [1]: " choice
case "${choice:-1}" in case "${choice:-1}" in
1) INSTALL_MODE="release" ;; 1) INSTALL_MODE="release" ;;
2) INSTALL_MODE="build" ;; 2) INSTALL_MODE="build" ;;
*) error "Неизвестный вариант"; exit 1 ;; *) error "Unknown option"; exit 1 ;;
esac esac
} }
main() { main() {
log "Запуск установки DCR" log "Starting DCR installation"
check_os check_os
detect_target detect_target
@@ -157,8 +157,8 @@ main() {
check_path check_path
cleanup cleanup
success "Установка завершена успешно" success "Installation completed successfully"
log "Лог сохранён в $LOGFILE" log "Log saved to $LOGFILE"
} }
main "$@" main "$@"

View File

@@ -1,14 +1,13 @@
use crate::config::{PROFILE, PROJECT_COMPILER, flags}; use crate::config::{PROFILE, PROJECT_COMPILER, flags};
use crate::utils::fs::check_dir; use crate::utils::fs::check_dir;
use crate::utils::text::{BOLD, BRIGHT_GREEN, BRIGHT_RED, colored}; use crate::utils::log::{error, warn};
use crate::utils::text::{BOLD_GREEN, colored};
use std::fs; use std::fs;
use std::process::Command; use std::process::Command;
use std::time::Instant; use std::time::Instant;
pub fn build(args: &[String]) -> i32 { pub fn build(args: &[String]) -> i32 {
let mut active_profile = PROFILE.to_string(); let mut active_profile = PROFILE.to_string();
let red_bold = BRIGHT_RED.to_owned() + BOLD;
let green_bold = BRIGHT_GREEN.to_owned() + BOLD;
let project_name = std::env::current_dir() let project_name = std::env::current_dir()
.ok() .ok()
.and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string())) .and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string()))
@@ -16,7 +15,7 @@ pub fn build(args: &[String]) -> i32 {
let items = check_dir(None).unwrap_or_default(); let items = check_dir(None).unwrap_or_default();
if !items.contains(&"dcr.toml".to_string()) { if !items.contains(&"dcr.toml".to_string()) {
println!("{}: не найден файл dcr.toml", colored("error", &red_bold)); error("dcr.toml file not found");
return 1; return 1;
} }
@@ -26,20 +25,20 @@ pub fn build(args: &[String]) -> i32 {
if flags(candidate).is_some() { if flags(candidate).is_some() {
active_profile = candidate.to_string(); active_profile = candidate.to_string();
} else { } else {
println!("{}: неизвестный флаг сборки", colored("error", &red_bold)); warn("Unknown build flag");
return 1; return 1;
} }
} else { } else {
println!("{}: неизвестный аргумент", colored("error", &red_bold)); warn("Unknown argument");
return 1; return 1;
} }
} }
println!( println!(
" Сборка проекта `{}`\n Профиль: {}\n Компилятор: {}\n", " Building project `{}`\n Profile: {}\n Compiler: {}\n",
colored(&project_name, &green_bold), colored(&project_name, BOLD_GREEN),
colored(&active_profile, &green_bold), colored(&active_profile, BOLD_GREEN),
colored(PROJECT_COMPILER, &green_bold) colored(PROJECT_COMPILER, BOLD_GREEN)
); );
if !items.contains(&"target".to_string()) { if !items.contains(&"target".to_string()) {
@@ -65,14 +64,14 @@ pub fn build(args: &[String]) -> i32 {
Ok(status) if status.success() => { Ok(status) if status.success() => {
let times = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; let times = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
println!( println!(
" {} Сборка завершена успешно, за {} секунд", " {} Build completed successfully in {} seconds",
colored("✔", &green_bold), colored("✔", BOLD_GREEN),
colored(&times.to_string(), &green_bold) colored(&times.to_string(), BOLD_GREEN)
); );
return 0; return 0;
} }
_ => { _ => {
println!("{}: сборка не удалась", colored("error", &red_bold)); error("Build failed");
return 1; return 1;
} }
} }

View File

@@ -1,13 +1,10 @@
use crate::config::flags; use crate::config::flags;
use crate::utils::fs::check_dir; use crate::utils::fs::check_dir;
use crate::utils::text::{BOLD, BRIGHT_GREEN, BRIGHT_RED, BRIGHT_YELLOW, colored}; use crate::utils::log::{error, warn};
use crate::utils::text::{BOLD_GREEN, colored};
use std::fs; use std::fs;
pub fn clean(args: &[String]) -> i32 { pub fn clean(args: &[String]) -> i32 {
let red_bold = BRIGHT_RED.to_owned() + BOLD;
let green_bold = BRIGHT_GREEN.to_owned() + BOLD;
let yellow_bold = BRIGHT_YELLOW.to_owned() + BOLD;
let project_name = std::env::current_dir() let project_name = std::env::current_dir()
.ok() .ok()
.and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string())) .and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string()))
@@ -15,23 +12,20 @@ pub fn clean(args: &[String]) -> i32 {
let items = check_dir(None).unwrap_or_default(); let items = check_dir(None).unwrap_or_default();
if args.len() > 1 { if args.len() > 1 {
println!("{}: неизвестный аргумент", colored("error", &red_bold)); error("Unknown argument");
return 1; return 1;
} }
if !items.contains(&"dcr.toml".to_string()) { if !items.contains(&"dcr.toml".to_string()) {
println!("{}: не найден файл dcr.toml", colored("error", &red_bold)); error("dcr.toml file not found");
return 1; return 1;
} }
println!( println!(
" Очистка проекта `{}`", " Cleaning project `{}`",
colored(&project_name, &green_bold) colored(&project_name, BOLD_GREEN)
); );
if !items.contains(&"target".to_string()) { if !items.contains(&"target".to_string()) {
println!( warn("Directory target not found");
"{}: директория target не найдена",
colored("warn", &yellow_bold)
);
return 1; return 1;
} }
@@ -41,32 +35,29 @@ pub fn clean(args: &[String]) -> i32 {
profile = profile.trim_start_matches("--").to_string(); profile = profile.trim_start_matches("--").to_string();
} }
if flags(&profile).is_none() { if flags(&profile).is_none() {
println!("{}: неизвестный профиль", colored("error", &red_bold)); error("Unknown profile");
return 1; return 1;
} }
let target_items = check_dir(Some("target")).unwrap_or_default(); let target_items = check_dir(Some("target")).unwrap_or_default();
if !target_items.contains(&profile) { if !target_items.contains(&profile) {
println!( warn(&format!("Directory target/{profile} not found"));
"{}: директория target/{profile} не найдена",
colored("warn", &yellow_bold)
);
return 1; return 1;
} }
println!(" Профиль: {}", colored(&profile, &green_bold)); println!(" Profile: {}", colored(&profile, BOLD_GREEN));
let _ = fs::remove_dir_all(format!("target/{profile}")); let _ = fs::remove_dir_all(format!("target/{profile}"));
println!( println!(
"{} Удалена директория target/{profile}", "{} Removed directory target/{profile}",
colored("\n ✔", &green_bold) colored("\n ✔", BOLD_GREEN)
); );
return 0; return 0;
} }
let _ = fs::remove_dir_all("target"); let _ = fs::remove_dir_all("target");
println!( println!(
"{} Удалена директория target", "{} Removed directory target",
colored("\n ✔", &green_bold) colored("\n ✔", BOLD_GREEN)
); );
0 0
} }

View File

@@ -1,3 +1,4 @@
use crate::utils::log::{error, warn};
use reqwest::blocking::Client; use reqwest::blocking::Client;
use serde::Deserialize; use serde::Deserialize;
use std::fs; use std::fs;
@@ -20,7 +21,7 @@ struct ReleaseAsset {
pub fn flag_update(args: &[String]) -> i32 { pub fn flag_update(args: &[String]) -> i32 {
if !args.is_empty() { if !args.is_empty() {
println!("Ошибка: команда не поддежривает аргументы"); warn("Command does not support additional arguments");
return 1; return 1;
} }
@@ -29,7 +30,7 @@ pub fn flag_update(args: &[String]) -> i32 {
let client = match Client::builder().user_agent("dcr-updater").build() { let client = match Client::builder().user_agent("dcr-updater").build() {
Ok(client) => client, Ok(client) => client,
Err(_) => { Err(_) => {
println!("Ошибка: не удалось инициализировать HTTP клиент"); error("Failed to initialize HTTP client");
return 1; return 1;
} }
}; };
@@ -37,14 +38,14 @@ pub fn flag_update(args: &[String]) -> i32 {
let release = match fetch_latest_release(&client) { let release = match fetch_latest_release(&client) {
Ok(release) => release, Ok(release) => release,
Err(err) => { Err(err) => {
println!("Ошибка: не удалось проверить обновления: {err}"); error(&format!("Failed to check for updates: {err}"));
return 1; return 1;
} }
}; };
let latest_version = release.tag_name.trim_start_matches('v'); let latest_version = release.tag_name.trim_start_matches('v');
if latest_version == current_version { if latest_version == current_version {
println!("Установлена последняя версия: {current_version}"); println!("Latest version is already installed: {current_version}");
return 0; return 0;
} }
@@ -54,14 +55,14 @@ pub fn flag_update(args: &[String]) -> i32 {
.iter() .iter()
.find(|asset| candidate_names.iter().any(|name| name == &asset.name)) .find(|asset| candidate_names.iter().any(|name| name == &asset.name))
else { else {
println!("Ошибка: не найден бинарник для таргета {target}"); error(&format!("Binary for target {target} not found"));
return 1; return 1;
}; };
let bytes = match download_asset(&client, &asset.browser_download_url) { let bytes = match download_asset(&client, &asset.browser_download_url) {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(err) => { Err(err) => {
println!("Ошибка: не удалось скачать обновление: {err}"); error(&format!("Failed to download update: {err}"));
return 1; return 1;
} }
}; };
@@ -69,26 +70,26 @@ pub fn flag_update(args: &[String]) -> i32 {
let current_exe = match std::env::current_exe() { let current_exe = match std::env::current_exe() {
Ok(path) => path, Ok(path) => path,
Err(_) => { Err(_) => {
println!("Ошибка: не удалось определить путь текущего бинарника"); error("Failed to resolve current binary path");
return 1; return 1;
} }
}; };
let temp_path = temp_binary_path(&current_exe); let temp_path = temp_binary_path(&current_exe);
if fs::write(&temp_path, &bytes).is_err() { if fs::write(&temp_path, &bytes).is_err() {
println!("Ошибка: не удалось записать временный бинарник"); error("Failed to write temporary binary");
return 1; return 1;
} }
set_executable_permissions(&temp_path); set_executable_permissions(&temp_path);
if self_replace::self_replace(&temp_path).is_err() { if self_replace::self_replace(&temp_path).is_err() {
let _ = fs::remove_file(&temp_path); let _ = fs::remove_file(&temp_path);
println!("Ошибка: не удалось заменить текущий бинарник"); error("Failed to replace current binary");
return 1; return 1;
} }
let _ = fs::remove_file(&temp_path); let _ = fs::remove_file(&temp_path);
println!("Обновление завершено: {current_version} -> {latest_version}"); println!("Update completed: {current_version} -> {latest_version}");
0 0
} }
@@ -96,31 +97,31 @@ fn fetch_latest_release(client: &Client) -> Result<Release, String> {
let response = client let response = client
.get(LATEST_RELEASE_URL) .get(LATEST_RELEASE_URL)
.send() .send()
.map_err(|_| "запрос к GitHub API завершился ошибкой".to_string())?; .map_err(|_| "GitHub API request failed".to_string())?;
if !response.status().is_success() { if !response.status().is_success() {
return Err(format!("GitHub API вернул статус {}", response.status())); return Err(format!("GitHub API returned status {}", response.status()));
} }
response response
.json::<Release>() .json::<Release>()
.map_err(|_| "ответ GitHub API имеет неожиданный формат".to_string()) .map_err(|_| "GitHub API response has an unexpected format".to_string())
} }
fn download_asset(client: &Client, url: &str) -> Result<Vec<u8>, String> { fn download_asset(client: &Client, url: &str) -> Result<Vec<u8>, String> {
let response = client let response = client
.get(url) .get(url)
.send() .send()
.map_err(|_| "запрос на скачивание завершился ошибкой".to_string())?; .map_err(|_| "Download request failed".to_string())?;
if !response.status().is_success() { if !response.status().is_success() {
return Err(format!("скачивание вернуло статус {}", response.status())); return Err(format!("Download returned status {}", response.status()));
} }
response response
.bytes() .bytes()
.map(|bytes| bytes.to_vec()) .map(|bytes| bytes.to_vec())
.map_err(|_| "не удалось прочитать скачанные данные".to_string()) .map_err(|_| "Failed to read downloaded data".to_string())
} }
fn asset_candidates(target: &str) -> Vec<String> { fn asset_candidates(target: &str) -> Vec<String> {

View File

@@ -1,36 +1,33 @@
use crate::utils::text::{BOLD, BRIGHT_CYAN, BRIGHT_GREEN, colored}; use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc};
pub fn help() -> i32 { pub fn help() -> i32 {
let green_bold = BRIGHT_GREEN.to_owned() + BOLD;
let cyan_bold = BRIGHT_CYAN.to_owned() + BOLD;
println!("DCR (Dexoron Cargo Realization)"); println!("DCR (Dexoron Cargo Realization)");
println!("Менеджер C-проектов, вдохновленный Cargo."); println!("C project manager inspired by Cargo.");
println!(); println!();
println!("{}", colored("ИСПОЛЬЗОВАНИЕ:", &green_bold)); printc("USAGE:", BOLD_GREEN);
println!("{}", colored(" dcr <команда> [опции]", &cyan_bold)); printc(" dcr <command> [options]", BOLD_CYAN);
println!(); println!();
println!("{}", colored("КОМАНДЫ:", &green_bold)); printc("COMMANDS:", BOLD_GREEN);
println!(" new <name> Создать новый проект"); println!(" new <name> Create a new project");
println!(" init Инициализировать текущую директорию как проект"); println!(" init Initialize the current directory as a project");
println!(" build [--profile] Собрать проект (по умолчанию: --debug)"); println!(" build [--profile] Build the project (default: --debug)");
println!(" run [--profile] Собрать и запустить (по умолчанию: --debug)"); println!(" run [--profile] Build and run the project (default: --debug)");
println!(" clean Удалить директорию target"); println!(" clean Remove the target directory");
println!("{}", colored("ФЛАГИ:", &green_bold)); printc("FLAGS:", BOLD_GREEN);
println!(" --help Показать справку по команде"); println!(" --help Show command help");
println!(" --update Обновить dcr до актуальной версии"); println!(" --update Update dcr to the latest version");
println!(" --version Показать версию dcr"); println!(" --version Show dcr version");
println!(); println!();
println!("{}", colored("ОПЦИИ:", &green_bold)); printc("OPTIONS:", BOLD_GREEN);
println!(" --debug Сборка с профилем debug"); println!(" --debug Build with debug profile");
println!(" --release Сборка с профилем release"); println!(" --release Build with release profile");
println!(); println!();
println!("{}", colored("ПРИМЕРЫ:", &green_bold)); printc("EXAMPLES:", BOLD_GREEN);
println!("{}", colored(" dcr new hello", &cyan_bold)); printc(" dcr new hello", BOLD_CYAN);
println!("{}", colored(" dcr build --release", &cyan_bold)); printc(" dcr build --release", BOLD_CYAN);
println!("{}", colored(" dcr run --debug", &cyan_bold)); printc(" dcr run --debug", BOLD_CYAN);
println!(); println!();
println!("{}", colored("ПОДСКАЗКА:", &green_bold)); printc("TIP:", BOLD_GREEN);
println!(" Запусти 'dcr <команда> --help' для справки по команде."); println!(" Run 'dcr <command> --help' for command-specific help.");
0 0
} }

View File

@@ -1,19 +1,13 @@
use crate::config::{FILE_MAIN_C, file_dcr_toml}; use crate::config::{FILE_MAIN_C, file_dcr_toml};
use crate::utils::fs::check_dir; use crate::utils::fs::check_dir;
use crate::utils::text::{BOLD, BRIGHT_CYAN, BRIGHT_GREEN, BRIGHT_RED, colored, printc}; use crate::utils::log::{error, warn};
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
pub fn init(args: &[String]) -> i32 { pub fn init(args: &[String]) -> i32 {
let red_bold = BRIGHT_RED.to_owned() + BOLD;
let green_bold = BRIGHT_GREEN.to_owned() + BOLD;
let cyan_bold = BRIGHT_CYAN.to_owned() + BOLD;
if !args.is_empty() { if !args.is_empty() {
println!( warn("Command does not support additional arguments");
"{}: команда не поддерживает доп. аргументы",
colored("error", &red_bold)
);
return 1; return 1;
} }
@@ -24,22 +18,19 @@ pub fn init(args: &[String]) -> i32 {
.unwrap_or_else(|| "project".to_string()); .unwrap_or_else(|| "project".to_string());
if !items.is_empty() { if !items.is_empty() {
println!("{}: директория не пуста", colored("error", &red_bold)); error("Directory not empty");
return 1; return 1;
} }
let cwd = std::env::current_dir() let cwd = std::env::current_dir()
.map(|v| v.to_string_lossy().to_string()) .map(|v| v.to_string_lossy().to_string())
.unwrap_or_else(|_| ".".to_string()); .unwrap_or_else(|_| ".".to_string());
println!("Инициализация проекта в {cwd}"); println!("Initializing the project in {cwd}");
let mut dcr_toml = match fs::File::create("./dcr.toml") { let mut dcr_toml = match fs::File::create("./dcr.toml") {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
println!( error("Failed to create dcr.toml");
"{}: не удалось создать dcr.toml",
colored("error", &red_bold)
);
return 1; return 1;
} }
}; };
@@ -47,50 +38,41 @@ pub fn init(args: &[String]) -> i32 {
.write_all(file_dcr_toml(&project_name).as_bytes()) .write_all(file_dcr_toml(&project_name).as_bytes())
.is_err() .is_err()
{ {
println!( error("Failed to write dcr.toml");
"{}: не удалось записать dcr.toml",
colored("error", &red_bold)
);
return 1; return 1;
} }
println!( println!(
" {} Создан файл {}", " {} Created file {}",
colored("✔", &green_bold), colored("✔", BOLD_CYAN),
colored("dcr.toml", &cyan_bold) colored("dcr.toml", BOLD_CYAN)
); );
if fs::create_dir("src").is_err() { if fs::create_dir("src").is_err() {
println!("{}: не удалось создать src", colored("error", &red_bold)); error("Failed to create src/");
return 1; return 1;
} }
let mut main_c = match fs::File::create("./src/main.c") { let mut main_c = match fs::File::create("./src/main.c") {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
println!( error("Failed to create src/main.c");
"{}: не удалось создать src/main.c",
colored("error", &red_bold)
);
return 1; return 1;
} }
}; };
if main_c.write_all(FILE_MAIN_C.as_bytes()).is_err() { if main_c.write_all(FILE_MAIN_C.as_bytes()).is_err() {
println!( error("Failed to write src/main.c");
"{}: не удалось записать src/main.c",
colored("error", &red_bold)
);
return 1; return 1;
} }
println!( println!(
" {} Создан файл {}\n", " {} Created file {}\n",
colored("✔", &green_bold), colored("✔", BOLD_GREEN),
colored("src/main.c", &cyan_bold) colored("src/main.c", BOLD_CYAN)
); );
println!( println!(
"Проект `{}` успешно создан\n", "Project `{}` successfully created\n",
colored(&project_name, &green_bold) colored(project_name.as_str(), BOLD_GREEN)
); );
printc("Следуюший шаг:", &green_bold); printc("Next step:", BOLD_GREEN);
printc(" dcr run", &cyan_bold); printc(" cd {}\n dcr run", project_name.as_str());
0 0
} }

View File

@@ -1,60 +1,48 @@
use crate::config::{FILE_MAIN_C, file_dcr_toml}; use crate::config::{FILE_MAIN_C, file_dcr_toml};
use crate::utils::fs::check_dir; use crate::utils::fs::check_dir;
use crate::utils::text::{BOLD, BRIGHT_CYAN, BRIGHT_GREEN, BRIGHT_RED, colored, printc}; use crate::utils::log::{error, warn};
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
pub fn new(args: &[String]) -> i32 { pub fn new(args: &[String]) -> i32 {
let items = check_dir(None).unwrap_or_default(); let items = check_dir(None).unwrap_or_default();
let red_bold = BRIGHT_RED.to_owned() + BOLD;
let green_bold = BRIGHT_GREEN.to_owned() + BOLD;
let cyan_bold = BRIGHT_CYAN.to_owned() + BOLD;
if args.is_empty() { if args.is_empty() {
println!( error("Project name not specified");
"{}: не указанно название проекта",
colored("error", &red_bold)
);
return 1; return 1;
} }
if args.len() > 1 { if args.len() > 1 {
println!( warn("Command does not support additional arguments");
"{}: команда не поддерживает доп. аргументы",
colored("error", &red_bold)
);
return 1; return 1;
} }
let project_name = &args[0]; let project_name = &args[0];
println!( println!(
"Создание проекта `{}`...", "Creating a Project `{}`...",
colored(project_name, &green_bold) colored(project_name, BOLD_CYAN)
); );
if items.contains(project_name) { if items.contains(project_name) {
error(&format!(
"Directory `{}` already exists\n",
colored(project_name, BOLD_CYAN)
));
printc("Подсказка:", BOLD_CYAN);
println!( println!(
"{}: директория `{}` уже существует\n", " Use `{}` to initialize an existing project\n or specify a different project name",
colored("error", &red_bold), colored("dcr init", BOLD_CYAN)
colored(project_name, &green_bold)
);
printc("Подсказка:", &green_bold);
println!(
" Используй `{}` для инициализации существующего проекта\n или задай другое имя проекта",
colored("dcr init", &cyan_bold)
); );
return 1; return 1;
} }
if fs::create_dir(project_name).is_err() { if fs::create_dir(project_name).is_err() {
println!( error("Failed to create directory");
"{}: не удалось создать директорию",
colored("error", &red_bold)
);
return 1; return 1;
} }
println!( println!(
" {} Создана директория {}", " {} Directory created {}",
colored("✔", &green_bold), colored("✔", BOLD_CYAN),
project_name project_name
); );
@@ -62,10 +50,7 @@ pub fn new(args: &[String]) -> i32 {
let mut dcr_toml = match fs::File::create(&toml_path) { let mut dcr_toml = match fs::File::create(&toml_path) {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
println!( error("Failed to create dcr.toml");
"{}: не удалось создать dcr.toml",
colored("error", &red_bold)
);
return 1; return 1;
} }
}; };
@@ -73,51 +58,42 @@ pub fn new(args: &[String]) -> i32 {
.write_all(file_dcr_toml(project_name).as_bytes()) .write_all(file_dcr_toml(project_name).as_bytes())
.is_err() .is_err()
{ {
println!( error("Failed to write dcr.toml");
"{}: не удалось записать dcr.toml",
colored("error", &red_bold)
);
return 1; return 1;
} }
println!( println!(
" {} Создан файл {}", " {} Created file {}",
colored("✔", &green_bold), colored("✔", BOLD_CYAN),
colored("dcr.toml", &cyan_bold) colored("dcr.toml", BOLD_CYAN)
); );
if fs::create_dir_all(format!("./{project_name}/src")).is_err() { if fs::create_dir_all(format!("./{project_name}/src")).is_err() {
println!("{}: не удалось создать src", colored("error", &red_bold)); error("Failed to create src/");
return 1; return 1;
} }
let main_c_path = format!("./{project_name}/src/main.c"); let main_c_path = format!("./{project_name}/src/main.c");
let mut main_c = match fs::File::create(&main_c_path) { let mut main_c = match fs::File::create(&main_c_path) {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
println!( error("Failed to create src/main.c");
"{}: не удалось создать src/main.c",
colored("error", &red_bold)
);
return 1; return 1;
} }
}; };
if main_c.write_all(FILE_MAIN_C.as_bytes()).is_err() { if main_c.write_all(FILE_MAIN_C.as_bytes()).is_err() {
println!( error("Failed to write src/main.c");
"{}: не удалось записать src/main.c",
colored("error", &red_bold)
);
return 1; return 1;
} }
println!( println!(
" {} Создан файл {}\n", " {} Created file {}\n",
colored("✔", &green_bold), colored("✔", BOLD_GREEN),
colored("src/main.c", &cyan_bold) colored("src/main.c", BOLD_CYAN)
); );
println!( println!(
"Проект `{}` успешно создан\n", "Project `{}` successfully created\n",
colored(project_name, &green_bold) colored(project_name, BOLD_GREEN)
); );
printc("Следуюший шаг:", &green_bold); printc("Next step:", BOLD_GREEN);
printc(&format!(" cd {project_name}\n dcr run"), &cyan_bold); printc(" cd {}\n dcr run", project_name);
0 0
} }

View File

@@ -1,16 +1,16 @@
use crate::cli::build::build; use crate::cli::build::build;
use crate::config::{PROFILE, flags}; use crate::config::{PROFILE, flags};
use crate::utils::fs::check_dir; use crate::utils::fs::check_dir;
use crate::utils::text::{BOLD, BRIGHT_RED, colored}; use crate::utils::log::{error, warn};
use crate::utils::text::{BOLD_GREEN, colored};
use std::process::Command; use std::process::Command;
pub fn run(args: &[String]) -> i32 { pub fn run(args: &[String]) -> i32 {
let red_bold = BRIGHT_RED.to_owned() + BOLD;
let mut active_profile = PROFILE.to_string(); let mut active_profile = PROFILE.to_string();
let items = check_dir(None).unwrap_or_default(); let items = check_dir(None).unwrap_or_default();
if !items.contains(&"dcr.toml".to_string()) { if !items.contains(&"dcr.toml".to_string()) {
println!("{}: не найден файл dcr.toml", colored("error", &red_bold)); error("dcr.toml file not found");
return 1; return 1;
} }
@@ -20,18 +20,21 @@ pub fn run(args: &[String]) -> i32 {
if flags(candidate).is_some() { if flags(candidate).is_some() {
active_profile = candidate.to_string(); active_profile = candidate.to_string();
} else { } else {
println!("{}: неизвестный флаг сборки", colored("error", &red_bold)); warn("Unknown build flag");
return 1; return 1;
} }
} else { } else {
println!("{}: неизвестный аргумент", colored("error", &red_bold)); warn("Unknown argument");
return 1; return 1;
} }
} }
let build_status = build(args); let build_status = build(args);
if build_status == 0 { if build_status == 0 {
println!("\n Запуск target/{active_profile}/main"); println!(
"\n {} target/{active_profile}/main",
colored("Running", BOLD_GREEN)
);
println!("--------------------------------"); println!("--------------------------------");
return Command::new(format!("./target/{active_profile}/main")) return Command::new(format!("./target/{active_profile}/main"))
.status() .status()
@@ -43,13 +46,13 @@ pub fn run(args: &[String]) -> i32 {
.unwrap_or_default() .unwrap_or_default()
.contains(&active_profile) .contains(&active_profile)
{ {
println!("Запуск последнего релиза"); warn("Launch of the latest release");
return Command::new(format!("./target/{active_profile}/main")) return Command::new(format!("./target/{active_profile}/main"))
.status() .status()
.map(|status| status.code().unwrap_or(1)) .map(|status| status.code().unwrap_or(1))
.unwrap_or(1); .unwrap_or(1);
} }
println!("Исправьте ошибки в коде для запуска проекта"); error("Fix errors in the code to run the project");
0 0
} }

View File

@@ -1,3 +1,4 @@
use crate::utils::log::error;
mod cli; mod cli;
mod config; mod config;
mod utils; mod utils;
@@ -25,7 +26,7 @@ fn main() {
"--help" => cli::help::help(), "--help" => cli::help::help(),
"--update" => cli::flag_update::flag_update(rest), "--update" => cli::flag_update::flag_update(rest),
_ => { _ => {
println!("Неизвестная команда или аргумент"); error("Unknown command or argument");
0 0
} }
}; };

View File

@@ -1,6 +1,7 @@
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
#[allow(dead_code)]
pub fn check_dir(dir: Option<&str>) -> io::Result<Vec<String>> { pub fn check_dir(dir: Option<&str>) -> io::Result<Vec<String>> {
let path: PathBuf = match dir { let path: PathBuf = match dir {
None | Some(".") | Some("./") => std::env::current_dir()?, None | Some(".") | Some("./") => std::env::current_dir()?,

View File

@@ -1,30 +1,24 @@
use crate::utils::text::{BOLD, BRIGHT_GREEN, BRIGHT_RED, BRIGHT_YELLOW, colored}; use crate::utils::text::{BOLD_CYAN, colored};
#[allow(dead_code)] #[allow(dead_code)]
pub fn error(msg: &str) { pub fn error(msg: &str) {
println!( println!("{}: {msg}", colored("error", BOLD_CYAN),);
"{}: {msg}",
colored("error", &(BRIGHT_RED.to_owned() + BOLD))
);
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn warn(msg: &str) { pub fn warn(msg: &str) {
println!( println!("{}: {msg}", colored("warn", BOLD_CYAN),);
"{}: {msg}",
colored("warn", &(BRIGHT_YELLOW.to_owned() + BOLD))
);
} }
#[allow(dead_code)] // #[allow(dead_code)]
pub fn info(msg: &str) { // pub fn info(msg: &str) {
println!("{}: {msg}", colored("info", BOLD)); // println!("{}: {msg}", colored("info", BOLD));
} // }
//
#[allow(dead_code)] // #[allow(dead_code)]
pub fn ok(msg: &str) { // pub fn ok(msg: &str) {
println!( // println!(
"{}: {msg}", // "{}: {msg}",
colored("ok", &(BRIGHT_GREEN.to_owned() + BOLD)) // colored("ok", &(BRIGHT_GREEN.to_owned() + BOLD))
); // );
} // }

View File

@@ -1,16 +1,32 @@
#[allow(dead_code)]
pub const RESET: &str = "\x1b[0m"; pub const RESET: &str = "\x1b[0m";
#[allow(dead_code)]
pub const BOLD: &str = "\x1b[1m"; pub const BOLD: &str = "\x1b[1m";
#[allow(dead_code)]
pub const BRIGHT_RED: &str = "\x1b[91m"; pub const BRIGHT_RED: &str = "\x1b[91m";
#[allow(dead_code)]
pub const BRIGHT_GREEN: &str = "\x1b[92m"; pub const BRIGHT_GREEN: &str = "\x1b[92m";
#[allow(dead_code)]
pub const BRIGHT_YELLOW: &str = "\x1b[93m"; pub const BRIGHT_YELLOW: &str = "\x1b[93m";
#[allow(dead_code)]
pub const BRIGHT_CYAN: &str = "\x1b[96m"; pub const BRIGHT_CYAN: &str = "\x1b[96m";
#[allow(dead_code)]
pub const BOLD_RED: &str = "\x1b[1m\x1b[91m";
#[allow(dead_code)]
pub const BOLD_GREEN: &str = "\x1b[1m\x1b[92m";
#[allow(dead_code)]
pub const BOLD_YELLOW: &str = "\x1b[1m\x1b[93m";
#[allow(dead_code)]
pub const BOLD_CYAN: &str = "\x1b[1m\x1b[96m";
#[allow(dead_code)]
pub fn colored(msg: &str, style: &str) -> String { pub fn colored(msg: &str, style: &str) -> String {
format!("{style}{msg}{RESET}") format!("{style}{msg}{RESET}")
} }
#[allow(dead_code)]
pub fn printc(msg: &str, style: &str) { pub fn printc(msg: &str, style: &str) {
println!("{style}{msg}{RESET}"); println!("{style}{msg}{RESET}");
} }