1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize)]
5pub struct PropelConfig {
6 #[serde(default)]
7 pub project: ProjectConfig,
8 #[serde(default)]
9 pub build: BuildConfig,
10 #[serde(default)]
11 pub cloud_run: CloudRunConfig,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ProjectConfig {
16 pub name: Option<String>,
18 #[serde(default = "default_region")]
20 pub region: String,
21 pub gcp_project_id: Option<String>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct BuildConfig {
27 #[serde(default = "default_builder_image")]
29 pub base_image: String,
30 #[serde(default = "default_runtime_image")]
32 pub runtime_image: String,
33 #[serde(default)]
35 pub extra_packages: Vec<String>,
36 #[serde(default = "default_cargo_chef_version")]
38 pub cargo_chef_version: String,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct CloudRunConfig {
43 #[serde(default = "default_memory")]
45 pub memory: String,
46 #[serde(default = "default_cpu")]
48 pub cpu: u32,
49 #[serde(default)]
51 pub min_instances: u32,
52 #[serde(default = "default_max_instances")]
54 pub max_instances: u32,
55 #[serde(default = "default_concurrency")]
57 pub concurrency: u32,
58 #[serde(default = "default_port")]
60 pub port: u16,
61}
62
63impl Default for ProjectConfig {
64 fn default() -> Self {
65 Self {
66 name: None,
67 region: default_region(),
68 gcp_project_id: None,
69 }
70 }
71}
72
73impl Default for BuildConfig {
74 fn default() -> Self {
75 Self {
76 base_image: default_builder_image(),
77 runtime_image: default_runtime_image(),
78 extra_packages: Vec::new(),
79 cargo_chef_version: default_cargo_chef_version(),
80 }
81 }
82}
83
84impl Default for CloudRunConfig {
85 fn default() -> Self {
86 Self {
87 memory: default_memory(),
88 cpu: default_cpu(),
89 min_instances: 0,
90 max_instances: default_max_instances(),
91 concurrency: default_concurrency(),
92 port: default_port(),
93 }
94 }
95}
96
97impl PropelConfig {
98 pub fn load(project_dir: &std::path::Path) -> crate::Result<Self> {
100 let config_path = project_dir.join("propel.toml");
101 if config_path.exists() {
102 let content =
103 std::fs::read_to_string(&config_path).map_err(|e| crate::Error::ConfigLoad {
104 path: config_path.clone(),
105 source: e,
106 })?;
107 toml::from_str(&content).map_err(|e| crate::Error::ConfigParse {
108 path: config_path,
109 source: e,
110 })
111 } else {
112 Ok(Self::default())
113 }
114 }
115}
116
117fn default_region() -> String {
118 "us-central1".to_owned()
119}
120
121fn default_builder_image() -> String {
122 "rust:1.84-bookworm".to_owned()
123}
124
125fn default_runtime_image() -> String {
126 "gcr.io/distroless/cc-debian12".to_owned()
127}
128
129fn default_cargo_chef_version() -> String {
130 "0.1.68".to_owned()
131}
132
133fn default_memory() -> String {
134 "512Mi".to_owned()
135}
136
137fn default_cpu() -> u32 {
138 1
139}
140
141fn default_max_instances() -> u32 {
142 10
143}
144
145fn default_concurrency() -> u32 {
146 80
147}
148
149fn default_port() -> u16 {
150 8080
151}