rust+nix: load static assets at runtime, drop build.rs (#555)
Cuts every `include_bytes!`/`include_str!` of a non-rust path in
the workspace over to runtime file loads from `$HIVE_ASSETS_DIR`
(the `hyperhive-assets` derivation introduced in the previous
commit). After this commit the rust derivation has no compile-time
dependency on `branding/*` or `hive-ag3nt/prompts/*` anymore.
Call-site flips:
- `hive-c0re/src/forge.rs::CORE_AVATAR_PNG` /
`CONFIG_ORG_AVATAR_PNG`: were `include_bytes!` of
`branding/hyperhive.png` and `$OUT_DIR/agent-configs.png`. Now
`ensure_core_avatar` / `ensure_config_org_avatar` `tokio::fs::read`
via `hive_sh4re::assets::{core_avatar_png, config_org_avatar_png}`
at startup. The `agent-configs.png` is now rendered by the
`hyperhive-assets` derivation's rsvg-convert step (was
`hive-c0re/build.rs` + librsvg on the rust derivation's
nativeBuildInputs — both gone in the next commit).
- `hive-ag3nt/src/prompt.rs::TEMPLATE`: `render` now takes the
template as an argument; `write_system_prompt` reads it once from
`$HIVE_ASSETS_DIR/prompts/system.md` before calling render. The
test module still `include_str!`s the production template so
`cargo test --workspace` doesn't need `HIVE_ASSETS_DIR` set —
this is the only remaining compile-time reference to the file
from the rust workspace, gated to `#[cfg(test)]`.
- `hive-ag3nt/src/turn.rs::CLAUDE_SETTINGS`: was `include_str!`'d
and written via `tokio::fs::write`; now `tokio::fs::copy` from
`$HIVE_ASSETS_DIR/prompts/claude-settings.json` into the
per-agent socket dir.
- `hive-ag3nt/src/web_ui.rs::DEFAULT_ICON`: was `include_str!`'d;
now read on-demand from `$HIVE_ASSETS_DIR/branding/hyperhive.svg`
inside `serve_icon`. Falls back to an empty body if missing so
the endpoint never panics on a misconfigured container (matches
the existing "per-agent icon.svg override" fallthrough).
`HIVE_ASSETS_DIR` wiring:
- Inside containers: `nix/templates/harness-base.nix`
`environment.variables` sets it to
`${pkgs.hyperhive-assets}/share/hyperhive` (resolved through
the default overlay applied in `mkContainer`). Verified by
building `agent-base-toplevel` and grepping the resulting
`/etc/set-environment`.
- Host-side: `nix/modules/hive-c0re.nix` adds an `assets` option
defaulting to `hyperhive.packages.${system}.assets`, threaded
in from the flake's nixosModules wiring, and sets the same env
var on the `hive-c0re` systemd unit so the daemon's
`forge::ensure_*_avatar` startup hooks find the PNGs.
`hive-c0re/build.rs` deleted entirely; `[package].build` removed
from `hive-c0re/Cargo.toml`; rsvg-convert dependency lives in the
assets derivation only.
Validated: `nix build .#default .#checks.x86_64-linux.clippy
.#agent-base-toplevel .#manager-toplevel --fallback` all succeed.
`/etc/set-environment` in the toplevel shows
`HIVE_ASSETS_DIR="/nix/store/.../hyperhive-assets-0.1.0/share/hyperhive"`.
This commit is contained in:
parent
246dd19390
commit
73684fb00a
11 changed files with 207 additions and 105 deletions
|
|
@ -2,13 +2,6 @@
|
|||
name = "hive-c0re"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
# Render branding/agent-configs.svg → $OUT_DIR/agent-configs.png at
|
||||
# compile time (#424). build.rs shells out to `rsvg-convert`
|
||||
# (librsvg, pulled in via flake.nix' crane nativeBuildInputs); the
|
||||
# baked PNG is included via include_bytes! from forge.rs so no
|
||||
# raster gets checked into git.
|
||||
build = "build.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
//! Render `branding/agent-configs.svg` → `$OUT_DIR/agent-configs.png`
|
||||
//! at compile time so the daemon can `include_bytes!` the PNG without
|
||||
//! checking the raster into git (#424 mara: "generate png on the fly
|
||||
//! or in build"). The SVG is the source of truth; the PNG is a build
|
||||
//! artifact.
|
||||
//!
|
||||
//! Uses `rsvg-convert` from PATH (librsvg, already available in
|
||||
//! nixpkgs and added to the crane derivation's `nativeBuildInputs`
|
||||
//! in `flake.nix`). For dev builds outside Nix, install librsvg via
|
||||
//! your system package manager (Debian/Ubuntu: `librsvg2-bin`,
|
||||
//! macOS: `brew install librsvg`).
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
const SVG_PATH: &str = "../branding/agent-configs.svg";
|
||||
const PNG_NAME: &str = "agent-configs.png";
|
||||
// 300×300 to match the existing branding/hyperhive.png, which the
|
||||
// Forgejo avatar endpoint accepts without resizing on upload.
|
||||
const PX: &str = "300";
|
||||
|
||||
fn main() {
|
||||
// Re-run the build script when either the SVG itself or this
|
||||
// script change. We deliberately don't watch every file in
|
||||
// `branding/` — only the one PNG we generate.
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed={SVG_PATH}");
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR set by cargo"));
|
||||
let png_path = out_dir.join(PNG_NAME);
|
||||
|
||||
let status = Command::new("rsvg-convert")
|
||||
.args(["--width", PX, "--height", PX, "-o"])
|
||||
.arg(&png_path)
|
||||
.arg(SVG_PATH)
|
||||
.status();
|
||||
|
||||
match status {
|
||||
Ok(s) if s.success() => {}
|
||||
Ok(s) => panic!("rsvg-convert exited with {s} rendering {SVG_PATH}"),
|
||||
Err(e) => panic!(
|
||||
"failed to invoke rsvg-convert: {e}\n\
|
||||
install librsvg (Debian/Ubuntu: librsvg2-bin, macOS: brew install librsvg, \
|
||||
NixOS: pkgs.librsvg). The Nix derivation already pulls it in via \
|
||||
flake.nix → craneLib.buildPackage.nativeBuildInputs.",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -41,20 +41,14 @@ const CORE_AVATAR_MARKER: &str = "/var/lib/hyperhive/forge-core-avatar-set";
|
|||
/// Sibling marker for the `agent-configs` org avatar (#424). Same one-
|
||||
/// shot semantics — delete to force the upload to re-run.
|
||||
const CONFIG_ORG_AVATAR_MARKER: &str = "/var/lib/hyperhive/forge-agent-configs-avatar-set";
|
||||
/// Hyperhive logo bytes, baked into the daemon. Uploaded once via the
|
||||
/// admin avatar API so the `core` Forgejo user shows the project mark
|
||||
/// next to commits in `agent-configs/*`, `core/meta`, etc. instead of
|
||||
/// the default hash identicon.
|
||||
const CORE_AVATAR_PNG: &[u8] = include_bytes!("../../branding/hyperhive.png");
|
||||
/// `agent-configs` org logo bytes (#424). Sibling visual to the main
|
||||
/// hyperhive mark — same dark base + outer ring + corner brackets,
|
||||
/// with a stacked-config-files glyph in the centre so the operator
|
||||
/// can distinguish the agent-configs namespace from the main
|
||||
/// `hyperhive` org at a glance. Source-of-truth is
|
||||
/// `branding/agent-configs.svg`; `hive-c0re/build.rs` renders it
|
||||
/// into `$OUT_DIR/agent-configs.png` at compile time via
|
||||
/// `rsvg-convert` so the raster never gets checked into git.
|
||||
const CONFIG_ORG_AVATAR_PNG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/agent-configs.png"));
|
||||
// Avatar PNGs are loaded at runtime from
|
||||
// `$HIVE_ASSETS_DIR/branding/{hyperhive,agent-configs}.png` via the
|
||||
// helpers in `hive_sh4re::assets` (#555 — was `include_bytes!` of an
|
||||
// in-source path and an OUT_DIR-rendered sibling, both of which
|
||||
// invalidated the crane src cache on any branding edit). The
|
||||
// `agent-configs.png` is rendered from its SVG during the
|
||||
// `hyperhive-assets` derivation's build (was `hive-c0re/build.rs`
|
||||
// + `rsvg-convert` on PATH; both gone now).
|
||||
/// Forgejo org grouping every agent's applied config repo. Core is a
|
||||
/// site admin and reads + writes every repo here; agents are NOT
|
||||
/// members and the repos are private, so no agent — not even the one
|
||||
|
|
@ -298,9 +292,13 @@ async fn ensure_core_avatar(token: &str) -> Result<()> {
|
|||
if marker.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
let png_path = hive_sh4re::assets::core_avatar_png();
|
||||
let png_bytes = tokio::fs::read(&png_path)
|
||||
.await
|
||||
.with_context(|| format!("read core avatar PNG from {}", png_path.display()))?;
|
||||
let body = format!(
|
||||
r#"{{"image":"{}"}}"#,
|
||||
base64::engine::general_purpose::STANDARD.encode(CORE_AVATAR_PNG),
|
||||
base64::engine::general_purpose::STANDARD.encode(&png_bytes),
|
||||
);
|
||||
let url = format!("{FORGE_HTTP}/api/v1/admin/users/core/avatar");
|
||||
let status = forge_http(reqwest::Method::POST, &url, token, &body).await?;
|
||||
|
|
@ -325,9 +323,13 @@ async fn ensure_config_org_avatar(token: &str) -> Result<()> {
|
|||
if marker.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
let png_path = hive_sh4re::assets::config_org_avatar_png();
|
||||
let png_bytes = tokio::fs::read(&png_path)
|
||||
.await
|
||||
.with_context(|| format!("read {CONFIG_ORG} avatar PNG from {}", png_path.display()))?;
|
||||
let body = format!(
|
||||
r#"{{"image":"{}"}}"#,
|
||||
base64::engine::general_purpose::STANDARD.encode(CONFIG_ORG_AVATAR_PNG),
|
||||
base64::engine::general_purpose::STANDARD.encode(&png_bytes),
|
||||
);
|
||||
let url = format!("{FORGE_HTTP}/api/v1/orgs/{CONFIG_ORG}/avatar");
|
||||
let status = forge_http(reqwest::Method::POST, &url, token, &body).await?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue