fn generate_installer_toml(
patterns: &[BashPattern],
name: &str,
) -> Result<(String, Vec<TemplateFile>, ConversionStats)> {
let mut toml = String::new();
let mut templates = Vec::new();
let mut stats = ConversionStats::default();
let mut step_id = 0;
let requires_root = patterns.iter().any(|p| matches!(p, BashPattern::RootCheck));
toml.push_str(&format!(
r#"# Installer specification converted from bash script
# Generated by bashrs installer from-bash
[installer]
name = "{name}"
version = "1.0.0"
description = "Converted from legacy bash script"
[installer.requirements]
privileges = "{}"
"#,
if requires_root { "root" } else { "user" }
));
for pattern in patterns {
match pattern {
BashPattern::RootCheck => {
stats.conditionals_converted += 1;
}
BashPattern::AptUpdate => {
step_id += 1;
stats.steps_generated += 1;
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-apt-update"
name = "Update Package Lists"
action = "script"
[step.script]
interpreter = "sh"
content = "apt-get update"
"#
));
}
BashPattern::AptInstall { packages } => {
step_id += 1;
stats.steps_generated += 1;
stats.apt_installs += 1;
let packages_list = packages
.iter()
.map(|p| format!("\"{}\"", p))
.collect::<Vec<_>>()
.join(", ");
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-install"
name = "Install Packages"
action = "script"
[step.script]
interpreter = "sh"
content = "apt-get install -y {}"
# Packages: [{}]
"#,
packages.join(" "),
packages_list
));
}
BashPattern::MkdirP { path } => {
step_id += 1;
stats.steps_generated += 1;
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-mkdir"
name = "Create Directory"
action = "script"
[step.script]
interpreter = "sh"
content = "mkdir -p {path}"
"#
));
}
BashPattern::Download { url, output } => {
step_id += 1;
stats.steps_generated += 1;
let output_str = output.as_deref().unwrap_or("downloaded-file");
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-download"
name = "Download File"
action = "script"
[step.script]
interpreter = "sh"
content = "curl -fsSL {url} -o {output_str}"
"#
));
}
BashPattern::Heredoc { delimiter, content } => {
step_id += 1;
stats.steps_generated += 1;
stats.heredocs_converted += 1;
let template_name = format!("template-{}.txt", step_id);
templates.push(TemplateFile {
name: template_name.clone(),
content: content.clone(),
});
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-heredoc"
name = "Write Template File"
action = "script"
# Original heredoc delimiter: {delimiter}
# Template extracted to: templates/{template_name}
[step.script]
interpreter = "sh"
content = "cat templates/{template_name}"
"#
));
}
BashPattern::SudoCommand { command } => {
step_id += 1;
stats.steps_generated += 1;
stats.sudo_patterns += 1;
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-sudo"
name = "Execute Privileged Command"
action = "script"
[step.script]
interpreter = "sh"
content = "{command}"
[step.checkpoint]
enabled = true
"#
));
}
BashPattern::Script { content } => {
step_id += 1;
stats.steps_generated += 1;
toml.push_str(&format!(
r#"[[step]]
id = "step-{step_id}-script"
name = "Execute Script"
action = "script"
[step.script]
interpreter = "sh"
content = "{content}"
"#
));
}
}
}
Ok((toml, templates, stats))
}
include!("from_bash_generate.rs");