1use std::{
2 env::{ consts::{ ARCH, OS }, var },
3 fs::metadata,
4 io::{ Error as IoError, ErrorKind },
5 path::PathBuf,
6 process::Command,
7 str::from_utf8
8};
9use crate::{
10 error::Error,
11 helpers::var_bool,
12 force::{ get_force_bin, get_force_include },
13 install::install,
14 path::{ get_bin_path, get_include_path },
15 version::{ compare_versions, get_protoc_asset_name }
16};
17
18pub fn init(version: &str) -> Result<(PathBuf, PathBuf), Error> {
27 let protoc_bin: PathBuf = get_force_bin()?.map_or_else(|| -> Result<PathBuf, Error> {
28 let out_dir = PathBuf::from(var("OUT_DIR").map_err(Error::VarError)?);
29
30 let protoc_asset_name = get_protoc_asset_name(version, OS, ARCH)?;
31 let protoc_out_dir = out_dir.join(&protoc_asset_name);
32
33 if !protoc_out_dir.exists() {
35 install(version, &out_dir, &protoc_asset_name, &protoc_out_dir)?;
36 }
37
38 Ok(get_bin_path(version, &protoc_out_dir))
39 }, Ok)?;
40
41 metadata(&protoc_bin).map_err(Error::Io)?;
43
44 let output = Command::new(&protoc_bin).args(["--version"]).output().map_err(Error::Io)?;
46 if !output.status.success() {
47 return Err(Error::Io(IoError::new(ErrorKind::Other, "test run protoc fail")))
48 }
49
50 if !var_bool("PROTOC_PREBUILT_NOT_CHECK_VERSION") {
51 let stdout = match from_utf8(&output.stdout) {
52 Ok(stdout) => stdout,
53 Err(_) => return Err(
54 Error::Io(IoError::new(ErrorKind::Other, "parse test run protoc output fail"))
55 )
56 };
57
58 let returned = stdout.trim().replace("libprotoc ", "");
59
60 if !compare_versions(version, &returned) {
61 return Err(Error::VersionCheck((version, returned)))
62 }
63 }
64
65 let protoc_include: PathBuf = get_force_include()?
66 .map_or_else(|| Ok(get_include_path(version, &protoc_bin)), Ok)?;
67
68 Ok((protoc_bin, protoc_include))
69}