build: embed exact/fresh git hash (+ -dirty for uncommitted code)

build.rs now re-runs when the commit changes (cargo:rerun-if-changed on
.git/HEAD + the branch ref) so GIT_HASH never goes stale, and appends -dirty
when tracked code (frontend, src-tauri/src, build.rs) is uncommitted. Lets a
distributed APK be pinned to an exact source commit for regression tracking.
README documents versionName 0.1.NNN + hash traceability. Decision at b4fdc824144.
This commit is contained in:
4aiman 2026-08-20 19:55:08 +03:00
commit 3f2100cdd1
2 changed files with 36 additions and 1 deletions

View file

@ -40,6 +40,16 @@
./build.sh -d -i -u android # debug + install + upload
```
## Версия и трассируемость сборки
Чтобы по розданному APK однозначно находить, где регресс/косяк:
- **`versionName 0.1.NNN`** — монотонный `BUILD_NUMBER` (инкремент на каждой сборке в `build.sh`), первичный уникальный идентификатор билда. Виден в Настройках и в свойствах пакета Android.
- **git-хэш коммита исходников** зашивается в бинарник при компиляции (`src-tauri/build.rs` → `GIT_HASH`) и показывается в Настройках: `v0.1.NNN (<hash>) <дата>`. Хэш всегда свежий (`build.rs` перезапускается при смене коммита через `cargo:rerun-if-changed`), с суффиксом **`-dirty`**, если отслеживаемый код (`frontend/`, `src-tauri/src/`) не закоммичен.
- Хэш = HEAD на момент компиляции. `build.sh` бампает версию, но НЕ коммитит, поэтому в dev-сборке хэш = последний коммит, а код может быть впереди (тогда `-dirty`). **Для раздачи: закоммить код перед release-сборкой** — тогда хэш чистый и APK точно соответствует коммиту.
Решение о точном встроенном хэше принято на коммите `b4fdc824144` (ветка master, 2026-08-16).
## Структура
Подробно: [PROJECT_MAP.md](PROJECT_MAP.md)

View file

@ -1,13 +1,38 @@
use std::process::Command;
fn main() {
// Re-run this script whenever the checked-out commit changes, so the embedded
// git hash never goes stale: HEAD changes on checkout; the branch ref file
// changes on commit. Without this, a rebuild after a commit (with no source
// change) could keep a cached, wrong hash.
println!("cargo:rerun-if-changed=../.git/HEAD");
if let Ok(head) = std::fs::read_to_string("../.git/HEAD") {
if let Some(r) = head.strip_prefix("ref: ") {
println!("cargo:rerun-if-changed=../.git/{}", r.trim());
}
}
// Pass git hash and build info to Rust via env vars
let git_hash = Command::new("git")
let hash = Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
.unwrap_or_else(|_| "unknown".into());
// "-dirty" ONLY for uncommitted TRACKED code (frontend + Rust src). Version files
// are bumped on every build, binaries/ churn, and there are many untracked files
// in the tree — none of those mean the built code differs from HEAD, so exclude
// them (-uno + pathspec). This flags "the APK's code isn't fully committed".
let dirty = Command::new("git")
.args([
"-C", "..", "status", "--porcelain", "-uno", "--",
"frontend", "src-tauri/src", "src-tauri/build.rs",
])
.output()
.map(|o| !o.stdout.is_empty())
.unwrap_or(false);
let git_hash = if dirty { format!("{}-dirty", hash) } else { hash };
let build_date = chrono_free_date();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);