Skip to main content

folk_builder/
codegen.rs

1use crate::config::{BuildConfig, PluginEntry};
2
3/// Generate the content of the output `Cargo.toml`.
4pub fn generate_cargo_toml(cfg: &BuildConfig) -> String {
5    let mut deps = String::new();
6
7    // Core dependencies
8    deps.push_str(
9        r#"folk-core = "0.1.3"
10folk-api = "0.1"
11folk-runtime-pipe = "0.1.2"
12folk-runtime-fork = "0.1.2"
13serde_json = "1"
14toml = "0.8"
15tokio = { version = "1", features = ["full"] }
16anyhow = "1"
17tracing-subscriber = { version = "0.3", features = ["env-filter"] }
18"#,
19    );
20
21    for plugin in &cfg.plugin {
22        deps.push_str(&generate_plugin_dep(plugin));
23    }
24
25    format!(
26        r#"[package]
27name = "{output}"
28version = "0.1.0"
29edition = "2024"
30
31[[bin]]
32name = "{output}"
33path = "src/main.rs"
34
35[dependencies]
36{deps}
37"#,
38        output = cfg.build.output,
39        deps = deps
40    )
41}
42
43fn generate_plugin_dep(p: &PluginEntry) -> String {
44    if let Some(path) = &p.path {
45        format!(
46            r#"{} = {{ path = "{}" }}
47"#,
48            p.crate_name, path
49        )
50    } else if let Some(git) = &p.git {
51        let ver = p.version.as_deref().unwrap_or("0.1");
52        format!(
53            r#"{} = {{ git = "{}", version = "{}" }}
54"#,
55            p.crate_name, git, ver
56        )
57    } else {
58        let ver = p.version.as_deref().unwrap_or("0.1");
59        format!(
60            r#"{} = "{}"
61"#,
62            p.crate_name, ver
63        )
64    }
65}
66
67/// Generate the content of the output `main.rs`.
68pub fn generate_main_rs(cfg: &BuildConfig) -> String {
69    let imports: Vec<String> = cfg
70        .plugin
71        .iter()
72        .map(|p| {
73            let ident = p.crate_name.replace('-', "_");
74            format!("use {}::folk_plugin_factory as {}_factory;", ident, ident)
75        })
76        .collect();
77
78    let registrations: Vec<String> = cfg
79        .plugin
80        .iter()
81        .map(|p| {
82            let ident = p.crate_name.replace('-', "_");
83            let key = if p.config_key.is_empty() {
84                &p.crate_name
85            } else {
86                &p.config_key
87            };
88            format!(
89                r#"    let cfg_{ident} = raw_cfg.get("{key}").cloned().unwrap_or(toml::Value::Table(Default::default()));
90    let cfg_{ident}_json = serde_json::to_value(&cfg_{ident}).unwrap_or_default();
91    server.register_plugin({ident}_factory().create(cfg_{ident}_json)?);
92"#,
93                ident = ident,
94                key = key
95            )
96        })
97        .collect();
98
99    format!(
100        r#"//! Generated by folk-builder. Do not edit.
101
102{imports}
103
104#[tokio::main]
105async fn main() -> anyhow::Result<()> {{
106    let cfg = folk_core::config::FolkConfig::load()?;
107    folk_core::logging::init(&cfg.log)?;
108    let raw_cfg: toml::Table = {{
109        let content = std::fs::read_to_string("folk.toml").unwrap_or_default();
110        content.parse().unwrap_or_default()
111    }};
112
113    let runtime: std::sync::Arc<dyn folk_core::runtime::Runtime> = match cfg.server.runtime {{
114        folk_core::config::RuntimeKind::Pipe => std::sync::Arc::new(
115            folk_runtime_pipe::runtime::PipeRuntime::new(
116                folk_runtime_pipe::runtime::PipeConfig {{
117                    php: cfg.workers.php.clone(),
118                    script: cfg.workers.script.clone(),
119                }},
120            ),
121        ),
122        folk_core::config::RuntimeKind::Fork => {{
123            folk_runtime_fork::ForkRuntime::new(folk_runtime_fork::ForkConfig {{
124                php: cfg.workers.php.clone(),
125                script: cfg.workers.script.clone(),
126                boot_timeout: cfg.workers.boot_timeout,
127            }})
128            .await?
129        }}
130    }};
131
132    let mut server = folk_core::server::FolkServer::new(cfg, runtime);
133
134{registrations}
135
136    server.run().await
137}}
138"#,
139        imports = imports.join("\n"),
140        registrations = registrations.join("")
141    )
142}