use shep_client::{Client, ConnectError};
use shep_core::paths::ShepPaths;
use shep_core::protocol::DogSource;
use crate::commands::shep_toml::{ShepToml, ShepTomlError};
use crate::exit::ExitCode;
use crate::output::{DogActionRow, DogActionStatus, Streams, emit, write_outcome};
mod adopt;
mod barks;
mod disable;
mod enable;
mod remove;
mod vet;
#[cfg(all(test, unix))]
mod emit_dog_action_tests;
#[cfg(test)]
mod test_support;
pub use adopt::adopt;
pub use barks::barks;
pub use disable::disable;
pub use enable::enable;
pub use remove::rehome;
pub(crate) use remove::{Removal, remove_dog};
pub use vet::{DogSchema, warn_of_a_dog_a_restart_would_break};
pub(crate) use disable::disable_in_config;
pub(crate) use enable::{EnableRefusal, enable_in_config, join_with_and};
pub(crate) use vet::{VERSION_BUDGET, ask_schema, dog_env};
const NO_SHEPHERD_ENABLE_STATUS: DogActionStatus =
DogActionStatus::NoShepherd("will start with the next shepherd");
const NO_SHEPHERD_DISABLE_STATUS: DogActionStatus =
DogActionStatus::NoShepherd("not running; will not start with the next shepherd");
const DISABLED_STATUS: DogActionStatus = DogActionStatus::Acted("stopped");
fn emit_dog_action(
streams: &mut Streams<'_>,
verb: &str,
name: &str,
source: impl Into<Option<DogSource>>,
status: DogActionStatus,
) -> ExitCode {
write_outcome(emit(
&mut *streams.out,
streams.fmt,
verb,
DogActionRow::new(name, source, status),
streams.style,
))
}
pub(crate) fn fail_config(streams: &mut Streams<'_>, err: &ShepTomlError) -> ExitCode {
let code = match err {
ShepTomlError::Io { .. } => ExitCode::Failure,
ShepTomlError::Parse { .. } | ShepTomlError::WrongShape { .. } => ExitCode::InvalidConfig,
};
streams.fail(code, &err.to_string())
}
fn dog_source(cfg: &ShepToml, name: &str) -> DogSource {
adopted_source(cfg, name).unwrap_or(DogSource::BuiltIn)
}
fn adopted_source(cfg: &ShepToml, name: &str) -> Option<DogSource> {
cfg.adopted_dog_path(name).map(|path| DogSource::Adopted {
path: path.display().to_string(),
channel: cfg.asked_for_channel(name),
})
}
pub(crate) async fn connect_or_absent(
paths: &ShepPaths,
streams: &mut Streams<'_>,
) -> Result<Option<Client>, ExitCode> {
match Client::connect(&paths.socket).await {
Ok(client) => Ok(Some(client)),
Err(ConnectError::Connect { .. }) => Ok(None),
Err(err) => {
let code = ExitCode::from(&err);
Err(streams.fail(
code,
&format!(
"{err}; run `shep {}`",
crate::version_guard::VERSION_SKEW_REMEDY
),
))
}
}
}