relay-knowledge 1.1.10

Graph-database-based knowledge graph project.
Documentation
use crate::{
    application::{RelayKnowledgeService, RuntimeConfiguration, update_notice},
    project::PROJECT_NAME,
};

use super::{CliAction, CliCommand, CliError, OutputFormat, cli_render::serialize_line};

pub(super) fn render_version(format: OutputFormat) -> Result<String, CliError> {
    match format {
        OutputFormat::Text => Ok(format!("{} {}\n", PROJECT_NAME, env!("CARGO_PKG_VERSION"))),
        OutputFormat::Json => serialize_line(&serde_json::json!({
            "project_name": PROJECT_NAME,
            "version": env!("CARGO_PKG_VERSION"),
        })),
        OutputFormat::Markdown => Ok(format!("{} {}\n", PROJECT_NAME, env!("CARGO_PKG_VERSION"))),
        OutputFormat::StreamingJson => Err(CliError::UnsupportedVersionFormat(format)),
    }
}

pub(super) async fn run_version_check(
    service: &RelayKnowledgeService,
    format: OutputFormat,
) -> Result<String, CliError> {
    if format == OutputFormat::StreamingJson {
        return Err(CliError::UnsupportedVersionFormat(format));
    }
    let response = service.check_for_updates(true).await;
    match format {
        OutputFormat::Text | OutputFormat::Markdown => Ok(render_version_check_text(&response)),
        OutputFormat::Json => serialize_line(&response),
        OutputFormat::StreamingJson => unreachable!("streaming-json was rejected above"),
    }
}

pub(super) async fn update_notice_for_process(
    command: &CliCommand,
    interactive_text_output: bool,
) -> Option<String> {
    if !interactive_text_output || !should_check_after_command(command) {
        return None;
    }
    let runtime = RuntimeConfiguration::from_process_environment()
        .await
        .ok()?;
    update_notice(&runtime.paths, &runtime.network, &runtime.updates).await
}

fn should_check_after_command(command: &CliCommand) -> bool {
    matches!(command.format, OutputFormat::Text | OutputFormat::Markdown)
        && !matches!(
            command.action,
            CliAction::Help { .. }
                | CliAction::Version
                | CliAction::VersionCheck
                | CliAction::ServiceRun { .. }
        )
}

fn render_version_check_text(response: &crate::application::VersionCheckResponse) -> String {
    match (
        response.update_available,
        response.latest_version.as_deref(),
        response.source.as_deref(),
    ) {
        (true, Some(latest), Some(source)) => format!(
            "{} update available: current={} latest={} source={}\n",
            response.project_name, response.current_version, latest, source
        ),
        (true, Some(latest), None) => format!(
            "{} update available: current={} latest={}\n",
            response.project_name, response.current_version, latest
        ),
        (false, Some(latest), Some(source)) => format!(
            "{} is current: current={} latest={} source={}\n",
            response.project_name, response.current_version, latest, source
        ),
        _ => format!(
            "{} latest version unavailable: current={} diagnostics={}\n",
            response.project_name,
            response.current_version,
            response.diagnostics.len()
        ),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn version_notice_skips_machine_readable_and_version_commands() {
        assert!(!should_check_after_command(&CliCommand {
            action: CliAction::Version,
            format: OutputFormat::Text,
            remote_base_url: None,
            help: false,
        }));
        assert!(!should_check_after_command(&CliCommand {
            action: CliAction::Status,
            format: OutputFormat::Json,
            remote_base_url: None,
            help: false,
        }));
        assert!(should_check_after_command(&CliCommand {
            action: CliAction::Status,
            format: OutputFormat::Text,
            remote_base_url: None,
            help: false,
        }));
    }
}