mod case;
mod context;
mod fourcc;
mod kind;
mod layout;
mod render;
mod spec;
use std::fs;
use std::path::Path;
use crate::{BoxErr, Res};
use context::{PluginScaffoldingContext, TruceTomlContext, WorkspaceContext};
use layout::{ProjectLayout, WorkspaceLayout};
use render::{Renderer, tpl};
pub use case::to_pascal_case;
pub use fourcc::{resolve_fourccs, to_fourcc};
pub use kind::PluginKind;
pub use spec::{DepForm, FeatureSet, PluginSpec, VendorInfo};
pub struct Scaffolder {
renderer: Renderer,
tag: String,
}
impl Scaffolder {
#[allow(clippy::new_without_default)]
#[must_use]
pub fn new() -> Self {
Self {
renderer: Renderer::new(),
tag: format!("v{}", env!("CARGO_PKG_VERSION")),
}
}
pub fn single(
&self,
root: &Path,
plugin: &PluginSpec,
features: FeatureSet,
vendor: &VendorInfo,
) -> Res {
let layout = ProjectLayout::single(root);
self.write_plugin_files(
&layout,
&plugin.name,
plugin.kind,
DepForm::GitTag,
features,
)?;
let plugins = std::slice::from_ref(plugin);
let fourcc_map = resolve_fourccs(plugins)?;
let truce_ctx = TruceTomlContext::new(vendor, plugins, &plugin.name, &fourcc_map, false);
let truce_path = layout.truce_toml();
write(
&truce_path,
self.renderer.render(tpl::TRUCE_TOML, &truce_ctx),
)?;
Ok(())
}
pub fn workspace(
&self,
root: &Path,
workspace_name: &str,
plugins: &[PluginSpec],
features: FeatureSet,
vendor: &VendorInfo,
) -> Res {
let ws_layout = WorkspaceLayout::new(root);
fs::create_dir_all(ws_layout.cargo_dir())?;
let ws_ctx = WorkspaceContext::new(plugins, features, &self.tag);
write(
&ws_layout.cargo_toml(),
self.renderer.render(tpl::WORKSPACE_CARGO_TOML, &ws_ctx),
)?;
let fourcc_map = resolve_fourccs(plugins)?;
let truce_ctx = TruceTomlContext::new(vendor, plugins, workspace_name, &fourcc_map, true);
write(
&ws_layout.truce_toml(),
self.renderer.render(tpl::TRUCE_TOML, &truce_ctx),
)?;
write(
&ws_layout.gitignore(),
include_str!("../../templates/scaffold/plugin/.gitignore.tpl").to_string(),
)?;
write(
&ws_layout.cargo_config(),
include_str!("../../templates/scaffold/plugin/.cargo/config.toml.tpl").to_string(),
)?;
for p in plugins {
let layout = ProjectLayout::workspace_plugin(root, &p.name);
let crate_name = format!("{workspace_name}-{}", p.name);
self.write_plugin_files(&layout, &crate_name, p.kind, DepForm::Workspace, features)?;
}
Ok(())
}
fn write_plugin_files(
&self,
layout: &ProjectLayout,
crate_name: &str,
kind: PluginKind,
dep_form: DepForm,
features: FeatureSet,
) -> Res {
fs::create_dir_all(layout.src_dir())?;
fs::create_dir_all(layout.cargo_dir())?;
let ctx = PluginScaffoldingContext::new(crate_name, kind, dep_form, features, &self.tag);
write(
&layout.cargo_toml(),
self.renderer.render(tpl::PLUGIN_CARGO_TOML, &ctx),
)?;
write(
&layout.lib_rs(),
self.renderer.render(tpl::PLUGIN_LIB_RS, &ctx),
)?;
if features.standalone {
write(
&layout.main_rs(),
self.renderer.render(tpl::PLUGIN_MAIN_RS, &ctx),
)?;
}
if dep_form == DepForm::GitTag {
write(
&layout.gitignore(),
self.renderer.render(tpl::PLUGIN_GITIGNORE, &ctx),
)?;
write(
&layout.cargo_config(),
self.renderer.render(tpl::PLUGIN_CARGO_CONFIG, &ctx),
)?;
}
Ok(())
}
}
fn write(path: &Path, content: String) -> Res {
fs::write(path, content)
.map_err(|e| -> BoxErr { format!("write {}: {}", path.display(), e).into() })?;
Ok(())
}