use std::io::Write;
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use clap::{Args, ValueEnum};
mod api;
mod cache;
mod server;
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
enum StartupOutputFormat {
Text,
Json,
}
#[derive(Debug, Args)]
pub(super) struct InspectArgs {
#[arg(long, default_value = ".")]
repo: PathBuf,
#[arg(long, default_value = "127.0.0.1")]
host: String,
#[arg(long, default_value_t = 7878)]
port: u16,
#[arg(long)]
open: bool,
#[arg(long)]
api_only: bool,
#[arg(long, value_enum, default_value_t = StartupOutputFormat::Text)]
format: StartupOutputFormat,
}
pub(super) fn run(
args: InspectArgs,
stdout: &mut dyn Write,
) -> Result<(), Box<dyn std::error::Error>> {
let span = tracing::info_span!("shore.inspect");
let _entered = span.enter();
tracing::debug!(command = "inspect", "command_start");
let ip: IpAddr = args
.host
.parse()
.map_err(|_| format!("invalid --host value: {}", args.host))?;
if !ip.is_loopback() {
return Err(format!("--host must be a loopback IP address: {ip}").into());
}
validate_flag_compatibility(args.api_only, args.open)?;
let addr = SocketAddr::new(ip, args.port);
server::serve(
addr,
args.repo,
args.open,
args.api_only,
args.format,
stdout,
)
}
fn validate_flag_compatibility(
api_only: bool,
open: bool,
) -> Result<(), Box<dyn std::error::Error>> {
if api_only && open {
return Err("--open cannot be used with --api-only".into());
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::validate_flag_compatibility;
#[test]
fn open_depends_only_on_the_served_surface() {
assert!(validate_flag_compatibility(false, false).is_ok());
assert!(validate_flag_compatibility(false, true).is_ok());
assert!(validate_flag_compatibility(true, false).is_ok());
assert!(validate_flag_compatibility(true, true).is_err());
}
}