diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8b2dc8..f8fe8f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,10 @@ on: description: "Update AUR packages (dcr & dcr-bin)" type: boolean default: false + run_aur_dev: + description: "Update Dev AUR packages (dcr-dev, dcr-dev-bin)" + type: boolean + default: false run_bsd: description: "Build BSD" type: boolean @@ -56,6 +60,7 @@ jobs: outputs: tag: ${{ steps.tag.outputs.value }} version: ${{ steps.tag.outputs.version }} + clean_version: ${{ steps.tag.outputs.clean_version }} prerelease: ${{ steps.tag.outputs.prerelease }} steps: - name: Resolve tag @@ -67,9 +72,11 @@ jobs: TAG="${GITHUB_REF_NAME}" fi VERSION="${TAG#v}" + CLEAN_VERSION="${VERSION%-dev}" [[ "$TAG" == *"-"* ]] && PRERELEASE="true" || PRERELEASE="false" echo "value=${TAG}" >> "$GITHUB_OUTPUT" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "clean_version=${CLEAN_VERSION}" >> "$GITHUB_OUTPUT" echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT" # ── Release Notes ────────────────────────────────────────────────────────── @@ -122,6 +129,36 @@ jobs: body_path: .github/release-notes.md prerelease: ${{ needs.setup.outputs.prerelease == 'true' }} + # ── Man Pages Archive ────────────────────────────────────────────────────── + man-pages: + if: ${{ github.event_name == 'push' || github.event.inputs.run_linux == 'true' }} + needs: [setup, notes, create-release] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.setup.outputs.tag }} + + - name: Download Release Notes + uses: actions/download-artifact@v4 + with: + name: release-notes + path: .github + + - name: Create Man Pages Archive + run: | + tar czf "dcr-man-pages-${{ needs.setup.outputs.version }}.tar.gz" \ + --transform 's/^man\/man1\//usr\/share\/man\/man1\//' \ + man/man1/*.1 + + - name: Upload Man Pages to Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.setup.outputs.tag }} + files: dcr-man-pages-${{ needs.setup.outputs.version }}.tar.gz + body_path: .github/release-notes.md + prerelease: ${{ needs.setup.outputs.prerelease == 'true' }} + # ── Linux Binaries Matrix ────────────────────────────────────────────────── build-linux: if: ${{ github.event_name == 'push' || github.event.inputs.run_linux == 'true' }} @@ -135,6 +172,12 @@ jobs: - target: aarch64-unknown-linux-gnu - target: x86_64-unknown-linux-musl - target: aarch64-unknown-linux-musl + - target: i686-unknown-linux-gnu + - target: i686-unknown-linux-musl + - target: armv7-unknown-linux-gnueabihf + - target: armv7-unknown-linux-musleabihf + - target: riscv64gc-unknown-linux-gnu + - target: riscv64gc-unknown-linux-musl steps: - uses: actions/checkout@v4 with: @@ -192,41 +235,73 @@ jobs: strategy: fail-fast: false matrix: - include: - - package_type: deb - artifact_name: debian-package - - package_type: rpm - artifact_name: rpm-package + package_type: [deb, rpm, arch, snap] + target: [x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, i686-unknown-linux-gnu, armv7-unknown-linux-gnueabihf, riscv64gc-unknown-linux-gnu] + exclude: - package_type: arch - artifact_name: arch-package + target: aarch64-unknown-linux-gnu + - package_type: arch + target: i686-unknown-linux-gnu + - package_type: arch + target: armv7-unknown-linux-gnueabihf + - package_type: arch + target: riscv64gc-unknown-linux-gnu - package_type: snap - artifact_name: snap-package + target: aarch64-unknown-linux-gnu + - package_type: snap + target: i686-unknown-linux-gnu + - package_type: snap + target: armv7-unknown-linux-gnueabihf + - package_type: snap + target: riscv64gc-unknown-linux-gnu steps: - uses: actions/checkout@v4 with: ref: ${{ needs.setup.outputs.tag }} - - name: Setup Rust (For non-container builds) + - name: Install cargo-zigbuild + if: matrix.package_type == 'deb' || matrix.package_type == 'rpm' + run: | + pip install cargo-zigbuild + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Setup Zig + if: (matrix.package_type == 'deb' || matrix.package_type == 'rpm') && matrix.target != 'x86_64-unknown-linux-gnu' + uses: mlugg/setup-zig@v1 + with: + version: 0.13.0 + + - name: Setup Rust if: matrix.package_type != 'arch' uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} # ── DEB Build ── - name: Build Debian Package if: matrix.package_type == 'deb' run: | cargo install cargo-deb - cargo build --release - cargo deb --no-build - mkdir -p dist-packages && cp target/debian/*.deb dist-packages/ + if [ "${{ matrix.target }}" != "x86_64-unknown-linux-gnu" ]; then + cargo zigbuild --release --target ${{ matrix.target }} + else + cargo build --release --target ${{ matrix.target }} + fi + cargo deb --no-build --target ${{ matrix.target }} + mkdir -p dist-packages && cp target/${{ matrix.target }}/debian/*.deb dist-packages/ # ── RPM Build ── - name: Build RPM Package if: matrix.package_type == 'rpm' run: | cargo install cargo-generate-rpm - cargo build --release - cargo generate-rpm - mkdir -p dist-packages && cp target/generate-rpm/*.rpm dist-packages/ + if [ "${{ matrix.target }}" != "x86_64-unknown-linux-gnu" ]; then + cargo zigbuild --release --target ${{ matrix.target }} + else + cargo build --release --target ${{ matrix.target }} + fi + cargo generate-rpm --target ${{ matrix.target }} + mkdir -p dist-packages && cp target/${{ matrix.target }}/generate-rpm/*.rpm dist-packages/ # ── Snap Build ── - name: Build Snap Package @@ -235,6 +310,7 @@ jobs: cargo build --release mkdir -p packaging/snap/dist/bin cp target/release/dcr packaging/snap/dist/bin/ + cp -r man packaging/snap/dist/man - name: Snapcraft Build Action if: matrix.package_type == 'snap' @@ -276,9 +352,12 @@ jobs: cargo build --release --locked } package() { - cd "\$srcdir/\$pkgname-${PKGVER_ORIG}" + cd "\$srcdir/dcr-${PKGVER_ORIG}" install -Dm755 "target/release/dcr" "\$pkgdir/usr/bin/dcr" install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE" + for manpage in man/man1/*.1; do + install -Dm644 "\$manpage" "\$pkgdir/usr/share/man/man1/\$(basename "\$manpage")" + done } PKG docker run --rm \ @@ -298,7 +377,7 @@ jobs: - name: Upload Package Artifact uses: actions/upload-artifact@v4 with: - name: ${{ matrix.artifact_name }} + name: ${{ matrix.package_type }}-package-${{ matrix.target }} path: dist-packages/* if-no-files-found: ignore @@ -323,10 +402,10 @@ jobs: with: tag_name: ${{ needs.setup.outputs.tag }} files: | - collected-packages/debian-package/* - collected-packages/rpm-package/* - collected-packages/arch-package/* - collected-packages/snap-package/* + collected-packages/deb-package-*/* + collected-packages/rpm-package-*/* + collected-packages/arch-package-*/* + collected-packages/snap-package-*/* body_path: .github/release-notes.md prerelease: ${{ needs.setup.outputs.prerelease == 'true' }} @@ -452,8 +531,6 @@ jobs: cp target/release/dcr "$ASSET" echo "BSD_ASSET=${ASSET}" >> "$GITHUB_ENV" - - # --- UPLOAD TARGET --- - name: Upload BSD Asset to Release uses: softprops/action-gh-release@v2 @@ -474,6 +551,7 @@ jobs: include: - target: x86_64-pc-windows-msvc - target: aarch64-pc-windows-msvc + - target: i686-pc-windows-msvc - target: x86_64-pc-windows-gnu steps: - uses: actions/checkout@v4 @@ -568,10 +646,11 @@ jobs: cd "\$srcdir/\$pkgname-${PKGVER_ORIG}" install -Dm755 "target/release/dcr" "\$pkgdir/usr/bin/dcr" install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE" + for manpage in man/man1/*.1; do + install -Dm644 "\$manpage" "\$pkgdir/usr/share/man/man1/\$(basename "\$manpage")" + done } PKG - - cat > packages/aur/dcr/.SRCINFO <> "$GITHUB_OUTPUT" - echo "sha256=$SHA256" >> "$GITHUB_OUTPUT" + TAG="${{ needs.setup.outputs.tag }}" + VER="${{ needs.setup.outputs.version }}" + BASE_URL="https://github.com/dexoron/dcr/releases/download/${TAG}" + for arch in x86_64 aarch64 i686 armv7h riscv64; do + case "$arch" in + x86_64) triple="x86_64-unknown-linux-musl" ;; + aarch64) triple="aarch64-unknown-linux-musl" ;; + i686) triple="i686-unknown-linux-musl" ;; + armv7h) triple="armv7-unknown-linux-musleabihf" ;; + riscv64) triple="riscv64gc-unknown-linux-musl" ;; + esac + url="${BASE_URL}/dcr-${triple}-${VER}" + sha256="$(curl -fsSL "$url" | sha256sum | awk '{print $1}')" + echo "${arch}_url=${url}" >> "$GITHUB_OUTPUT" + echo "${arch}_sha256=${sha256}" >> "$GITHUB_OUTPUT" + done - name: Render AUR Metadata shell: bash @@ -656,16 +747,13 @@ jobs: set -euo pipefail PKGVER_ORIG='${{ needs.setup.outputs.version }}' PKGVER_CLEAN="${PKGVER_ORIG//-/.}" - BIN_URL='${{ steps.meta.outputs.bin_url }}' - SHA256='${{ steps.meta.outputs.sha256 }}' - mkdir -p packages/aur/dcr-bin cat > packages/aur/dcr-bin/PKGBUILD <> "$GITHUB_OUTPUT" + echo "sha256=$SHA256" >> "$GITHUB_OUTPUT" + + - name: Render AUR metadata + shell: bash + run: | + set -euo pipefail + PKGVER_ORIG='${{ needs.setup.outputs.version }}' + PKGVER_CLEAN='${{ needs.setup.outputs.clean_version }}' + SRC_URL='${{ steps.meta.outputs.source_url }}' + SHA256='${{ steps.meta.outputs.sha256 }}' + + mkdir -p packages/aur/dcr-dev + cat > packages/aur/dcr-dev/PKGBUILD < packages/aur/dcr-dev/.SRCINFO < ~/.ssh/aur + chmod 600 ~/.ssh/aur + ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts + + export GIT_SSH_COMMAND='ssh -i ~/.ssh/aur -o IdentitiesOnly=yes' + + mkdir -p aur-repo + cd aur-repo + git init + git remote add origin "ssh://aur@aur.archlinux.org/${AUR_PACKAGE}.git" + + git fetch origin master || true + git checkout master || git checkout -b master + + cp ../packages/aur/dcr-dev/PKGBUILD . + cp ../packages/aur/dcr-dev/.SRCINFO . + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + if git rev-parse --verify HEAD >/dev/null 2>&1; then + if git diff --quiet; then + echo "No AUR changes" + exit 0 + fi + fi + + git add PKGBUILD .SRCINFO + git commit -m "dcr-dev ${{ needs.setup.outputs.version }}" + git push -u origin master + + # ── Arch User Repository (dcr-dev-bin) ──────────────────────────── + publish-aur-dev-bin: + if: ${{ (github.event_name == 'push' && needs.setup.outputs.prerelease == 'true') || github.event.inputs.run_aur_dev == 'true' }} + needs: [setup, build-linux] + runs-on: ubuntu-latest + environment: aur + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Derive checksum + id: meta + shell: bash + run: | + set -euo pipefail + TAG="${{ needs.setup.outputs.tag }}" + VER="${{ needs.setup.outputs.version }}" + BASE_URL="https://github.com/dexoron/dcr/releases/download/${TAG}" + for arch in x86_64 aarch64 i686 armv7h riscv64; do + case "$arch" in + x86_64) triple="x86_64-unknown-linux-musl" ;; + aarch64) triple="aarch64-unknown-linux-musl" ;; + i686) triple="i686-unknown-linux-musl" ;; + armv7h) triple="armv7-unknown-linux-musleabihf" ;; + riscv64) triple="riscv64gc-unknown-linux-musl" ;; + esac + url="${BASE_URL}/dcr-${triple}-${VER}" + sha256="$(curl -fsSL "$url" | sha256sum | awk '{print $1}')" + echo "${arch}_url=${url}" >> "$GITHUB_OUTPUT" + echo "${arch}_sha256=${sha256}" >> "$GITHUB_OUTPUT" + done + + - name: Render AUR Metadata + shell: bash + run: | + set -euo pipefail + PKGVER_ORIG='${{ needs.setup.outputs.version }}' + PKGVER_CLEAN='${{ needs.setup.outputs.clean_version }}' + mkdir -p packages/aur/dcr-dev-bin + cat > packages/aur/dcr-dev-bin/PKGBUILD < packages/aur/dcr-dev-bin/.SRCINFO < ~/.ssh/aur + chmod 600 ~/.ssh/aur + ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts + + export GIT_SSH_COMMAND='ssh -i ~/.ssh/aur -o IdentitiesOnly=yes' + + mkdir -p aur-repo + cd aur-repo + git init + git remote add origin "ssh://aur@aur.archlinux.org/${AUR_PACKAGE}.git" + + git fetch origin master || true + git checkout master || git checkout -b master + + cp ../packages/aur/dcr-dev-bin/PKGBUILD . + cp ../packages/aur/dcr-dev-bin/.SRCINFO . + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + if git rev-parse --verify HEAD >/dev/null 2>&1; then + if git diff --quiet; then + echo "No AUR changes" + exit 0 + fi + fi + + git add PKGBUILD .SRCINFO + git commit -m "dcr-dev-bin ${{ needs.setup.outputs.version }}" + git push -u origin master + + # ── crates.io ────────────────────────────────────────────────────────────── publish-crates: if: | @@ -783,6 +1159,7 @@ jobs: echo "linux_arm=$(download_sha "dcr-aarch64-unknown-linux-gnu-${VERSION}")" >> "$GITHUB_OUTPUT" echo "macos_x86=$(download_sha "dcr-x86_64-apple-darwin-${VERSION}")" >> "$GITHUB_OUTPUT" echo "macos_arm=$(download_sha "dcr-aarch64-apple-darwin-${VERSION}")" >> "$GITHUB_OUTPUT" + echo "man_pages=$(download_sha "dcr-man-pages-${VERSION}.tar.gz")" >> "$GITHUB_OUTPUT" - name: Checkout homebrew-dexoron uses: actions/checkout@v4 @@ -825,6 +1202,18 @@ jobs: bin.install Dir["dcr*"].first => "dcr" end + resource "man-pages" do + url "https://github.com/dexoron/dcr/releases/download/v#{version}/dcr-man-pages-#{version}.tar.gz" + sha256 "${{ steps.sha.outputs.man_pages }}" + end + + def install + bin.install Dir["dcr*"].first => "dcr" + resource("man-pages").stage do + man1.install Dir["usr/share/man/man1/*.1"] + end + end + test do system "#{bin}/dcr", "--version" end diff --git a/.gitignore b/.gitignore index cefd271..8f346c0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ target/ sandbox/** .idea/ .vscode/ +.cargo/ .env personal/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c8524ef..3705958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,54 @@ # Changelog +## [0.7.1] - 2026-06-02 "Мультиархитектурное расширение / The Multi-Arch Expansion" + +### RU + +**Добавлено:** +- Вывод `--help` для всех команд с цветным форматированием. +- man-страницы (12 штук в `man/man1/`) и их установка во всех пакетах. +- Валидация имен проектов в `dcr init` и `dcr new` (только ASCII буквы, цифры, `_` и `-`). +- Метаданные `documentation` и `homepage` в `Cargo.toml`. +- Оптимизация сборки: `opt-level = "z"`, LTO, `codegen-units = 1`, `panic = "abort"`, `strip = true`. +- Поддержка новых архитектур (i686, armv7, riscv64gc, aarch64) в рабочих процессах и установочных скриптах. +- Сборка пакетов `deb` и `rpm` для всех 5 архитектур Linux через `cargo-zigbuild`. +- Пакеты AUR (`dcr-dev`, `dcr-dev-bin`) и публикация Snap в CI. + +**Изменено:** +- Функция `validate_package_name` стала публичной. +- Команды `gen`, `tree`, `fmt`, `setup` больше не игнорируют аргументы и используют цветной вывод. +- Инструкция в README изменена с `| bash` на `| sh` для POSIX. +- Отключена архитектура Windows 32-bit (GNU) из-за проблем со сборкой. + +### EN + +**Added:** +- `--help` for all commands with styled headers and usage lines. +- Man pages (12 troff man pages in `man/man1/`) and their installation across all packaging formats. +- Project name validation in `dcr init` and `dcr new` (ASCII letters, digits, `_`, `-` only). +- `documentation` and `homepage` metadata in `Cargo.toml`. +- Release profile optimizations (`opt-level = "z"`, LTO, `codegen-units = 1`, `panic = "abort"`, `strip = true`). +- Linux i686, armv7, riscv64gc, aarch64 architecture support in release workflows and installation scripts. +- Multi-arch `deb` and `rpm` package builds for all 5 Linux architectures via `cargo-zigbuild`. +- AUR packages (`dcr-dev`, `dcr-dev-bin`) and automated Snapcraft publishing in CI. + +**Changed:** +- `validate_package_name` made public and callable from CLI commands directly. +- `gen.rs`, `tree.rs`, `fmt.rs`, `setup.rs` no longer ignore arguments and use styled output. +- README install instructions changed from `| bash` to `| sh` for POSIX compatibility. +- Disabled Windows 32-bit (GNU) target due to build issues. + +Fixed: + +- **`dcr new ` creates directory then fails** — validation now happens + before any file operations. +- **`dcr init` creates dcr.toml then fails on invalid directory name** — same fix. +- **Man pages missing after installation** — now installed via install scripts, + package managers, and Homebrew. +- **Windows drive letter false positive** — in dependency file parsing. +- **CRLF `\r\n` breaks dependency parser** — now handles mixed line endings. +- **Newline after backslash not consumed** — in `parse_d_file` escape handling. + ## [0.7.0] - 2026-06-02 Added: diff --git a/Cargo.lock b/Cargo.lock index 92aee21..91c07d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ dependencies = [ [[package]] name = "dcr" -version = "0.7.0" +version = "0.7.1" dependencies = [ "ctrlc", "git2", diff --git a/Cargo.toml b/Cargo.toml index 347fcdc..1ad9ff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,13 @@ [package] name = "dcr" -version = "0.7.0" +version = "0.7.1" edition = "2024" build = "build.rs" description = "DCR is a utility for managing C/C++ projects in a Cargo-like style." license = "GPL-3.0-or-later" repository = "https://github.com/dexoron/dcr" +documentation = "https://dcr.dexoron.su/docs" +homepage = "https://dcr.dexoron.su" [package.metadata.binstall] pkg-fmt = "bin" @@ -21,6 +23,18 @@ section = "devel" priority = "optional" assets = [ ["target/release/dcr", "usr/bin/dcr", "755"], + ["man/man1/dcr.1", "usr/share/man/man1/dcr.1", "644"], + ["man/man1/dcr-add.1", "usr/share/man/man1/dcr-add.1", "644"], + ["man/man1/dcr-build.1", "usr/share/man/man1/dcr-build.1", "644"], + ["man/man1/dcr-clean.1", "usr/share/man/man1/dcr-clean.1", "644"], + ["man/man1/dcr-fmt.1", "usr/share/man/man1/dcr-fmt.1", "644"], + ["man/man1/dcr-gen.1", "usr/share/man/man1/dcr-gen.1", "644"], + ["man/man1/dcr-init.1", "usr/share/man/man1/dcr-init.1", "644"], + ["man/man1/dcr-new.1", "usr/share/man/man1/dcr-new.1", "644"], + ["man/man1/dcr-run.1", "usr/share/man/man1/dcr-run.1", "644"], + ["man/man1/dcr-setup.1", "usr/share/man/man1/dcr-setup.1", "644"], + ["man/man1/dcr-test.1", "usr/share/man/man1/dcr-test.1", "644"], + ["man/man1/dcr-tree.1", "usr/share/man/man1/dcr-tree.1", "644"], ] [package.metadata.generate-rpm] @@ -30,7 +44,19 @@ Cargo-like utility to manage C/C++ projects. """ assets = [ - { source = "target/release/dcr", dest = "/usr/bin/dcr", mode = "755" } + { source = "target/release/dcr", dest = "/usr/bin/dcr", mode = "755" }, + { source = "man/man1/dcr.1", dest = "/usr/share/man/man1/dcr.1", mode = "644" }, + { source = "man/man1/dcr-add.1", dest = "/usr/share/man/man1/dcr-add.1", mode = "644" }, + { source = "man/man1/dcr-build.1", dest = "/usr/share/man/man1/dcr-build.1", mode = "644" }, + { source = "man/man1/dcr-clean.1", dest = "/usr/share/man/man1/dcr-clean.1", mode = "644" }, + { source = "man/man1/dcr-fmt.1", dest = "/usr/share/man/man1/dcr-fmt.1", mode = "644" }, + { source = "man/man1/dcr-gen.1", dest = "/usr/share/man/man1/dcr-gen.1", mode = "644" }, + { source = "man/man1/dcr-init.1", dest = "/usr/share/man/man1/dcr-init.1", mode = "644" }, + { source = "man/man1/dcr-new.1", dest = "/usr/share/man/man1/dcr-new.1", mode = "644" }, + { source = "man/man1/dcr-run.1", dest = "/usr/share/man/man1/dcr-run.1", mode = "644" }, + { source = "man/man1/dcr-setup.1", dest = "/usr/share/man/man1/dcr-setup.1", mode = "644" }, + { source = "man/man1/dcr-test.1", dest = "/usr/share/man/man1/dcr-test.1", mode = "644" }, + { source = "man/man1/dcr-tree.1", dest = "/usr/share/man/man1/dcr-tree.1", mode = "644" }, ] [dependencies] @@ -43,9 +69,29 @@ toml = "1.0.3" serde_json = "1" ctrlc = "3" -[target.'cfg(not(windows))'.dependencies] -git2 = { version = "0.20.4", features = ["vendored-libgit2", "vendored-openssl"] } -openssl = { version = "0.10", features = ["vendored"] } +[features] +default = ["vendored"] +vendored = [ + "git2/vendored-libgit2", + "git2/vendored-openssl", + "openssl/vendored", +] -[target.'cfg(windows)'.dependencies] -git2 = { version = "0.20.4", features = ["vendored-libgit2"] } \ No newline at end of file +[target.'cfg(not(windows))'.dependencies] +git2 = "0.20.4" +openssl = "0.10" + +[profile.release] +opt-level = "z" +lto = "thin" +codegen-units = 1 +panic = "abort" +strip = true + +[profile.fast] +inherits = "release" +opt-level = 1 +lto = false +codegen-units = 16 +panic = "abort" +strip = true \ No newline at end of file diff --git a/README.md b/README.md index 1d5310c..177f71f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![AUR](https://img.shields.io/aur/version/dcr)](https://aur.archlinux.org/packages/dcr) [![Crates.io](https://img.shields.io/crates/v/dcr)](https://crates.io/crates/dcr) [![Homebrew](https://img.shields.io/badge/homebrew-dexoron%2Fdexoron-orange)](https://github.com/dexoron/homebrew-dexoron) +[![Snap](https://img.shields.io/badge/snap-dcrup-orange)](https://snapcraft.io/dcrup)
[![GitHub Stars](https://img.shields.io/github/stars/dexoron/dcr?style=flat)](https://github.com/dexoron/dcr/stargazers) [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](LICENSE) @@ -22,10 +23,11 @@ ## Why DCR? - **No boilerplate** — one config file, predictable structure -- **Cargo-like workflow** — `build`, `run`, `clean`, `test`, `add` +- **Cargo-like workflow** — `build`, `run`, `clean`, `test`, `add`, `fmt` - **Cross-compilation** — full target triple support with short names - **IDE integration** — VS Code, CLion, `compile_commands.json` out of the box - **Dependencies** — path, git, and registry-based with lock file +- **Man pages** — `man dcr` and per-command pages (`man dcr-build`, `man dcr-new`, etc.) --- @@ -119,6 +121,16 @@ curl -fsSL https://dcr.dexoron.su/install.sh | sh curl -fsSL https://dcr.dexoron.su/install_bsd.sh | sh ``` + + + +Snap (Linux) + + +```sh +sudo snap install dcrup +``` + @@ -200,24 +212,26 @@ kind = "bin" | `dcr gen ` | Generate IDE integration | | `dcr setup` | Initialize DCR registry | -other in [docs/](docs/) and `dcr --help` +other in [docs/](docs/), `dcr --help` and `dcr --help` --- -## Platforms(pre-build source) +## Platforms (pre-built binary)
-| OS | x86_64 | aarch64 | armv7 | i686 | riscv64 | GNU | Musl | MSVC | MinGW | -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| Linux | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | -| macOS | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| Windows | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| FreeBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| OpenBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | -| NetBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| OS | x86_64 | aarch64 | armv7 | i686 | riscv64 | +|:---:|:---:|:---:|:---:|:---:|:---:| +| Linux (GNU) | ✅ | ✅ | ✅ | ✅ | ✅ | +| Linux (Musl) | ✅ | ✅ | ✅ | ✅ | 🚧 | +| macOS | ✅ | ✅ | ❌ | ❌ | ❌ | +| Windows (MSVC) | ✅ | ✅ | ❌ | ✅ | ❌ | +| Windows (MinGW) | ✅ | 🚧 | ❌ | ✅ | ❌ | +| FreeBSD | ✅ | 🚧 | ❌ | ❌ | ❌ | +| OpenBSD | ✅ | 🚧 | ❌ | ❌ | ❌ | +| NetBSD | ✅ | 🚧 | ❌ | ❌ | ❌ | -✅ officially supported · ⚠️ community / best-effort · ❌ not supported +✅ pre-built binary · 🚧 planned · ❌ not supported by platform or CI
@@ -257,6 +271,7 @@ cargo test
GPL-3.0 — see [LICENSE](LICENSE)
+DCR is a build tool, not a library. The GPL applies only to DCR's own source code, not to projects built with it.
Made with ❤️ by [Dexoron](https://github.com/dexoron) and contributors.
diff --git a/docs/README.mdx b/docs/README.mdx index cfa6eb6..08bd33f 100644 --- a/docs/README.mdx +++ b/docs/README.mdx @@ -44,6 +44,7 @@ dcr gen vscode | [Self Update](/docs/self-update) | Auto-update | | [FAQ](/docs/faq) | Frequently asked questions | | [Changelog](/docs/changelog) | Version history | +| [License](/docs/license) | DCR and vendored library licenses | | [Contributing](/docs/contributing) | DCR development | ## Features @@ -58,3 +59,5 @@ dcr gen vscode - **Registry + Git + Path** — three dependency mechanisms - **IDE generation** — VS Code, CLion, compile_commands.json, JSON metadata - **pkg-config** — automatic system library discovery +- **Per-command `--help`** — `dcr build --help`, `dcr new --help`, etc. +- **Man pages** — `man dcr`, `man dcr-build`, `man dcr-new` diff --git a/docs/changelog.mdx b/docs/changelog.mdx index 36cc191..66b0d74 100644 --- a/docs/changelog.mdx +++ b/docs/changelog.mdx @@ -4,6 +4,50 @@ sidebar_label: Changelog # Changelog +## 0.7.1 (2026-06-02) + +### Added + +- **`--help` for all commands** — `dcr build --help`, `dcr run --help`, `dcr new --help`, + `dcr init --help`, `dcr clean --help`, `dcr add --help`, `dcr fmt --help`, + `dcr setup --help`, `dcr tree --help`, `dcr gen --help`, `dcr --update --help`, + `dcr test --help`. All output uses styled headers (green) and usage lines (cyan). +- **Man pages** — 12 troff pages in `man/man1/`: `dcr.1`, `dcr-build.1`, + `dcr-run.1`, `dcr-new.1`, `dcr-init.1`, `dcr-clean.1`, `dcr-add.1`, `dcr-test.1`, + `dcr-gen.1`, `dcr-fmt.1`, `dcr-tree.1`, `dcr-setup.1`. +- **Man pages in all packaging** — install.sh, install_bsd.sh, AUR PKGBUILD, + Debian (cargo-deb), RPM (cargo-generate-rpm), Nix (postInstall), Homebrew + (resource), Snap, GitHub Release assets. +- **Project name validation** — `dcr init` and `dcr new` now validate names before + creating files. Only ASCII letters, digits, `_` and `-` are allowed. +- **`documentation` and `homepage` fields** — added to `Cargo.toml`. +- **Release profile optimizations** — `opt-level = "z"`, LTO, `codegen-units = 1`, + `panic = "abort"`, `strip = true` for smaller binaries. +- **Linux i686, armv7, riscv64 targets** — added to release workflow and install scripts. +- **Linux musl i686, armv7 targets** — cross-compiled via zigbuild in CI. +- **AUR packages** — `dcr-dev`, `dcr-dev-bin` publishing workflow. +- **Snap publishing** — automated Snapcraft publishing in CI. +- **Snap badge** — in README. + +### Changed + +- **`validate_package_name` made public** — callable from CLI commands. +- **README platform table** — reorganized: libc variants as separate OS rows, + removed extra columns. Linux architecture list updated. +- **`gen.rs` no-args output** — now uses styled output instead of raw `eprintln!`. +- **`tree.rs`, `fmt.rs`, and `setup.rs`** — now accept arguments for `--help`. +- **README install commands** — `| bash` → `| sh` for POSIX compatibility. + +### Fixed + +- **`dcr new ` creates directory then fails** — validation now + happens before any file operations. +- **`dcr init` on invalid directory name** — same fix. +- **Man pages missing in installed packages** — now shipped in all formats. +- **Windows drive letter false positive** — in dependency file parser. +- **CRLF (`\r\n`) breaks dependency parser** — now handles mixed line endings. +- **Newline after backslash not consumed** — in `parse_d_file` escape handling. + ## 0.7.0 (2026-06-01) ### Added diff --git a/docs/commands/project-commands.mdx b/docs/commands/project-commands.mdx index 6a03020..0adacb8 100644 --- a/docs/commands/project-commands.mdx +++ b/docs/commands/project-commands.mdx @@ -8,6 +8,8 @@ sidebar_label: Project commands (new, init) Creates a new project with a standard structure and `dcr.toml`. The `name` argument is required. +Only ASCII letters, digits, underscores `_` and hyphens `-` are allowed in the project name. + ```bash dcr new my-app ``` @@ -25,4 +27,4 @@ mkdir app && cd app dcr init ``` -The project name is taken from the current directory name. +The project name is taken from the current directory name. The directory name must follow the same naming rules as `dcr new`. diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index f666819..956bf44 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -36,6 +36,12 @@ brew tap dexoron/dexoron brew install dcr ``` +## Snap (Linux) + +```sh +sudo snap install dcrup +``` + ## Nix (flake) ```sh @@ -53,13 +59,13 @@ cargo install dcr ## Linux / macOS (script) ```sh -curl -fsSL https://dcr.dexoron.su/install.sh | bash +curl -fsSL https://dcr.dexoron.su/install.sh | sh ``` ## BSD (script) ```sh -curl -fsSL https://dcr.dexoron.su/install_bsd.sh | bash +curl -fsSL https://dcr.dexoron.su/install_bsd.sh | sh ``` ## Windows (PowerShell) @@ -84,6 +90,13 @@ Verify the installation: dcr --version ``` +Man pages are available after installation: + +```bash +man dcr +man dcr-build +``` + To use the registry, create `~/.dcr/config.toml`: ```toml diff --git a/docs/license.mdx b/docs/license.mdx new file mode 100644 index 0000000..f424731 --- /dev/null +++ b/docs/license.mdx @@ -0,0 +1,46 @@ +--- +sidebar_label: License +--- + +# License + +## DCR + +DCR itself is [GPL-3.0-or-later](https://spdx.org/licenses/GPL-3.0-or-later.html) licensed. + +> **Note:** DCR is a build tool, not a library. The GPL applies only to DCR's own source code. Projects built with DCR are not subject to DCR's license — their licensing is determined solely by their own code and dependencies. + +## Vendored libraries + +DCR statically links the following C libraries through its vendored Rust dependencies: + +| Library | License | Bundled by | +|---|---|---| +| [libgit2](https://libgit2.org) | MIT OR Apache-2.0 | `git2` / `libgit2-sys` | +| [libssh2](https://libssh2.org) | MIT OR Apache-2.0 | `libgit2-sys` | +| [zlib](https://zlib.net) | MIT OR Apache-2.0 | `libgit2-sys` | +| [OpenSSL](https://openssl.org) | Apache-2.0 | `openssl-sys` / `openssl-src` | +| [ring](https://github.com/briansmith/ring) | Apache-2.0 AND ISC | `rustls` | + +## Rust dependencies + +DCR is written in Rust. The following notable Rust crates are statically linked: + +| Crate | License | +|---|---| +| [`reqwest`](https://crates.io/crates/reqwest) | MIT OR Apache-2.0 | +| [`rustls`](https://crates.io/crates/rustls) | Apache-2.0 OR ISC OR MIT | +| [`serde`](https://crates.io/crates/serde) | MIT OR Apache-2.0 | +| [`toml`](https://crates.io/crates/toml) | MIT OR Apache-2.0 | +| [`sha2`](https://crates.io/crates/sha2) | MIT OR Apache-2.0 | +| [`git2`](https://crates.io/crates/git2) | MIT OR Apache-2.0 | +| [`openssl`](https://crates.io/crates/openssl) | Apache-2.0 | +| [`tokio`](https://crates.io/crates/tokio) | MIT | +| [`hyper`](https://crates.io/crates/hyper) | MIT | +| [`ctrlc`](https://crates.io/crates/ctrlc) | MIT OR Apache-2.0 | + +Full dependency tree (143 packages) is available in [`Cargo.lock`](https://github.com/dexoron/dcr/blob/main/Cargo.lock). The overwhelming majority are dual-licensed under MIT OR Apache-2.0. + +## Additional credits + +- DCR's CLI design and project model are inspired by [Cargo](https://doc.rust-lang.org/cargo/). diff --git a/flake.nix b/flake.nix index 0e24749..41a9891 100644 --- a/flake.nix +++ b/flake.nix @@ -64,6 +64,10 @@ pkgs.darwin.apple_sdk.frameworks.SystemConfiguration ]; + postInstall = '' + install -Dm644 man/man1/*.1 -t $out/share/man/man1/ + ''; + # Tests require external services; run separately. doCheck = false; }; diff --git a/install.ps1 b/install.ps1 index 20eeb2a..11eaca9 100644 --- a/install.ps1 +++ b/install.ps1 @@ -47,10 +47,16 @@ function Select-Mode { } function Get-Target { - if ($env:PROCESSOR_ARCHITECTURE -ne 'AMD64') { - Fail "Only x86_64 Windows is supported, current architecture: $env:PROCESSOR_ARCHITECTURE" + $arch = $env:PROCESSOR_ARCHITECTURE + if ($env:PROCESSOR_ARCHITEW6432) { + $arch = $env:PROCESSOR_ARCHITEW6432 + } + switch ($arch) { + 'AMD64' { return 'x86_64-pc-windows-msvc' } + 'ARM64' { return 'aarch64-pc-windows-msvc' } + 'x86' { return 'i686-pc-windows-msvc' } + default { Fail "Unsupported Windows architecture: $arch" } } - return 'x86_64-pc-windows-msvc' } function Fetch-ReleaseJson($channel) { diff --git a/install.sh b/install.sh index 1d8d6ea..b600c3b 100755 --- a/install.sh +++ b/install.sh @@ -4,6 +4,7 @@ set -Eeuo pipefail TMPDIR="/tmp/dcr-install" INSTALL_PATH="$HOME/.local/share/dcr" BINPATH="$HOME/.local/bin" +MANPATH="${XDG_DATA_HOME:-$HOME/.local/share}/man" LOGFILE="$HOME/.cache/dcr-install.log" REPO_URL="https://github.com/dexoron/dcr" GITHUB_API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest" @@ -43,11 +44,20 @@ detect_target() { case "$os:$arch" in Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;; Linux:aarch64|Linux:arm64) TARGET_TRIPLE="aarch64-unknown-linux-gnu" ;; + Linux:i686|Linux:i386) TARGET_TRIPLE="i686-unknown-linux-gnu" ;; + Linux:armv7l|Linux:armv7) TARGET_TRIPLE="armv7-unknown-linux-gnueabihf" ;; + Linux:riscv64) TARGET_TRIPLE="riscv64gc-unknown-linux-gnu" ;; Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;; Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;; FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; + FreeBSD:aarch64|FreeBSD:arm64) TARGET_TRIPLE="aarch64-unknown-freebsd" ;; + FreeBSD:i686|FreeBSD:i386) TARGET_TRIPLE="i686-unknown-freebsd" ;; OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; + OpenBSD:aarch64|OpenBSD:arm64) TARGET_TRIPLE="aarch64-unknown-openbsd" ;; + OpenBSD:i686|OpenBSD:i386) TARGET_TRIPLE="i686-unknown-openbsd" ;; NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; + NetBSD:aarch64|NetBSD:arm64) TARGET_TRIPLE="aarch64-unknown-netbsd" ;; + NetBSD:i686|NetBSD:i386) TARGET_TRIPLE="i686-unknown-netbsd" ;; *) error "Unsupported platform: $os/$arch"; exit 1 ;; esac @@ -190,6 +200,16 @@ install_link() { success "Command 'dcr' added to $BINPATH" } +install_man() { + log "Installing man pages..." + local man_src="$TMPDIR/man/man1" + if [[ -d "$man_src" ]]; then + mkdir -p "$MANPATH/man1" + cp "$man_src"/*.1 "$MANPATH/man1/" + success "Man pages installed to $MANPATH/man1" + fi +} + check_path() { if ! echo "$PATH" | grep -q "$BINPATH"; then warn "Directory $BINPATH not found in PATH" @@ -222,6 +242,7 @@ main() { fi install_link + install_man check_path cleanup diff --git a/install_bsd.sh b/install_bsd.sh index 867805f..e793c9b 100755 --- a/install_bsd.sh +++ b/install_bsd.sh @@ -4,6 +4,7 @@ set -eu TMPDIR="/tmp/dcr-install" INSTALL_PATH="$HOME/.local/share/dcr" BINPATH="$HOME/.local/bin" +MANPATH="${XDG_DATA_HOME:-$HOME/.local/share}/man" LOGFILE="$HOME/.cache/dcr-install.log" REPO_URL="https://github.com/dexoron/dcr" GITHUB_API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest" @@ -39,8 +40,14 @@ detect_target() { case "$os:$arch" in FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; + FreeBSD:aarch64|FreeBSD:arm64) TARGET_TRIPLE="aarch64-unknown-freebsd" ;; + FreeBSD:i686|FreeBSD:i386) TARGET_TRIPLE="i686-unknown-freebsd" ;; OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; + OpenBSD:aarch64|OpenBSD:arm64) TARGET_TRIPLE="aarch64-unknown-openbsd" ;; + OpenBSD:i686|OpenBSD:i386) TARGET_TRIPLE="i686-unknown-openbsd" ;; NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; + NetBSD:aarch64|NetBSD:arm64) TARGET_TRIPLE="aarch64-unknown-netbsd" ;; + NetBSD:i686|NetBSD:i386) TARGET_TRIPLE="i686-unknown-netbsd" ;; DragonFly:x86_64|DragonFly:amd64) TARGET_TRIPLE="x86_64-unknown-dragonfly" ;; *) error "Unsupported BSD platform: $os/$arch"; exit 1 ;; esac @@ -181,6 +188,16 @@ install_link() { success "Command 'dcr' added to $BINPATH" } +install_man() { + log "Installing man pages..." + man_src="$TMPDIR/man/man1" + if [ -d "$man_src" ]; then + mkdir -p "$MANPATH/man1" + cp "$man_src"/*.1 "$MANPATH/man1/" + success "Man pages installed to $MANPATH/man1" + fi +} + check_path() { if ! echo "$PATH" | grep -q "$BINPATH"; then warn "Directory $BINPATH not found in PATH" @@ -213,6 +230,7 @@ main() { fi install_link + install_man check_path cleanup diff --git a/man/man1/dcr-add.1 b/man/man1/dcr-add.1 new file mode 100644 index 0000000..e3899a2 --- /dev/null +++ b/man/man1/dcr-add.1 @@ -0,0 +1,42 @@ +.TH DCR-ADD 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-add \- Add a dependency to a DCR project +.SH SYNOPSIS +.B dcr add \fI\fR \fI\fR +[\fB\-\-branch\fR \fI\fR] +[\fB\-\-tag\fR \fI\fR] +[\fB\-\-rev\fR \fI\fR] +.SH DESCRIPTION +Adds a dependency to the project. +.SH SOURCES +.TP +.B user/repo +GitHub shorthand. +.TP +.B github:user/repo +Full GitHub repository. +.TP +.B gitlab:user/repo +GitLab repository. +.TP +.B git:host.com/user/repo +Generic git repository. +.TP +.B path:./path/to/lib +Local path dependency. +.TP +.B +Version from registry. +.SH OPTIONS +.TP +.B \-\-branch \fI\fR +Use a specific branch. +.TP +.B \-\-tag \fI\fR +Use a specific tag. +.TP +.B \-\-rev \fI\fR +Use a specific commit hash. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-tree (1) diff --git a/man/man1/dcr-build.1 b/man/man1/dcr-build.1 new file mode 100644 index 0000000..7c80c21 --- /dev/null +++ b/man/man1/dcr-build.1 @@ -0,0 +1,37 @@ +.TH DCR-BUILD 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-build \- Compile a DCR project +.SH SYNOPSIS +.B dcr build +[\fB\-\-debug\fR | \fB\-\-release\fR] +[\fB\-\-target\fR \fI\fR] +[\fB\-\-force\fR] +[\fB\-\-clean\fR] +[\fB\-\-verbose\fR] +[\fB\-\-workspace\fR \fI\fR] +.SH DESCRIPTION +Compiles the project. Default profile is \fB\-\-debug\fR. +.SH OPTIONS +.TP +.B \-\-debug +Build with debug profile (default). Enables debug symbols. +.TP +.B \-\-release +Build with release profile. Enables full optimization. +.TP +.B \-\-target \fI\fR +Cross-compile for the given target. +.TP +.B \-\-force +Force a full rebuild, ignoring cached artifacts. +.TP +.B \-\-clean +Clean before building. +.TP +.B \-\-verbose +Print detailed build output including compiler commands. +.TP +.B \-\-workspace \fI\fR +Build a specific workspace member. +.SH SEE ALSO +.BR dcr (1) diff --git a/man/man1/dcr-clean.1 b/man/man1/dcr-clean.1 new file mode 100644 index 0000000..d375a6e --- /dev/null +++ b/man/man1/dcr-clean.1 @@ -0,0 +1,26 @@ +.TH DCR-CLEAN 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-clean \- Remove build artifacts +.SH SYNOPSIS +.B dcr clean +[\fB\-\-debug\fR | \fB\-\-release\fR] +[\fB\-\-target\fR \fI\fR] +[\fB\-\-all\fR] +.SH DESCRIPTION +Removes build artifacts from the target directory. +.SH OPTIONS +.TP +.B \-\-debug +Clean debug artifacts (default). +.TP +.B \-\-release +Clean release artifacts. +.TP +.B \-\-target \fI\fR +Clean artifacts for a specific target. +.TP +.B \-\-all +Clean all workspace members. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-build (1) diff --git a/man/man1/dcr-fmt.1 b/man/man1/dcr-fmt.1 new file mode 100644 index 0000000..6c8e9ca --- /dev/null +++ b/man/man1/dcr-fmt.1 @@ -0,0 +1,10 @@ +.TH DCR-FMT 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-fmt \- Format C/C++ source files +.SH SYNOPSIS +.B dcr fmt +.SH DESCRIPTION +Formats all C/C++ source files using clang-format. Scans \fBsrc/\fR +and \fBtests/\fR directories recursively. +.SH SEE ALSO +.BR dcr (1) diff --git a/man/man1/dcr-gen.1 b/man/man1/dcr-gen.1 new file mode 100644 index 0000000..5b61487 --- /dev/null +++ b/man/man1/dcr-gen.1 @@ -0,0 +1,23 @@ +.TH DCR-GEN 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-gen \- Generate IDE and tooling integration files +.SH SYNOPSIS +.B dcr gen \fI\fR +.SH DESCRIPTION +Generates IDE and tooling integration files for DCR projects. +.SH SUBCOMMANDS +.TP +.B project-info +Print project metadata as JSON to stdout. +.TP +.B compile-commands +Generate \fBcompile_commands.json\fR for IDE tooling. +.TP +.B vscode +Generate \fB.vscode/\fR integration files (tasks, launch configurations). +.TP +.B clion +Generate \fB.idea/\fR integration files for CLion. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-build (1) diff --git a/man/man1/dcr-init.1 b/man/man1/dcr-init.1 new file mode 100644 index 0000000..62c7368 --- /dev/null +++ b/man/man1/dcr-init.1 @@ -0,0 +1,11 @@ +.TH DCR-INIT 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-init \- Initialize a directory as a DCR project +.SH SYNOPSIS +.B dcr init +.SH DESCRIPTION +Initializes the current directory as a DCR project. The directory must +be empty. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-new (1) diff --git a/man/man1/dcr-new.1 b/man/man1/dcr-new.1 new file mode 100644 index 0000000..1c2d490 --- /dev/null +++ b/man/man1/dcr-new.1 @@ -0,0 +1,13 @@ +.TH DCR-NEW 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-new \- Create a new DCR project +.SH SYNOPSIS +.B dcr new \fI\fR +.SH DESCRIPTION +Creates a new C/C++ project with the given name. The name may only +contain ASCII letters, digits, underscores and hyphens. +.SH EXAMPLE +.B dcr new my-project +.SH SEE ALSO +.BR dcr (1), +.BR dcr-init (1) diff --git a/man/man1/dcr-run.1 b/man/man1/dcr-run.1 new file mode 100644 index 0000000..c5939b3 --- /dev/null +++ b/man/man1/dcr-run.1 @@ -0,0 +1,35 @@ +.TH DCR-RUN 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-run \- Build and run a DCR project +.SH SYNOPSIS +.B dcr run +[\fB\-\-debug\fR | \fB\-\-release\fR] +[\fB\-\-target\fR \fI\fR] +[\fB\-\-force\fR] +[\fB\-\-clean\fR] +[\fB\-\-verbose\fR] +.SH DESCRIPTION +Builds and runs the project. Only available for projects with +\fBkind = "bin"\fR. +.SH OPTIONS +.TP +.B \-\-debug +Run with debug profile (default). +.TP +.B \-\-release +Run with release profile. +.TP +.B \-\-target \fI\fR +Cross-compile for the given target. +.TP +.B \-\-force +Force a full rebuild. +.TP +.B \-\-clean +Clean before building. +.TP +.B \-\-verbose +Print detailed build output. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-build (1) diff --git a/man/man1/dcr-setup.1 b/man/man1/dcr-setup.1 new file mode 100644 index 0000000..0fe61b3 --- /dev/null +++ b/man/man1/dcr-setup.1 @@ -0,0 +1,11 @@ +.TH DCR-SETUP 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-setup \- Set up DCR registries +.SH SYNOPSIS +.B dcr setup +.SH DESCRIPTION +Sets up DCR registries. Downloads and indexes package registries +for dependency resolution. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-add (1) diff --git a/man/man1/dcr-test.1 b/man/man1/dcr-test.1 new file mode 100644 index 0000000..f6ac7ac --- /dev/null +++ b/man/man1/dcr-test.1 @@ -0,0 +1,24 @@ +.TH DCR-TEST 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-test \- Run project tests +.SH SYNOPSIS +.B dcr test +[\fB\-\-init\fR] +[\fB\-\-debug\fR | \fB\-\-release\fR] +.SH ALIASES +.B dcr tests +.SH DESCRIPTION +Runs project tests and prints a unified testsuite report. +.SH OPTIONS +.TP +.B \-\-init +Create \fBtests/dcr_test.h\fR in the current project. +.TP +.B \-\-debug +Build and run tests with debug profile (default). +.TP +.B \-\-release +Build and run tests with release profile. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-build (1) diff --git a/man/man1/dcr-tree.1 b/man/man1/dcr-tree.1 new file mode 100644 index 0000000..0e9da6c --- /dev/null +++ b/man/man1/dcr-tree.1 @@ -0,0 +1,11 @@ +.TH DCR-TREE 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr-tree \- Display the dependency tree +.SH SYNOPSIS +.B dcr tree +.SH DESCRIPTION +Displays the dependency tree of the current project, showing all +transitive dependencies and their versions. +.SH SEE ALSO +.BR dcr (1), +.BR dcr-add (1) diff --git a/man/man1/dcr.1 b/man/man1/dcr.1 new file mode 100644 index 0000000..183c570 --- /dev/null +++ b/man/man1/dcr.1 @@ -0,0 +1,204 @@ +.TH DCR 1 "2026-06-02" "dcr 0.7.0" "DCR Manual" +.SH NAME +dcr \- Cargo\-like build tool and package manager for C/C++ projects +.SH SYNOPSIS +.B dcr +[\fIcommand\fR] [\fIoptions\fR] +.SH DESCRIPTION +DCR is a comprehensive build tool and package manager for C and C++ projects, +inspired by Cargo from the Rust ecosystem. It handles project creation, +building, dependency management, testing, formatting, and IDE integration. +.SH COMMANDS +.TP +.B new \fI\fR +Create a new C/C++ project with the given name. Only ASCII letters, digits, +underscores and hyphens are allowed. +.TP +.B init +Initialize the current (empty) directory as a DCR project. +.TP +.B build [\fIoptions\fR] +Compile the project. Default profile is \fB\-\-debug\fR. +.TP +.B run [\fIoptions\fR] +Build and run the project. Only available for binary projects. +.TP +.B clean [\fIoptions\fR] +Remove build artifacts from the target directory. +.TP +.B test [\fI\-\-init\fR] [\fI\-\-debug\fR|\fI\-\-release\fR] +Run project tests (alias: \fBdcr tests\fR). +.TP +.B add \fI\fR \fI\fR [\fIoptions\fR] +Add a dependency to the project. +.TP +.B tree +Display the dependency tree of the current project. +.TP +.B fmt +Format all C/C++ source files using clang-format. +.TP +.B gen \fI\fR +Generate IDE integration files (vscode, clion, compile-commands, project-info). +.TP +.B setup +Set up DCR registries for dependency resolution. +.SH GLOBAL FLAGS +.TP +.B \-\-help +Show this help message and exit. +.TP +.B \-\-version +Print version information and exit. +.TP +.B \-\-update +Update DCR to the latest version from GitHub Releases. +.SH BUILD OPTIONS +The following options apply to \fBbuild\fR and \fBrun\fR commands: +.TP +.B \-\-debug +Build with debug profile (default). Enables debug symbols and minimal optimization. +.TP +.B \-\-release +Build with release profile. Enables full optimization without debug symbols. +.TP +.B \-\-target \fI\fR +Cross-compile for the given target (e.g. \fBaarch64-linux-gnu\fR, \fBx86_64-w64-mingw32\fR). +Short names like \fBlinux\fR, \fBmacos\fR, \fBwindows\fR are also supported. +.TP +.B \-\-force +Force a full rebuild, ignoring cached build artifacts. +.TP +.B \-\-clean +Clean build artifacts before building. +.TP +.B \-\-verbose +Print detailed build output including compiler commands. +.TP +.B \-\-workspace \fI\fR +Build a specific workspace member. +.SH CLEAN OPTIONS +.TP +.B \-\-debug +Clean debug artifacts (default). +.TP +.B \-\-release +Clean release artifacts. +.TP +.B \-\-target \fI\fR +Clean artifacts for a specific target. +.TP +.B \-\-all +Clean all workspace members. +.SH ADD OPTIONS +.TP +.B \-\-branch \fI\fR +Use a specific branch when adding a git dependency. +.TP +.B \-\-tag \fI\fR +Use a specific tag when adding a git dependency. +.TP +.B \-\-rev \fI\fR +Use a specific commit hash when adding a git dependency. +.SH DEPENDENCY SOURCES +.TP +.B user/repo +GitHub shorthand (e.g. \fBuser/repo\fR). +.TP +.B github:user/repo +Full GitHub repository URL shorthand. +.TP +.B gitlab:user/repo +GitLab repository URL shorthand. +.TP +.B git:host.com/user/repo +Generic git repository. +.TP +.B path:./path/to/lib +Local path dependency. +.TP +.B \fI\fR +Version from registry (e.g. \fB1.2.3\fR). +.SH GEN SUBCOMMANDS +.TP +.B project-info +Print project metadata as JSON to stdout. +.TP +.B compile-commands +Generate \fBcompile_commands.json\fR for IDE tooling. +.TP +.B vscode +Generate \fB.vscode/\fR integration files (tasks, launch configurations). +.TP +.B clion +Generate \fB.idea/\fR integration files for CLion. +.SH TEST OPTIONS +.TP +.B \-\-init +Create \fBtests/dcr_test.h\fR in the current project. +.TP +.B \-\-debug +Build and run tests with debug profile (default). +.TP +.B \-\-release +Build and run tests with release profile. +.SH PROJECT CONFIGURATION +DCR uses \fBdcr.toml\fR for project configuration. Key settings include: +.TP +.B package.name +Project name (required). +.TP +.B package.version +Project version (default: \fB0.1.0\fR). +.TP +.B build.language +Programming language: \fBc\fR or \fBc++\fR (default: \fBc\fR). +.TP +.B build.standard +Language standard (e.g. \fBc11\fR, \fBc17\fR, \fBc++20\fR; default: \fBc11\fR). +.TP +.B build.compiler +Compiler to use: \fBclang\fR, \fBgcc\fR, \fBcl\fR, \fBclang-cl\fR (default: \fBclang\fR). +.TP +.B build.kind +Output type: \fBbin\fR, \fBlib\fR (static or dynamic), \fBstaticlib\fR, \fBsharedlib\fR (default: \fBbin\fR). +.SH FILES +.TP +.I dcr.toml +Project manifest file. +.TP +.I ~/.dcr/config.toml +User-level DCR configuration. +.TP +.I ~/.dcr/index.json +Local registry index. +.SH ENVIRONMENT +.TP +.B DCR_COMPILER +Override the compiler used for building. +.TP +.B DCR_CC +Alternative way to override the compiler. +.SH EXAMPLES +.TP +Create a new project: +.B dcr new hello +.TP +Initialize from current directory: +.B dcr init +.TP +Build with release profile: +.B dcr build \-\-release +.TP +Cross-compile for Windows: +.B dcr build \-\-target windows +.TP +Add a dependency: +.BR "dcr add curl git:https://github.com/curl/curl" . +.TP +Generate VS Code integration: +.B dcr gen vscode +.SH SEE ALSO +.IR https://dcr.dexoron.su ", " https://github.com/dexoron/dcr +.SH AUTHORS +Dexoron (Bezotechestvo Vladimir) diff --git a/packaging/aur/dcr-dev-git b/packaging/aur/dcr-dev-git new file mode 160000 index 0000000..93bdce8 --- /dev/null +++ b/packaging/aur/dcr-dev-git @@ -0,0 +1 @@ +Subproject commit 93bdce858b9ae6643efe473d09a01e41bc369c85 diff --git a/packaging/aur/dcr-git b/packaging/aur/dcr-git index 12038a6..2c5743a 160000 --- a/packaging/aur/dcr-git +++ b/packaging/aur/dcr-git @@ -1 +1 @@ -Subproject commit 12038a613e9c314c545cbb912590dc6b698b1dd0 +Subproject commit 2c5743a45685577d1cae563bdb749ff070a15759 diff --git a/packaging/aur/dcr/PKGBUILD b/packaging/aur/dcr/PKGBUILD index 467e392..f6ce0c9 100644 --- a/packaging/aur/dcr/PKGBUILD +++ b/packaging/aur/dcr/PKGBUILD @@ -27,4 +27,7 @@ package() { cd "$srcdir/$pkgname-$pkgver" install -Dm755 "target/release/dcr" "$pkgdir/usr/bin/dcr" install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" + for manpage in man/man1/*.1; do + install -Dm644 "$manpage" "$pkgdir/usr/share/man/man1/$(basename "$manpage")" + done } diff --git a/src/cli/add.rs b/src/cli/add.rs index f0ef5a2..2f9a3e9 100644 --- a/src/cli/add.rs +++ b/src/cli/add.rs @@ -19,7 +19,7 @@ use crate::core::config::Config; use crate::core::deps::register; use crate::utils::fs::find_project_root; use crate::utils::log::error; -use crate::utils::text::{BOLD_GREEN, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; use toml::Value; use toml::map::Map; @@ -34,6 +34,31 @@ pub struct AddArgs { } pub fn add(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc( + " dcr add [--branch ] [--tag ] [--rev ]", + BOLD_CYAN, + ); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Adds a dependency to the project."); + println!(); + printc("SOURCES:", BOLD_GREEN); + println!(" user/repo GitHub shorthand"); + println!(" github:user/repo GitHub repository"); + println!(" gitlab:user/repo GitLab repository"); + println!(" git:host.com/user/repo Generic git repository"); + println!(" path:./path/to/lib Local path dependency"); + println!(" Version from registry"); + println!(); + printc("OPTIONS:", BOLD_GREEN); + println!(" --branch Use a specific branch"); + println!(" --tag Use a specific tag"); + println!(" --rev Use a specific commit hash"); + return 0; + } + let add_args = match parse_add_args(args) { Ok(a) => a, Err(code) => return code, diff --git a/src/cli/build.rs b/src/cli/build.rs index 53d7691..5bf8223 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -29,7 +29,7 @@ use crate::utils::build::{ }; use crate::utils::fs::{check_dir, find_project_root, with_dir}; use crate::utils::log::error; -use crate::utils::text::{BOLD_GREEN, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; use glob::glob; use sha2::{Digest, Sha256}; use std::fs; @@ -42,6 +42,27 @@ static BUILD_INTERRUPTED: AtomicBool = AtomicBool::new(false); static SIGNAL_HANDLER: Once = Once::new(); pub fn build(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc( + " dcr build [--debug | --release] [--target ] [--force] [--clean] [--verbose]", + BOLD_CYAN, + ); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Compiles the project. Default profile is --debug."); + println!(); + printc("OPTIONS:", BOLD_GREEN); + println!(" --debug Build with debug profile (default)"); + println!(" --release Build with release profile"); + println!(" --target Cross-compile for the given target"); + println!(" --force Force a full rebuild"); + println!(" --clean Clean before building"); + println!(" --verbose Print detailed build output"); + println!(" --workspace Build a specific workspace member"); + return 0; + } + install_signal_handler(); BUILD_INTERRUPTED.store(false, Ordering::SeqCst); let start_dir = match std::env::current_dir() { diff --git a/src/cli/clean.rs b/src/cli/clean.rs index 73e82bc..931b1ed 100644 --- a/src/cli/clean.rs +++ b/src/cli/clean.rs @@ -21,12 +21,30 @@ use crate::core::workspace::parse_workspace; use crate::utils::build::parse_version_info; use crate::utils::fs::{check_dir, find_project_root, with_dir}; use crate::utils::log::{error, warn}; -use crate::utils::text::{BOLD_GREEN, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; use glob::glob; use std::fs; use std::path::Path; pub fn clean(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc( + " dcr clean [--debug | --release] [--target ] [--all]", + BOLD_CYAN, + ); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Removes build artifacts from the target directory."); + println!(); + printc("OPTIONS:", BOLD_GREEN); + println!(" --debug Clean debug artifacts (default)"); + println!(" --release Clean release artifacts"); + println!(" --target Clean artifacts for a specific target"); + println!(" --all Clean all workspace members"); + return 0; + } + let start_dir = match std::env::current_dir() { Ok(dir) => dir, Err(_) => { diff --git a/src/cli/flag_update.rs b/src/cli/flag_update.rs index 64c7b72..5d54dc9 100644 --- a/src/cli/flag_update.rs +++ b/src/cli/flag_update.rs @@ -16,6 +16,7 @@ // along with this program. If not, see . use crate::utils::log::{error, warn}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc}; use reqwest::blocking::Client; use serde::Deserialize; use std::fs; @@ -39,6 +40,15 @@ struct ReleaseAsset { } pub fn flag_update(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr --update", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Updates DCR to the latest version from GitHub Releases."); + return 0; + } + if !args.is_empty() { warn("Command does not support additional arguments"); return 1; diff --git a/src/cli/fmt.rs b/src/cli/fmt.rs index 6517fa8..551eae1 100644 --- a/src/cli/fmt.rs +++ b/src/cli/fmt.rs @@ -16,11 +16,21 @@ // along with this program. If not, see . use crate::utils::log::error; -use crate::utils::text::{BOLD_GREEN, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; use glob::glob; use std::process::Command; -pub fn fmt(_args: &[String]) -> i32 { +pub fn fmt(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr fmt", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Formats all C/C++ source files using clang-format."); + println!(" Scans src/ and tests/ directories recursively."); + return 0; + } + let patterns = [ "src/**/*.c", "src/**/*.cpp", diff --git a/src/cli/gen.rs b/src/cli/gen.rs index b35aaba..c879a9e 100644 --- a/src/cli/gen.rs +++ b/src/cli/gen.rs @@ -27,6 +27,7 @@ use crate::utils::build::{ }; use crate::utils::fs::find_project_root; use crate::utils::log::error; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc}; use std::path::{Path, PathBuf}; /// Like `deps::resolve_deps` but does NOT require lib directories to exist. @@ -186,13 +187,30 @@ pub struct ProjectInfo { pub fn r#gen(args: &[String]) -> i32 { let subcommand = match args.first() { + Some(s) if s == "--help" => { + printc("USAGE:", BOLD_GREEN); + printc(" dcr gen ", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Generates IDE and tooling integration files."); + println!(); + printc("SUBCOMMANDS:", BOLD_GREEN); + println!(" project-info Print project metadata as JSON"); + println!(" compile-commands Generate compile_commands.json"); + println!(" vscode Generate .vscode/ integration files"); + println!(" clion Generate .idea/ integration files"); + return 0; + } Some(s) => s.as_str(), None => { - eprintln!("Usage: dcr gen "); - eprintln!(" project-info Print project metadata as JSON"); - eprintln!(" compile-commands Generate compile_commands.json"); - eprintln!(" vscode Generate .vscode/ integration files"); - eprintln!(" clion Generate .idea/ integration files"); + printc("USAGE:", BOLD_GREEN); + printc(" dcr gen ", BOLD_CYAN); + println!(); + printc("SUBCOMMANDS:", BOLD_GREEN); + println!(" project-info Print project metadata as JSON"); + println!(" compile-commands Generate compile_commands.json"); + println!(" vscode Generate .vscode/ integration files"); + println!(" clion Generate .idea/ integration files"); return 1; } }; diff --git a/src/cli/init.rs b/src/cli/init.rs index 911fc65..28fa7d3 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . use crate::config::FILE_MAIN_C; -use crate::core::config::Config; +use crate::core::config::{Config, validate_package_name}; use crate::utils::fs::check_dir; use crate::utils::log::{error, warn}; use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; @@ -25,6 +25,16 @@ use std::io::Write; use toml::Value; pub fn init(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr init", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Initializes the current directory as a DCR project."); + println!(" The directory must be empty."); + return 0; + } + if !args.is_empty() { warn("Command does not support additional arguments"); return 1; @@ -41,6 +51,15 @@ pub fn init(args: &[String]) -> i32 { return 1; } + if let Err(e) = validate_package_name(&project_name) { + error(&format!( + "Invalid project name `{}`: {}", + colored(&project_name, BOLD_CYAN), + e + )); + return 1; + } + let cwd = std::env::current_dir() .map(|v| v.to_string_lossy().to_string()) .unwrap_or_else(|_| ".".to_string()); diff --git a/src/cli/new.rs b/src/cli/new.rs index b56bdff..661c610 100644 --- a/src/cli/new.rs +++ b/src/cli/new.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . use crate::config::FILE_MAIN_C; -use crate::core::config::Config; +use crate::core::config::{Config, validate_package_name}; use crate::utils::fs::check_dir; use crate::utils::log::{error, warn}; use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; @@ -25,6 +25,16 @@ use std::io::Write; use toml::Value; pub fn new(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr new ", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Creates a new C/C++ project with the given name."); + println!(" The name may only contain ASCII letters, digits, '_' and '-'."); + return 0; + } + let items = check_dir(None).unwrap_or_default(); if args.is_empty() { @@ -42,6 +52,15 @@ pub fn new(args: &[String]) -> i32 { colored(project_name, BOLD_CYAN) ); + if let Err(e) = validate_package_name(project_name) { + error(&format!( + "Invalid project name `{}`: {}", + colored(project_name, BOLD_CYAN), + e + )); + return 1; + } + if items.contains(project_name) { error(&format!( "Directory `{}` already exists\n", diff --git a/src/cli/run.rs b/src/cli/run.rs index cd6b858..70c2218 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -23,7 +23,7 @@ use crate::utils::build::{normalize_target_os, parse_version_info}; use crate::utils::fs::find_project_root; use crate::utils::fs::with_dir; use crate::utils::log::error; -use crate::utils::text::{BOLD_GREEN, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; use std::path::Path; use std::process::Command; @@ -56,6 +56,26 @@ fn get_run_cmd( } pub fn run(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc( + " dcr run [--debug | --release] [--target ] [--force] [--clean] [--verbose]", + BOLD_CYAN, + ); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Builds and runs the project. Only available for kind = \"bin\"."); + println!(); + printc("OPTIONS:", BOLD_GREEN); + println!(" --debug Run with debug profile (default)"); + println!(" --release Run with release profile"); + println!(" --target Cross-compile for the given target"); + println!(" --force Force a full rebuild"); + println!(" --clean Clean before building"); + println!(" --verbose Print detailed build output"); + return 0; + } + let start_dir = match std::env::current_dir() { Ok(dir) => dir, Err(_) => { diff --git a/src/cli/setup.rs b/src/cli/setup.rs index 62bf03c..5adcc4a 100644 --- a/src/cli/setup.rs +++ b/src/cli/setup.rs @@ -15,7 +15,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub fn setup(_args: &[String]) -> i32 { +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc}; + +pub fn setup(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr setup", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Sets up DCR registries. Downloads and indexes"); + println!(" package registries for dependency resolution."); + return 0; + } + println!("Setting up DCR registries..."); match crate::core::registry::RegistryManager::load() { Ok(manager) => { diff --git a/src/cli/test.rs b/src/cli/test.rs index b30d4b5..335ebb1 100644 --- a/src/cli/test.rs +++ b/src/cli/test.rs @@ -24,7 +24,7 @@ use crate::utils::build::{ }; use crate::utils::fs::{find_project_root, with_dir}; use crate::utils::log::error; -use crate::utils::text::{BOLD_GREEN, BOLD_RED, RESET, colored}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, BOLD_RED, RESET, colored, printc}; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; @@ -36,16 +36,16 @@ pub fn test(args: &[String]) -> i32 { let mut profile = "debug"; for arg in args { if arg == "--help" { - println!("USAGE:"); - println!(" dcr test [--init] [--debug | --release]"); + printc("USAGE:", BOLD_GREEN); + printc(" dcr test [--init] [--debug | --release]", BOLD_CYAN); println!(); - println!("ALIASES:"); + printc("ALIASES:", BOLD_GREEN); println!(" dcr tests"); println!(); - println!("DESCRIPTION:"); + printc("DESCRIPTION:", BOLD_GREEN); println!(" Runs project tests and prints a unified testsuite report."); println!(); - println!("OPTIONS:"); + printc("OPTIONS:", BOLD_GREEN); println!(" --init Create tests/dcr_test.h in current project"); println!(" --debug Build and run tests with debug profile (default)"); println!(" --release Build and run tests with release profile"); diff --git a/src/cli/tree.rs b/src/cli/tree.rs index 220db40..724bb16 100644 --- a/src/cli/tree.rs +++ b/src/cli/tree.rs @@ -17,12 +17,21 @@ use crate::core::config::Config; use crate::utils::log::error; -use crate::utils::text::{BOLD_CYAN, printc}; +use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc}; use std::collections::HashSet; use std::path::{Path, PathBuf}; use toml::Value; -pub fn tree(_args: &[String]) -> i32 { +pub fn tree(args: &[String]) -> i32 { + if args.first().is_some_and(|a| a == "--help") { + printc("USAGE:", BOLD_GREEN); + printc(" dcr tree", BOLD_CYAN); + println!(); + printc("DESCRIPTION:", BOLD_GREEN); + println!(" Displays the dependency tree of the current project."); + return 0; + } + let current_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); let config = match Config::open("dcr.toml") { Ok(c) => c, diff --git a/src/core/builder/common.rs b/src/core/builder/common.rs index 7527748..562cba2 100644 --- a/src/core/builder/common.rs +++ b/src/core/builder/common.rs @@ -329,17 +329,16 @@ pub fn needs_link(objects: &[String], output_path: &str) -> bool { fn parse_d_file(content: &str) -> Vec { let mut deps = Vec::new(); - let text = content.replace("\\\n", " ").replace("\\\r\n", " "); let mut target_end = 0; - let chars: Vec = text.chars().collect(); - for i in 0..chars.len() { - if chars[i] == ':' { + let bytes = content.as_bytes(); + for (i, &b) in bytes.iter().enumerate() { + if b == b':' { if i == 1 - && chars[0].is_ascii_alphabetic() - && i + 1 < chars.len() - && (chars[i + 1] == '\\' || chars[i + 1] == '/') + && bytes[0].is_ascii_alphabetic() + && i + 1 < bytes.len() + && (bytes[i + 1] == b'\\' || bytes[i + 1] == b'/') { - continue; // Windows drive letter + continue; } target_end = i + 1; break; @@ -347,17 +346,23 @@ fn parse_d_file(content: &str) -> Vec { } let deps_str = if target_end > 0 { - &text[target_end..] + &content[target_end..] } else { - &text + content }; let mut current_path = String::new(); let mut in_escape = false; + let mut chars = deps_str.chars().peekable(); - for c in deps_str.chars() { + while let Some(c) = chars.next() { if in_escape { - if c != '\n' && c != '\r' { + if c == '\n' { + } else if c == '\r' { + if chars.peek() == Some(&'\n') { + chars.next(); + } + } else { current_path.push(c); } in_escape = false; diff --git a/src/core/config.rs b/src/core/config.rs index f0fd405..25ee1f2 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -447,7 +447,7 @@ fn parse_typed_config(value: &Value) -> Result { value.clone().try_into().map_err(ConfigError::TomlDe) } -fn validate_package_name(name: &str) -> Result<(), ConfigError> { +pub fn validate_package_name(name: &str) -> Result<(), ConfigError> { let trimmed = name.trim(); if trimmed != name { return Err(ConfigError::Invalid(