volo_build/
config_builder.rs1use std::path::{Path, PathBuf};
2
3use anyhow::Ok;
4use pilota_build::BoxClonePlugin;
5use volo::FastStr;
6
7use crate::{
8 model::{self, Entry},
9 util::{
10 DEFAULT_CONFIG_FILE, DEFAULT_DIR, ServiceBuilder, download_repos_to_target,
11 get_service_builders_from_services, open_config_file, read_config_from_file,
12 },
13};
14
15pub struct ConfigBuilder {
16 filename: PathBuf,
17 plugins: Vec<BoxClonePlugin>,
18}
19
20#[allow(clippy::large_enum_variant)]
21pub enum InnerBuilder {
22 Protobuf(
23 crate::Builder<crate::grpc_backend::MkGrpcBackend, pilota_build::parser::ProtobufParser>,
24 ),
25 Thrift(
26 crate::Builder<crate::thrift_backend::MkThriftBackend, pilota_build::parser::ThriftParser>,
27 ),
28}
29
30impl InnerBuilder {
31 fn thrift() -> Self {
32 InnerBuilder::Thrift(crate::Builder::thrift())
33 }
34
35 fn protobuf() -> Self {
36 InnerBuilder::Protobuf(crate::Builder::protobuf())
37 }
38
39 fn plugin<P: pilota_build::Plugin + 'static>(self, p: P) -> Self {
40 match self {
41 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.plugin(p)),
42 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.plugin(p)),
43 }
44 }
45
46 fn write(self) -> anyhow::Result<()> {
47 match self {
48 InnerBuilder::Protobuf(inner) => inner.write(),
49 InnerBuilder::Thrift(inner) => inner.write(),
50 }
51 }
52
53 fn init_service(self) -> anyhow::Result<(String, String)> {
54 match self {
55 InnerBuilder::Protobuf(inner) => inner.init_service(),
56 InnerBuilder::Thrift(inner) => inner.init_service(),
57 }
58 }
59
60 fn filename(self, filename: PathBuf) -> Self {
61 match self {
62 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.filename(filename)),
63 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.filename(filename)),
64 }
65 }
66
67 fn includes(self, includes: Vec<PathBuf>) -> Self {
68 match self {
69 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.include_dirs(includes)),
70 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.include_dirs(includes)),
71 }
72 }
73
74 pub fn add_service<P>(self, path: P) -> Self
75 where
76 P: AsRef<Path>,
77 {
78 match self {
79 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.add_service(path)),
80 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.add_service(path)),
81 }
82 }
83
84 pub fn add_services(mut self, service_builders: Vec<ServiceBuilder>) -> Self {
85 for ServiceBuilder {
86 path,
87 includes,
88 touch,
89 keep_unknown_fields,
90 } in service_builders
91 {
92 self = self
93 .add_service(path.clone())
94 .includes(includes)
95 .touch([(path.clone(), touch)]);
96 if keep_unknown_fields {
97 self = self.keep_unknown_fields([path])
98 }
99 }
100 self
101 }
102
103 pub fn touch(self, items: impl IntoIterator<Item = (PathBuf, Vec<impl Into<String>>)>) -> Self {
104 match self {
105 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.touch(items)),
106 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.touch(items)),
107 }
108 }
109
110 pub fn ignore_unused(self, ignore_unused: bool) -> Self {
111 match self {
112 InnerBuilder::Protobuf(inner) => {
113 InnerBuilder::Protobuf(inner.ignore_unused(ignore_unused))
114 }
115 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.ignore_unused(ignore_unused)),
116 }
117 }
118
119 pub fn keep_unknown_fields(self, keep: impl IntoIterator<Item = PathBuf>) -> Self {
120 match self {
121 InnerBuilder::Protobuf(inner) => {
122 InnerBuilder::Protobuf(inner.keep_unknown_fields(keep))
123 }
124 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.keep_unknown_fields(keep)),
125 }
126 }
127
128 pub fn split_generated_files(self, split_generated_files: bool) -> Self {
129 match self {
130 InnerBuilder::Protobuf(inner) => {
131 InnerBuilder::Protobuf(inner.split_generated_files(split_generated_files))
132 }
133 InnerBuilder::Thrift(inner) => {
134 InnerBuilder::Thrift(inner.split_generated_files(split_generated_files))
135 }
136 }
137 }
138
139 pub fn common_crate_name(self, name: FastStr) -> Self {
140 match self {
141 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.common_crate_name(name)),
142 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.common_crate_name(name)),
143 }
144 }
145
146 pub fn special_namings(self, namings: impl IntoIterator<Item = FastStr>) -> Self {
147 match self {
148 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.special_namings(namings)),
149 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.special_namings(namings)),
150 }
151 }
152
153 pub fn dedup(self, dedup_list: Vec<FastStr>) -> Self {
154 match self {
155 InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.dedup(dedup_list)),
156 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.dedup(dedup_list)),
157 }
158 }
159
160 pub fn with_descriptor(self, with_descriptor: bool) -> Self {
161 match self {
162 InnerBuilder::Protobuf(inner) => {
163 InnerBuilder::Protobuf(inner.with_descriptor(with_descriptor))
164 }
165 InnerBuilder::Thrift(inner) => {
166 InnerBuilder::Thrift(inner.with_descriptor(with_descriptor))
167 }
168 }
169 }
170
171 pub fn with_field_mask(self, with_field_mask: bool) -> Self {
172 match self {
173 InnerBuilder::Protobuf(inner) => {
174 InnerBuilder::Protobuf(inner.with_field_mask(with_field_mask))
175 }
176 InnerBuilder::Thrift(inner) => {
177 InnerBuilder::Thrift(inner.with_field_mask(with_field_mask))
178 }
179 }
180 }
181
182 pub fn with_comments(self, with_comments: bool) -> Self {
183 match self {
184 InnerBuilder::Protobuf(inner) => {
185 InnerBuilder::Protobuf(inner.with_comments(with_comments))
186 }
187 InnerBuilder::Thrift(inner) => InnerBuilder::Thrift(inner.with_comments(with_comments)),
188 }
189 }
190}
191
192impl ConfigBuilder {
193 pub fn new(filename: PathBuf) -> Self {
194 ConfigBuilder {
195 filename,
196 plugins: Vec::new(),
197 }
198 }
199
200 pub fn plugin<P: pilota_build::ClonePlugin + 'static>(mut self, p: P) -> Self {
201 self.plugins.push(BoxClonePlugin::new(p));
202
203 self
204 }
205
206 pub fn write(self) -> anyhow::Result<()> {
207 println!("cargo:rerun-if-changed={}", self.filename.display());
208 let mut f = open_config_file(self.filename.clone())?;
209 let config = read_config_from_file(&mut f)?;
210 config
211 .entries
212 .into_iter()
213 .try_for_each(|(entry_name, entry)| {
214 let mut builder = match entry.protocol {
215 model::IdlProtocol::Thrift => InnerBuilder::thrift(),
216 model::IdlProtocol::Protobuf => InnerBuilder::protobuf(),
217 }
218 .filename(entry.filename.clone());
219
220 for p in self.plugins.iter() {
221 builder = builder.plugin(p.clone());
222 }
223
224 let target_dir = PathBuf::from(&*DEFAULT_DIR).join(entry_name);
226 let repo_dir_map = download_repos_to_target(&entry.repos, target_dir)?;
227
228 let service_builders =
230 get_service_builders_from_services(&entry.services, &repo_dir_map);
231
232 builder
234 .add_services(service_builders)
235 .ignore_unused(!entry.common_option.touch_all)
236 .special_namings(entry.common_option.special_namings)
237 .split_generated_files(entry.common_option.split_generated_files)
238 .dedup(entry.common_option.dedups)
239 .with_descriptor(entry.common_option.with_descriptor)
240 .with_field_mask(entry.common_option.with_field_mask)
241 .with_comments(entry.common_option.with_comments)
242 .write()?;
243
244 Ok(())
245 })?;
246 Ok(())
247 }
248}
249
250impl Default for ConfigBuilder {
251 fn default() -> Self {
252 ConfigBuilder::new(PathBuf::from(DEFAULT_CONFIG_FILE))
253 }
254}
255
256pub struct InitBuilder {
257 entry: Entry,
258}
259
260impl InitBuilder {
261 pub fn new(entry: Entry) -> Self {
262 InitBuilder { entry }
263 }
264
265 pub fn init(self) -> anyhow::Result<(String, String)> {
266 let mut builder = match self.entry.protocol {
267 model::IdlProtocol::Thrift => InnerBuilder::thrift(),
268 model::IdlProtocol::Protobuf => InnerBuilder::protobuf(),
269 }
270 .filename(self.entry.filename);
271
272 let temp_target_dir = tempfile::TempDir::new()?;
274 let repo_dir_map = download_repos_to_target(&self.entry.repos, temp_target_dir.as_ref())?;
275
276 let idl_builders = get_service_builders_from_services(&self.entry.services, &repo_dir_map);
278
279 builder = builder.add_services(idl_builders);
281
282 builder.init_service()
283 }
284}