1use std::{
2 error, fmt, fs, io,
3 path::{Path, PathBuf},
4 process::Command,
5};
6
7#[derive(Debug)]
8pub enum Error {
9 AlreadyDownloaded,
10 MissingEnv,
11 InvalidFlutterRoot(&'static str),
12}
13
14impl fmt::Display for Error {
15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16 use std::error::Error;
17
18 f.write_str(self.description())
19 }
20}
21
22impl error::Error for Error {
23 fn description(&self) -> &str {
24 match *self {
25 Error::AlreadyDownloaded => "Flutter engine already downloaded",
26 Error::MissingEnv => "Cannot find flutter engine version. flutter cli not in PATH. You may need to set either FLUTTER_ROOT or FLUTTER_ENGINE_VERSION",
27 Error::InvalidFlutterRoot(_) => "Cannot read from FLUTTER_ROOT",
28 }
29 }
30}
31
32fn guess_sdk_path() -> Result<PathBuf, &'static str> {
33 let output = if cfg!(target_os = "windows") {
34 Command::new("cmd")
35 .args(&["/C", "where.exe flutter"])
36 .output()
37 } else {
38 Command::new("sh").arg("-c").arg("which flutter").output()
39 }
40 .map_err(|_| "cannot find flutter executable")?;
41 let s = std::str::from_utf8(output.stdout.as_slice())
42 .map_err(|_| "parse result of `which flutter`")?;
43 let line = s.trim().lines().next().ok_or("output empty")?;
44 let p = Path::new(line).canonicalize().map_err(|_| "follow link")?;
45 let p = p
46 .parent()
47 .ok_or("parent of flutter")?
48 .parent()
49 .ok_or("parent of parent of flutter")?;
50 Ok(p.to_owned())
51}
52
53fn read_ver_from_sdk(p: &Path) -> io::Result<String> {
54 let p = p.join("bin").join("internal").join("engine.version");
55 fs::read_to_string(p).map(|v| v.trim().to_owned())
56}
57
58pub fn get_flutter_version() -> Result<String, Error> {
59 if let Ok(v) = std::env::var("FLUTTER_ENGINE_VERSION") {
60 Ok(v)
61 } else if let Ok(v) = std::env::var("FLUTTER_ROOT") {
62 let p = Path::new(&v);
63 read_ver_from_sdk(p)
64 .map_err(|_| Error::InvalidFlutterRoot("read engine version from FLUTTER_ROOT failed"))
65 } else {
66 match guess_sdk_path() {
67 Ok(p) => read_ver_from_sdk(&p).map_err(|_| {
68 Error::InvalidFlutterRoot("read engine version from flutter executable failed")
69 }),
70 Err("cannot find flutter executable") => Err(Error::MissingEnv),
71 Err(reason) => Err(Error::InvalidFlutterRoot(reason)),
72 }
73 }
74}