flutter_download/
util.rs

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}