generated from eblume/project-template
Pre-v1 cleanup: dependency-refresh sweep + drop fs4 + remove dead build hook #2
8 changed files with 2385 additions and 456 deletions
|
|
@ -20,9 +20,10 @@ class HephaestusCi:
|
||||||
dag.container()
|
dag.container()
|
||||||
.from_("rust:1-bookworm")
|
.from_("rust:1-bookworm")
|
||||||
.with_exec(["rustup", "component", "add", "clippy", "rustfmt"])
|
.with_exec(["rustup", "component", "add", "clippy", "rustfmt"])
|
||||||
# Cap parallel rustc — unbounded (= ncpu) spikes memory on heavy
|
# Serialize compilation (jobs=1) — even 4 parallel rustc invocations
|
||||||
# crates and OOMs the build engine on a many-core runner.
|
# spike memory on heavy crates and OOM-kill the DinD build engine.
|
||||||
.with_env_variable("CARGO_BUILD_JOBS", "4")
|
# Slower, but the runner survives; revisit if the host gets more RAM.
|
||||||
|
.with_env_variable("CARGO_BUILD_JOBS", "1")
|
||||||
.with_mounted_cache(
|
.with_mounted_cache(
|
||||||
"/usr/local/cargo/registry",
|
"/usr/local/cargo/registry",
|
||||||
dag.cache_volume("heph-cargo-registry"),
|
dag.cache_volume("heph-cargo-registry"),
|
||||||
|
|
@ -83,7 +84,7 @@ class HephaestusCi:
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
.with_env_variable("PATH", "/opt/nvim/bin:$PATH", expand=True)
|
.with_env_variable("PATH", "/opt/nvim/bin:$PATH", expand=True)
|
||||||
.with_env_variable("CARGO_BUILD_JOBS", "4")
|
.with_env_variable("CARGO_BUILD_JOBS", "1")
|
||||||
.with_directory("/workspace", src)
|
.with_directory("/workspace", src)
|
||||||
.with_workdir("/workspace")
|
.with_workdir("/workspace")
|
||||||
.with_mounted_cache("/workspace/target", dag.cache_volume("heph-target"))
|
.with_mounted_cache("/workspace/target", dag.cache_volume("heph-target"))
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Project build hook (tech-spec §9): run the Rust workspace checks in CI.
|
|
||||||
#
|
|
||||||
# Invoked by .forgejo/workflows/build.yaml after the generic `prek` pass.
|
|
||||||
# Bootstraps a minimal Rust toolchain via rustup when the runner image lacks
|
|
||||||
# one, so the suite runs without a bespoke CI image. The headless nvim e2e
|
|
||||||
# suite is added here once heph.nvim exists.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if ! command -v cargo >/dev/null 2>&1; then
|
|
||||||
echo "cargo not found; bootstrapping Rust toolchain via rustup..."
|
|
||||||
export RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}"
|
|
||||||
export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}"
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
|
||||||
| sh -s -- -y --profile minimal
|
|
||||||
# shellcheck disable=SC1091
|
|
||||||
. "$CARGO_HOME/env"
|
|
||||||
rustup component add clippy rustfmt
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "== cargo fmt --check =="
|
|
||||||
cargo fmt --all --check
|
|
||||||
|
|
||||||
echo "== cargo clippy =="
|
|
||||||
cargo clippy --all-targets --all-features -- -D warnings
|
|
||||||
|
|
||||||
echo "== cargo test =="
|
|
||||||
cargo test --all
|
|
||||||
2719
Cargo.lock
generated
2719
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
19
Cargo.toml
19
Cargo.toml
|
|
@ -14,16 +14,16 @@ version = "0.0.0"
|
||||||
license = "LicenseRef-Proprietary"
|
license = "LicenseRef-Proprietary"
|
||||||
publish = false
|
publish = false
|
||||||
authors = ["Erich Blume <blume.erich@gmail.com>"]
|
authors = ["Erich Blume <blume.erich@gmail.com>"]
|
||||||
rust-version = "1.85"
|
rust-version = "1.89"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
rusqlite = { version = "0.32", features = ["bundled"] }
|
rusqlite = { version = "0.40", features = ["bundled"] }
|
||||||
ulid = "1"
|
ulid = "1"
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
pulldown-cmark = { version = "0.13", default-features = false }
|
pulldown-cmark = { version = "0.13", default-features = false }
|
||||||
rrule = "0.13"
|
rrule = "0.14"
|
||||||
yrs = "0.26"
|
yrs = "0.27"
|
||||||
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
@ -38,16 +38,11 @@ tokio = { version = "1", features = [
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
ratatui = "0.29"
|
ratatui = "0.30"
|
||||||
fs4 = "0.12"
|
|
||||||
axum = "0.8"
|
axum = "0.8"
|
||||||
jsonwebtoken = { version = "10", features = ["rust_crypto"] }
|
jsonwebtoken = { version = "10", features = ["rust_crypto"] }
|
||||||
keyring = { version = "3", features = [
|
keyring = { version = "4" }
|
||||||
"apple-native",
|
keyring-core = "1"
|
||||||
"sync-secret-service",
|
|
||||||
"crypto-rust",
|
|
||||||
"vendored",
|
|
||||||
] }
|
|
||||||
ureq = { version = "3", features = ["json"] }
|
ureq = { version = "3", features = ["json"] }
|
||||||
reqwest = { version = "0.13", default-features = false, features = [
|
reqwest = { version = "0.13", default-features = false, features = [
|
||||||
"json",
|
"json",
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ thiserror.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
fs4.workspace = true
|
|
||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
jsonwebtoken.workspace = true
|
jsonwebtoken.workspace = true
|
||||||
keyring.workspace = true
|
keyring.workspace = true
|
||||||
|
keyring-core.workspace = true
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
ureq.workspace = true
|
ureq.workspace = true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ use std::fs::{File, OpenOptions};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use fs4::fs_std::FileExt;
|
|
||||||
|
|
||||||
/// Holds the exclusive lock for as long as it lives; drops release it.
|
/// Holds the exclusive lock for as long as it lives; drops release it.
|
||||||
pub struct LockGuard {
|
pub struct LockGuard {
|
||||||
|
|
@ -35,9 +34,10 @@ impl LockGuard {
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.with_context(|| format!("opening lock file {}", path.display()))?;
|
.with_context(|| format!("opening lock file {}", path.display()))?;
|
||||||
|
|
||||||
// A failure here (typically `WouldBlock`) means another process holds
|
// `File::try_lock` (std, stable since Rust 1.89) takes the advisory
|
||||||
// the lock.
|
// lock without blocking. A failure here (typically `WouldBlock`) means
|
||||||
file.try_lock_exclusive().map_err(|e| {
|
// another process holds it.
|
||||||
|
file.try_lock().map_err(|e| {
|
||||||
anyhow::anyhow!(
|
anyhow::anyhow!(
|
||||||
"store {} is already locked by another hephd process: {e}",
|
"store {} is already locked by another hephd process: {e}",
|
||||||
db_path.display()
|
db_path.display()
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,19 @@ impl KeyringTokenStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry(&self) -> Result<keyring::Entry, AuthError> {
|
fn entry(&self) -> Result<keyring_core::Entry, AuthError> {
|
||||||
keyring::Entry::new(&self.service, &self.account)
|
// keyring 4 splits the cross-platform `Entry`/`Error` types into
|
||||||
|
// `keyring_core` and requires a credential store to be registered
|
||||||
|
// before any entry is built. Register the OS-native store once,
|
||||||
|
// lazily, on first use (idempotent across both surfaces).
|
||||||
|
static NATIVE_STORE: std::sync::Once = std::sync::Once::new();
|
||||||
|
NATIVE_STORE.call_once(|| {
|
||||||
|
// `not_keyutils = true`: on Linux prefer the Secret Service over
|
||||||
|
// the kernel keyutils store, which is wiped on logout/reboot and
|
||||||
|
// would silently drop a persisted login token.
|
||||||
|
let _ = keyring::use_native_store(true);
|
||||||
|
});
|
||||||
|
keyring_core::Entry::new(&self.service, &self.account)
|
||||||
.map_err(|e| AuthError::Provider(e.to_string()))
|
.map_err(|e| AuthError::Provider(e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +119,7 @@ impl TokenStore for KeyringTokenStore {
|
||||||
fn clear(&self) -> Result<(), AuthError> {
|
fn clear(&self) -> Result<(), AuthError> {
|
||||||
match self.entry()?.delete_credential() {
|
match self.entry()?.delete_credential() {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(keyring::Error::NoEntry) => Ok(()),
|
Err(keyring_core::Error::NoEntry) => Ok(()),
|
||||||
Err(e) => Err(AuthError::Provider(e.to_string())),
|
Err(e) => Err(AuthError::Provider(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
docs/changelog.d/pre-v1-cleanup.infra.md
Normal file
1
docs/changelog.d/pre-v1-cleanup.infra.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Pre-v1 dependency-refresh sweep: bumped all external crates to latest stable — `keyring` 3→4 (the new `keyring_core` split + register-the-native-store model), `rusqlite` 0.32→0.40, `ratatui` 0.29→0.30, `rrule` 0.13→0.14, `yrs` 0.26→0.27, plus semver-compatible updates across the rest. Dropped the `fs4` dependency in favor of `std::fs::File::try_lock` (stable since Rust 1.89), raising the workspace MSRV to 1.89. Removed the orphaned `.forgejo/scripts/build` hook (CI calls Dagger directly). Full suite green: 228 Rust tests + 25 heph.nvim headless e2e specs, `clippy -D warnings` + `fmt` clean.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue