12 Commits

Author SHA1 Message Date
3bd91e85f9 Merge pull request #31 from dexoron/dev
v0.8.4
2026-08-05 21:22:20 +08:00
9bf1346d1b Merge pull request #30 from dexoron/dev
v0.8.3
2026-08-03 21:32:18 +08:00
f29322a547 Merge pull request #29 from dexoron/dev
v0.8.2
2026-07-24 19:15:55 +08:00
689fea7465 Merge pull request #28 from dexoron/dev
v0.8.1
2026-07-21 18:12:56 +08:00
1dcc8e614a Merge pull request #25 from dexoron/dev
v0.8.0
2026-07-18 20:05:12 +08:00
a3f8444c20 Replace GitLab pipeline trigger with Cloudflare build 2026-07-05 18:24:47 +08:00
1f3fc62cb6 Add GitHub Actions workflow to trigger site rebuild 2026-07-05 18:16:45 +08:00
f8d8c95912 Rename сrowdin.yml to crowdin.yml (latin) 2026-07-05 17:26:00 +08:00
9e07f70c78 fix crowdin file name 2026-07-05 17:24:14 +08:00
0376eded3f add Crowdin 2026-07-05 17:21:33 +08:00
803d5891ce Merge pull request #21 from dexoron/dev
v0.7.4
2026-06-19 17:50:59 +08:00
97db82e4f8 Merge pull request #20 from dexoron/dev
v0.7.3
2026-06-15 22:36:12 +08:00
10 changed files with 22 additions and 198 deletions

View File

@@ -0,0 +1,14 @@
name: Trigger site rebuild
on:
push:
branches: [master]
paths:
- 'docs/**'
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Cloudflare Pages build
run: curl -sS -X POST "${{ secrets.CF_PAGES_DEPLOY_HOOK }}"

View File

@@ -1,31 +1,5 @@
# Changelog
## [v0.8.5] - 2026-08-08 "Фиксация версии dcr-version и предупреждения совместимости / Config Version Pinning & Compatibility Warnings"
### RU
**Добавлено:**
- **`package.dcr-version`** — опциональный pin версии CLI в `dcr.toml`.
`dcr new` / `dcr init` пишут текущую версию. При загрузке конфига:
- нет / пустой pin → warn «добавь dcr-version»;
- dcr старше pin → warn «обнови dcr»;
- dcr новее pin → warn «проверь changelog, подними pin»;
- равенство — тишина.
Команды не падают, только предупреждение (раз на path за процесс).
### EN
**Added:**
- **`package.dcr-version`** — optional CLI version pin in `dcr.toml`.
`dcr new` / `dcr init` write the current version. On config load:
- missing / empty pin → warn "add dcr-version";
- dcr older than pin → warn "update dcr";
- dcr newer than pin → warn "check changelog, update pin";
- equal → silent.
Commands do not fail, warning only (once per path per process).
## [0.8.4] - 2026-08-04 "Инфраструктура .dcr/ и интеграция с IDE / Internal .dcr/ Layout & IDE Integration"
### RU

2
Cargo.lock generated
View File

