macro_rules! schema_as {
($ty:ident, $written:ident) => {
impl schemars::JsonSchema for $ty {
fn schema_name() -> std::borrow::Cow<'static, str> {
stringify!($ty).into()
}
fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
<$written as schemars::JsonSchema>::json_schema(g)
}
}
};
}
mod accounts;
mod files;
mod input;
mod services;
mod software;
mod words;
pub use accounts::{GroupStep, Password, UserStep};
pub use files::{Copy, FileState, FileStep, Template};
pub use services::{Argv, CommandStep, Firewall, FirewallPort, Guard, Invocation, Service};
pub use software::{Package, Repository, RepositoryKey};
pub use words::{AbsPath, AptWord, GroupName, HttpsUrl, PackageName, PackageVersion, ProjectPath, RepositoryName, Sha256, UnitName, UserName};
use serde::Deserialize;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(try_from = "input::StepSchema")]
#[non_exhaustive]
pub enum Step {
Run {
script: ProjectPath,
creates: Option<AbsPath>,
},
Copy(Copy),
Packages(Vec<Package>),
Reboot,
Playbook(ProjectPath),
Repository(Repository),
File(FileStep),
Template(Template),
User(UserStep),
Group(GroupStep),
Service(Service),
Command(CommandStep),
Firewall(Firewall),
}
impl Step {
#[must_use]
pub fn kind(&self) -> &'static str {
match self {
Step::Run { .. } => "run",
Step::Copy(_) => "copy",
Step::Packages(_) => "packages",
Step::Reboot => "reboot",
Step::Playbook(_) => "playbook",
Step::Repository(_) => "repository",
Step::File(_) => "file",
Step::Template(_) => "template",
Step::User(_) => "user",
Step::Group(_) => "group",
Step::Service(_) => "service",
Step::Command(_) => "command",
Step::Firewall(_) => "firewall",
}
}
#[must_use]
pub fn container_refusal(&self) -> Option<&'static str> {
match self {
Step::Reboot => Some("a reboot needs a machine with its own kernel and boot: a container has neither"),
Step::Playbook(_) => Some("a playbook step runs in a VM only in 1.0"),
Step::Run { script, .. } if has_extension(script.as_str(), "ps1") => Some("a PowerShell script means Windows, which has no container form in 1.0"),
_ => None,
}
}
}
pub(crate) fn has_extension(path: &str, extension: &str) -> bool {
std::path::Path::new(path).extension().is_some_and(|e| e.eq_ignore_ascii_case(extension))
}
impl schemars::JsonSchema for Step {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Step".into()
}
fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
<input::StepSchema as schemars::JsonSchema>::json_schema(g)
}
}
#[cfg(test)]
mod tests;