89 lines
2.8 KiB
Rust
89 lines
2.8 KiB
Rust
//! `hivectl forge create-user <name>` — provision a Forgejo account via the
|
|
//! daemon (which owns the forge admin token + account-token persistence);
|
|
//! hivectl just resolves the password client-side and relays the request.
|
|
|
|
use std::io::{self, Write};
|
|
use std::path::Path;
|
|
|
|
use anyhow::Result;
|
|
use hive_host_sock::{HostRequest, ReconcileDirection};
|
|
|
|
use crate::cli::ReconcileFrom;
|
|
use crate::util::{daemon_request, resolve_password};
|
|
|
|
pub(crate) async fn forge_create_user(
|
|
socket: &Path,
|
|
name: &str,
|
|
password: Option<&str>,
|
|
password_stdin: bool,
|
|
) -> Result<()> {
|
|
// Resolve the password client-side (inline flag or stdin read); the
|
|
// daemon never touches this process's stdin. The is-present check, the
|
|
// agent-vs-operator branch, and token persistence now live in the
|
|
// daemon handler.
|
|
let password = resolve_password(password, password_stdin)?;
|
|
daemon_request(
|
|
socket,
|
|
hive_host_sock::HostRequest::ForgeCreateUser {
|
|
name: crate::util::parse_ident(name)?,
|
|
password,
|
|
},
|
|
"forge",
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// `hivectl forge reconcile-config <agent> [--from <forge|local>] [--verbose]`.
|
|
/// Always shows the divergence first (daemon computes it read-only), then
|
|
/// applies the chosen direction — from `--from` or an interactive prompt.
|
|
pub(crate) async fn forge_reconcile_config(
|
|
socket: &Path,
|
|
agent: &str,
|
|
from: Option<ReconcileFrom>,
|
|
verbose: bool,
|
|
) -> Result<()> {
|
|
daemon_request(
|
|
socket,
|
|
HostRequest::ReconcileConfigStatus {
|
|
agent: crate::util::parse_ident(agent)?,
|
|
verbose,
|
|
},
|
|
"forge",
|
|
)
|
|
.await?;
|
|
let direction = match from {
|
|
Some(f) => Some(f.into()),
|
|
None => prompt_direction()?,
|
|
};
|
|
let Some(direction) = direction else {
|
|
println!("forge: aborted — no changes made");
|
|
return Ok(());
|
|
};
|
|
daemon_request(
|
|
socket,
|
|
HostRequest::ReconcileConfigApply {
|
|
agent: crate::util::parse_ident(agent)?,
|
|
direction,
|
|
},
|
|
"forge",
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Prompt the operator for the reconcile direction after showing the diff.
|
|
/// Returns `None` to abort (empty / `q` / unrecognized input).
|
|
fn prompt_direction() -> Result<Option<ReconcileDirection>> {
|
|
print!("reconcile from [forge/local] (or q to abort): ");
|
|
io::stdout().flush()?;
|
|
let mut line = String::new();
|
|
io::stdin().read_line(&mut line)?;
|
|
match line.trim().to_ascii_lowercase().as_str() {
|
|
"forge" | "f" => Ok(Some(ReconcileDirection::Forge)),
|
|
"local" | "l" => Ok(Some(ReconcileDirection::Local)),
|
|
"" | "q" | "quit" => Ok(None),
|
|
other => {
|
|
println!("forge: unrecognized direction {other:?} — aborting");
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|