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