@@ -154,7 +154,7 @@ dependencies = [
[[package]]
name = "dcr"
version = "0.8.5"
version = "0.8.4"
dependencies = [
"ctrlc",
"fatfs",

View File

@@ -1,6 +1,6 @@
[package]
name = "dcr"
version = "0.8.5"
version = "0.8.4"
edition = "2024"
build = "build.rs"
description = "DCR is a utility for managing C/C++ projects in a Cargo-like style."

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /docs/**/*.mdx
translation: /docs-crowdin-export/%locale%/%original_path%/%original_file_name%.%file_extension%

View File

@@ -4,16 +4,6 @@ sidebar_label: Changelog
# Changelog
## 0.8.5 (2026-08-08)
- **`package.dcr-version`** — optional CLI version pin in `dcr.toml`.
`dcr new` / `dcr init` write the current version. On config load:
- missing / empty pin → warn "add dcr-version";
- dcr older than pin → warn "update dcr";
- dcr newer than pin → warn "check changelog, update pin";
- equal → silent.
Commands do not fail, warning only (once per path per process).
## 0.8.4 (2026-08-04)
**Added:**

View File

@@ -43,8 +43,7 @@ Main project configuration file. Located at the project root.
| Field | Required | Description |
|-------|----------|-------------|
| `name` | yes | Project name |
| `version` | yes | Semantic version of the **project** |
| `dcr-version` | no | Semver of the **dcr tool** this project targets. Written by `dcr new` / `dcr init` to the current tool version. |
| `version` | yes | Semantic version |
| `type` | no | `app`, `lib`, `none` (defaults to `"none"`) |
| `license` | no | SPDX license identifier |
| `author` | no | Author |
@@ -53,26 +52,11 @@ Main project configuration file. Located at the project root.
[package]
name = "my-app"
version = "0.1.0"
dcr-version = "0.8.4"
type = "app"
license = "MIT"
author = "John Doe"
```
### `package.dcr-version`
Optional pin of the DCR CLI the project was written for. On every `dcr.toml` load:
| Situation | Behaviour |
|-----------|-----------|
| Field missing / empty | Warning: add `dcr-version` (set by `dcr new` / `dcr init`) |
| Running dcr **older** than pin | Warning: upgrade dcr (`dcr --update`) |
| Running dcr **newer** than pin | Warning: review changelog, bump the pin when ready |
| Equal | Silent |
| Invalid semver | Warning once, field ignored |
Never fails the command — warnings only. Pre-release suffixes (`1.0.0-dev`) are ignored for comparison (`1.0.0-dev` ≡ `1.0.0`).
## [build]
...

View File

@@ -154,11 +154,6 @@ Project name (required).
.B package.version
Project version (default: \fB0.1.0\fR).
.TP
.B package.dcr\-version
Semver of the DCR tool this project targets. Set automatically by
\fBdcr new\fR / \fBdcr init\fR. Missing pin, or an installed \fBdcr\fR older/newer
than the pin, prints a warning (commands still run).
.TP
.B build.language
Programming language: \fBc\fR or \fBc++\fR (default: \fBc\fR).
.TP

View File

@@ -132,17 +132,11 @@ pub struct ArchiveLayout {
pub to: String,
}
/// Package metadata section (name, version, type, dcr-version).
/// Package metadata section (name, version, type).
#[derive(Debug, Clone, Deserialize)]
pub struct PackageConfig {
pub name: String,
pub version: String,
/// Minimum/target DCR tool version this project was authored for (`package.dcr-version`).
///
/// Compared against the running `dcr` binary (`CARGO_PKG_VERSION`) on config load.
/// Missing or empty means "no pin" — no warning is emitted.
#[serde(default, rename = "dcr-version")]
pub dcr_version: Option<String>,
#[serde(default, rename = "type")]
pub pkg_type: Option<String>,
}
@@ -264,7 +258,6 @@ impl Config {
doc,
};
cfg.validate()?;
cfg.warn_dcr_version_mismatch();
Ok(cfg)
}
@@ -283,7 +276,6 @@ impl Config {
doc,
};
cfg.validate()?;
cfg.warn_dcr_version_mismatch();
Ok(cfg)
}
@@ -299,68 +291,6 @@ impl Config {
self.typed.package.as_ref()
}
/// Warn once per config path about `package.dcr-version` vs this `dcr` binary.
///
/// - Missing/`""` pin → recommend adding `dcr-version`.
/// - Tool older than pin → project may use features this binary does not support.
/// - Tool newer than pin → project may rely on outdated defaults; consider bumping the pin.
///
/// Never fails the load; warnings only. Equal pin is silent.
fn warn_dcr_version_mismatch(&self) {
let Some(pkg) = self.typed.package.as_ref() else {
return;
};
let path_key = self
.path
.canonicalize()
.unwrap_or_else(|_| self.path.clone())
.to_string_lossy()
.into_owned();
if !dcr_version_warn_once(&path_key) {
return;
}
let tool = env!("CARGO_PKG_VERSION");
let required = pkg
.dcr_version
.as_deref()
.map(str::trim)
.filter(|s| !s.is_empty());
let Some(required) = required else {
crate::utils::log::warn(&format!(
"package.dcr-version is missing in {}. Add e.g. dcr-version = \"{tool}\" \
so collaborators know which dcr this project targets \
(written automatically by `dcr new` / `dcr init`).",
self.path.display()
));
return;
};
match crate::utils::build::compare_semver(tool, required) {
Some(std::cmp::Ordering::Less) => {
crate::utils::log::warn(&format!(
"this project requires dcr {required} (package.dcr-version), \
but you are running dcr {tool}. Some features may be missing or misbehave. \
Upgrade dcr (e.g. `dcr --update`) or lower package.dcr-version if intentional."
));
}
Some(std::cmp::Ordering::Greater) => {
crate::utils::log::warn(&format!(
"this project pins dcr {required} (package.dcr-version), \
but you are running newer dcr {tool}. Config/defaults may be outdated. \
Review the changelog and bump package.dcr-version when the project is verified."
));
}
Some(std::cmp::Ordering::Equal) => {}
None => {
crate::utils::log::warn(&format!(
"package.dcr-version = \"{required}\" is not a valid semver (expected X.Y.Z); ignoring"
));
}
}
}
#[allow(dead_code)]
/// Returns the build configuration if present.
pub fn build_config(&self) -> Option<&BuildConfig> {
@@ -835,13 +765,11 @@ fn default_toml_text() -> String {
.ok()
.and_then(|p| p.file_name().map(|v| v.to_string_lossy().to_string()))
.unwrap_or_else(|| "project".to_string());
let dcr_version = env!("CARGO_PKG_VERSION");
format!(
"[package]\n\
name = \"{name}\"\n\
version = \"{DEFAULT_VERSION}\"\n\
dcr-version = \"{dcr_version}\"\n\
type = \"none\"\n\
description = \"\"\n\
author = \"\"\n\
@@ -857,17 +785,6 @@ fn default_toml_text() -> String {
)
}
fn dcr_version_warn_once(path_key: &str) -> bool {
use std::collections::HashSet;
use std::sync::{Mutex, OnceLock};
static WARNED: OnceLock<Mutex<HashSet<String>>> = OnceLock::new();
let set = WARNED.get_or_init(|| Mutex::new(HashSet::new()));
let Ok(mut guard) = set.lock() else {
return true;
};
guard.insert(path_key.to_string())
}
fn set_doc_path(doc: &mut DocumentMut, path: &[&str], value: &Value) -> Result<(), ConfigError> {
let mut current = doc.as_table_mut();
for &key in &path[..path.len().saturating_sub(1)] {
@@ -1020,21 +937,11 @@ mod tests {
let dir = temp_dir("typed_config");
let path = write_toml_file(
&dir,
"[package]\nname = \"typed\"\nversion = \"1.2.3\"\ndcr-version = \"0.8.4\"\ntype = \"lib\"\n\n[build]\nlanguage = [\"c\", \"c++\"]\nstandard = \"c11\"\ncompiler = \"clang\"\nkind = \"staticlib\"\ncflags = [\"-Wall\"]\n\n[dependencies]\nfoo = \"1.0.0\"\n",
"[package]\nname = \"typed\"\nversion = \"1.2.3\"\ntype = \"lib\"\n\n[build]\nlanguage = [\"c\", \"c++\"]\nstandard = \"c11\"\ncompiler = \"clang\"\nkind = \"staticlib\"\ncflags = [\"-Wall\"]\n\n[dependencies]\nfoo = \"1.0.0\"\n",
);
let config = Config::open(&path.to_string_lossy()).unwrap();
assert_eq!(config.package().unwrap().name, "typed");
assert_eq!(config.typed().package.as_ref().unwrap().version, "1.2.3");
assert_eq!(
config
.typed()
.package
.as_ref()
.unwrap()
.dcr_version
.as_deref(),
Some("0.8.4")
);
assert_eq!(config.build_config().unwrap().compiler, "clang");
assert_eq!(config.build_config().unwrap().cflags, ["-Wall"]);
assert!(config.typed().dependencies.contains_key("foo"));

View File

@@ -31,39 +31,6 @@ pub struct VersionInfo {
pub suffix_dash: String,
}
/// Compares two semver-like strings (`X.Y.Z` with optional `-suffix`, suffix ignored).
///
/// Returns `None` if either side has no parseable numeric major component.
/// Ordering is tool-centric: `compare_semver(tool, required)` → `Less` means tool is older.
pub fn compare_semver(left: &str, right: &str) -> Option<std::cmp::Ordering> {
let l = semver_numeric_parts(left)?;
let r = semver_numeric_parts(right)?;
Some(l.cmp(&r))
}
fn semver_numeric_parts(version: &str) -> Option<(u64, u64, u64)> {
let base = version
.trim()
.split_once('-')
.map(|(h, _)| h)
.unwrap_or(version.trim());
if base.is_empty() {
return None;
}
let mut parts = base.split('.');
let major = parts.next()?.parse::<u64>().ok()?;
let minor = parts.next().unwrap_or("0").parse::<u64>().unwrap_or(0);
let patch = parts
.next()
.unwrap_or("0")
.chars()
.take_while(|c| c.is_ascii_digit())
.collect::<String>()
.parse::<u64>()
.unwrap_or(0);
Some((major, minor, patch))
}
/// Parses a version string into VersionInfo struct.
pub fn parse_version_info(version: &str) -> VersionInfo {
let mut full = version.trim().to_string();
@@ -794,16 +761,6 @@ mod tests {
assert_eq!(info.suffix_dash, "-beta");
}
#[test]
fn compare_semver_orders_and_ignores_prerelease() {
use std::cmp::Ordering;
assert_eq!(compare_semver("0.8.4", "0.8.4"), Some(Ordering::Equal));
assert_eq!(compare_semver("0.8.3", "0.8.4"), Some(Ordering::Less));
assert_eq!(compare_semver("0.9.0", "0.8.4"), Some(Ordering::Greater));
assert_eq!(compare_semver("1.0.0-dev", "1.0.0"), Some(Ordering::Equal));
assert_eq!(compare_semver("not-a-version", "0.1.0"), None);
}
/// Test for normalize_target_with_profile function.
#[test]
fn normalize_target_with_profile() {