flowey_lib_common/
resolve_protoc.rs1use flowey::node::prelude::*;
7
8#[derive(Serialize, Deserialize)]
9pub struct ProtocPackage {
10 pub protoc_bin: PathBuf,
11 pub include_dir: PathBuf,
12}
13
14fn resolve_protoc_from_dir(
17 rt: &mut RustRuntimeServices<'_>,
18 base_dir: &Path,
19 make_executable: bool,
20) -> anyhow::Result<ProtocPackage> {
21 let protoc_bin = base_dir
22 .join("bin")
23 .join(rt.platform().binary("protoc"))
24 .absolute()?;
25
26 if !protoc_bin.exists() {
27 anyhow::bail!("protoc binary not found at {}", protoc_bin.display())
28 }
29
30 let protoc_bin_executable = protoc_bin.is_executable()?;
31 if !protoc_bin_executable && !make_executable {
32 anyhow::bail!(
33 "protoc binary at {} is not executable",
34 protoc_bin.display()
35 );
36 }
37
38 if make_executable {
39 protoc_bin.make_executable()?;
40 }
41
42 let include_dir = base_dir.join("include").absolute()?;
43 if !include_dir.exists() {
44 anyhow::bail!(
45 "protoc include directory not found at {}",
46 include_dir.display()
47 )
48 }
49
50 Ok(ProtocPackage {
51 protoc_bin,
52 include_dir,
53 })
54}
55
56flowey_request! {
57 pub enum Request {
58 LocalPath(ReadVar<PathBuf>),
60 Version(String),
62 Get(WriteVar<ProtocPackage>),
64 }
65}
66
67new_flow_node!(struct Node);
68
69impl FlowNode for Node {
70 type Request = Request;
71
72 fn imports(ctx: &mut ImportCtx<'_>) {
73 ctx.import::<crate::install_dist_pkg::Node>();
74 ctx.import::<crate::download_gh_release::Node>();
75 ctx.import::<crate::cache::Node>();
76 }
77
78 fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
79 let mut version = None;
80 let mut local_path: Option<ReadVar<PathBuf>> = None;
81 let mut get_reqs = Vec::new();
82
83 for req in requests {
84 match req {
85 Request::LocalPath(path) => {
86 if local_path.is_some() {
87 anyhow::bail!("Duplicate LocalPath requests")
88 }
89 local_path = Some(path);
90 }
91 Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
92 Request::Get(v) => get_reqs.push(v),
93 }
94 }
95
96 if version.is_some() && local_path.is_some() {
97 anyhow::bail!("Cannot specify both Version and LocalPath requests");
98 }
99
100 if version.is_none() && local_path.is_none() {
101 anyhow::bail!("Must specify a Version or LocalPath request");
102 }
103
104 if get_reqs.is_empty() {
107 return Ok(());
108 }
109
110 if let Some(local_path) = local_path {
111 ctx.emit_rust_step("use local protoc", |ctx| {
112 let get_reqs = get_reqs.claim(ctx);
113 let local_path = local_path.claim(ctx);
114 move |rt| {
115 let local_path = rt.read(local_path);
116 log::info!("using protoc from base path {}", local_path.display());
117
118 let pkg = resolve_protoc_from_dir(rt, &local_path, false)?;
121 rt.write_all(get_reqs, &pkg);
122
123 Ok(())
124 }
125 });
126
127 return Ok(());
128 }
129
130 let version = version.expect("local requests handled above");
131
132 let tag = format!("v{version}");
133 let file_name = format!(
134 "protoc-{}-{}.zip",
135 version,
136 match (ctx.platform(), ctx.arch()) {
137 (FlowPlatform::Windows, _) => "win64",
140 (FlowPlatform::Linux(_), FlowArch::X86_64) => "linux-x86_64",
141 (FlowPlatform::Linux(_), FlowArch::Aarch64) => "linux-aarch_64",
142 (FlowPlatform::MacOs, FlowArch::X86_64) => "osx-x86_64",
143 (FlowPlatform::MacOs, FlowArch::Aarch64) => "osx-aarch_64",
144 (platform, arch) => anyhow::bail!("unsupported platform {platform} {arch}"),
145 }
146 );
147
148 let protoc_zip = ctx.reqv(|v| crate::download_gh_release::Request {
149 repo_owner: "protocolbuffers".into(),
150 repo_name: "protobuf".into(),
151 needs_auth: false,
152 tag: tag.clone(),
153 file_name: file_name.clone(),
154 path: v,
155 });
156
157 let extract_zip_deps = crate::_util::extract::extract_zip_if_new_deps(ctx);
158 ctx.emit_rust_step("unpack protoc", |ctx| {
159 let extract_zip_deps = extract_zip_deps.clone().claim(ctx);
160 let get_reqs = get_reqs.claim(ctx);
161 let protoc_zip = protoc_zip.claim(ctx);
162 move |rt| {
163 let protoc_zip = rt.read(protoc_zip);
164
165 let extract_dir = crate::_util::extract::extract_zip_if_new(
166 rt,
167 extract_zip_deps,
168 &protoc_zip,
169 &tag,
170 )?;
171
172 let pkg = resolve_protoc_from_dir(rt, &extract_dir, true)?;
173 rt.write_all(get_reqs, &pkg);
174
175 Ok(())
176 }
177 });
178
179 Ok(())
180 }
181}