7 Commits

17 changed files with 141 additions and 60 deletions

View File

@@ -41,10 +41,6 @@ on:
description: "Publish to crates.io"
type: boolean
default: false
run_snap:
description: "Publish to Snap Store (dcrup)"
type: boolean
default: false
run_brew:
description: "Update Homebrew tap"
type: boolean
@@ -83,24 +79,40 @@ jobs:
notes:
needs: setup
runs-on: ubuntu-latest
outputs:
release_name: ${{ steps.extract.outputs.release_name }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.setup.outputs.tag }}
- name: Prepare Release Notes
id: extract
shell: bash
run: |
set -euo pipefail
tag="${{ needs.setup.outputs.version }}"
notes_file=".github/release-notes.md"
if grep -q "^## \\[${tag}\\]" CHANGELOG.md; then
# Extract release name from header: ## [0.7.1] - 2026-06-02 "Title"
release_name=$(awk -v ver="$tag" '
$0 ~ "^## \\[" ver "\\]" {
match($0, /"([^"]+)"/, arr)
if (arr[1] != "") {
print "v" ver " - " arr[1]
} else {
print "v" ver
}
}
' CHANGELOG.md)
echo "release_name=${release_name}" >> "$GITHUB_OUTPUT"
awk -v ver="$tag" '
$0 ~ "^## \\[" ver "\\]" {found=1; next}
found && $0 ~ "^## \\[" {exit}
found {print}
' CHANGELOG.md | sed -e '${/^$/d;}' > "$notes_file"
else
echo "release_name=v${tag}" >> "$GITHUB_OUTPUT"
echo "No CHANGELOG section for $tag." > "$notes_file"
git log -1 --pretty=format:"%s%n%n%b" >> "$notes_file"
fi
@@ -126,6 +138,7 @@ jobs:
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.setup.outputs.tag }}
name: ${{ needs.notes.outputs.release_name }}
body_path: .github/release-notes.md
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
@@ -651,6 +664,8 @@ jobs:
done
}
PKG
cat > packages/aur/dcr/.SRCINFO <<SRC
pkgbase = dcr
pkgdesc = Cargo-like utility to manage C/C++ projects
pkgver = ${PKGVER_CLEAN}
@@ -1229,34 +1244,11 @@ jobs:
git commit -m "dcr ${{ needs.setup.outputs.version }}"
git push
# ── Snap Store (dcrup) ─────────────────────────────────────────────────────
publish-snap:
if: |
(github.event_name == 'push' && needs.setup.outputs.prerelease == 'false') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_snap == 'true')
needs: [setup, build-linux-packages]
runs-on: ubuntu-latest
steps:
- name: Download Built Packages
uses: actions/download-artifact@v4
with:
name: snap-package
path: dist-packages
- name: Resolve Snap File
id: snap-file
run: |
snap_file=$(ls dist-packages/*.snap 2>/dev/null | head -1)
if [ -z "$snap_file" ]; then
echo "No .snap file found in dist-packages/"
exit 1
fi
echo "snap=$snap_file" >> "$GITHUB_OUTPUT"
- name: Publish to Snap Store
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with:
snap: ${{ steps.snap-file.outputs.snap }}
release: stable
# ── Snap Store (dcrup) — temporarily disabled ────────────────────────────
# Classic confinement was denied for this project (too new).
# Snap artifact is still built and attached to the release via
# publish-dexoron-packages. Users can install manually:
# sudo snap install --classic --dangerous dcrup_*.snap
#
# publish-snap:
# if: ...

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ target/
sandbox/**
.idea/
.vscode/
.cargo/
.env
personal/

View File

@@ -12,7 +12,7 @@
- Оптимизация сборки: `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.
- Пакеты AUR (`dcr-dev`, `dcr-dev-bin`) и сборка Snap в CI.
**Изменено:**
- Функция `validate_package_name` стала публичной.
@@ -20,6 +20,15 @@
- Инструкция в README изменена с `| bash` на `| sh` для POSIX.
- Отключена архитектура Windows 32-bit (GNU) из-за проблем со сборкой.
**Исправлено:**
- **`dcr new <invalid-name>` создаёт директорию, затем падает** — валидация теперь происходит до операций с файлами.
- **`dcr init` создаёт dcr.toml, затем падает при невалидном имени директории** — то же исправление.
- **Man-страницы отсутствовали после установки** — теперь устанавливаются через скрипты установки, пакетные менеджеры и Homebrew.
- **Ложное срабатывание на букву диска в Windows** — в парсинге файлов зависимостей.
- **CRLF `\r\n` ломает парсер зависимостей** — теперь обрабатываются смешанные окончания строк.
- **Новая строка после обратного слеша не поглощалась** — в обработке escape-последовательностей `parse_d_file`.
### EN
**Added:**
@@ -30,7 +39,7 @@
- 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.
- AUR packages (`dcr-dev`, `dcr-dev-bin`) and Snap build in CI.
**Changed:**
- `validate_package_name` made public and callable from CLI commands directly.

View File

@@ -69,16 +69,32 @@ toml = "1.0.3"
serde_json = "1"
ctrlc = "3"
[features]
default = ["vendored"]
vendored = [
"git2/vendored-libgit2",
"git2/vendored-openssl",
"openssl/vendored",
]
[target.'cfg(not(windows))'.dependencies]
git2 = { version = "0.20.4", features = ["vendored-libgit2", "vendored-openssl"] }
openssl = { version = "0.10", features = ["vendored"] }
git2 = "0.20.4"
openssl = "0.10"
[target.'cfg(windows)'.dependencies]
git2 = { version = "0.20.4", features = ["vendored-libgit2"] }
git2 = "0.20.4"
[profile.release]
opt-level = "z"
lto = true
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

View File

@@ -11,7 +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)
<!-- Snap badge removed — classic confinement was denied for this project. -->
<br/>
[![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)
@@ -127,8 +127,11 @@ curl -fsSL https://dcr.dexoron.su/install_bsd.sh | sh
<td><b>Snap (Linux)</b></td>
<td>
> Snap Store publishing temporarily disabled — see [#51671](https://forum.snapcraft.io/t/classic-confinement-request-for-dcrup/51671).
> Download the `.snap` from [GitHub Releases](https://github.com/dexoron/dcr/releases/latest) and install manually:
```sh
sudo snap install dcrup
sudo snap install --classic --dangerous dcrup_*.snap
```
</td>
@@ -226,7 +229,7 @@ other in [docs/](docs/), `dcr --help` and `dcr <command> --help`
| Linux (Musl) | ✅ | ✅ | ✅ | ✅ | 🚧 |
| macOS | ✅ | ✅ | ❌ | ❌ | ❌ |
| Windows (MSVC) | ✅ | ✅ | ❌ | ✅ | ❌ |
| Windows (MinGW) | ✅ | 🚧 | ❌ | ✅ | ❌ |
| Windows (MinGW) | ✅ | 🚧 | ❌ | ❌ | ❌ |
| FreeBSD | ✅ | 🚧 | ❌ | ❌ | ❌ |
| OpenBSD | ✅ | 🚧 | ❌ | ❌ | ❌ |
| NetBSD | ✅ | 🚧 | ❌ | ❌ | ❌ |
@@ -271,6 +274,7 @@ cargo test
<div align="center">
GPL-3.0 — see [LICENSE](LICENSE)<br/>
DCR is a build tool, not a library. The GPL applies only to DCR's own source code, not to projects built with it.<br/>
Made with ❤️ by [Dexoron](https://github.com/dexoron) and contributors.
</div>

View File

@@ -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

46
docs/license.mdx Normal file
View File

@@ -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/).

View File

@@ -34,9 +34,12 @@ pub struct AddArgs {
}
pub fn add(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr add <name> <source> [--branch <b>] [--tag <t>] [--rev <r>]", BOLD_CYAN);
printc(
" dcr add <name> <source> [--branch <b>] [--tag <t>] [--rev <r>]",
BOLD_CYAN,
);
println!();
printc("DESCRIPTION:", BOLD_GREEN);
println!(" Adds a dependency to the project.");

View File

@@ -42,9 +42,12 @@ static BUILD_INTERRUPTED: AtomicBool = AtomicBool::new(false);
static SIGNAL_HANDLER: Once = Once::new();
pub fn build(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr build [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose]", BOLD_CYAN);
printc(
" dcr build [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose]",
BOLD_CYAN,
);
println!();
printc("DESCRIPTION:", BOLD_GREEN);
println!(" Compiles the project. Default profile is --debug.");

View File

@@ -27,9 +27,12 @@ use std::fs;
use std::path::Path;
pub fn clean(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr clean [--debug | --release] [--target <triple>] [--all]", BOLD_CYAN);
printc(
" dcr clean [--debug | --release] [--target <triple>] [--all]",
BOLD_CYAN,
);
println!();
printc("DESCRIPTION:", BOLD_GREEN);
println!(" Removes build artifacts from the target directory.");

View File

@@ -40,7 +40,7 @@ struct ReleaseAsset {
}
pub fn flag_update(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr --update", BOLD_CYAN);
println!();

View File

@@ -21,7 +21,7 @@ use glob::glob;
use std::process::Command;
pub fn fmt(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr fmt", BOLD_CYAN);
println!();

View File

@@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::FILE_MAIN_C;
use crate::core::config::{validate_package_name, 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,7 +25,7 @@ use std::io::Write;
use toml::Value;
pub fn init(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr init", BOLD_CYAN);
println!();

View File

@@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::FILE_MAIN_C;
use crate::core::config::{validate_package_name, 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,7 +25,7 @@ use std::io::Write;
use toml::Value;
pub fn new(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr new <name>", BOLD_CYAN);
println!();

View File

@@ -56,9 +56,12 @@ fn get_run_cmd(
}
pub fn run(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr run [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose]", BOLD_CYAN);
printc(
" dcr run [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose]",
BOLD_CYAN,
);
println!();
printc("DESCRIPTION:", BOLD_GREEN);
println!(" Builds and runs the project. Only available for kind = \"bin\".");

View File

@@ -18,7 +18,7 @@
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, printc};
pub fn setup(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr setup", BOLD_CYAN);
println!();

View File

@@ -23,7 +23,7 @@ use std::path::{Path, PathBuf};
use toml::Value;
pub fn tree(args: &[String]) -> i32 {
if args.first().map_or(false, |a| a == "--help") {
if args.first().is_some_and(|a| a == "--help") {
printc("USAGE:", BOLD_GREEN);
printc(" dcr tree", BOLD_CYAN);
println!();