cargo_flutter/
engine.rs

1use crate::error::Error;
2use curl::easy::Easy;
3use exitfailure::ExitFailure;
4use std::fs::File;
5use std::io::Write;
6use std::path::PathBuf;
7
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct Engine {
10    version: String,
11    target: String,
12    build: Build,
13}
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum Build {
17    Debug,
18    Release,
19    Profile,
20}
21
22impl Build {
23    pub fn build(&self) -> &str {
24        match self {
25            Self::Debug => "debug_unopt",
26            Self::Release => "release",
27            Self::Profile => "profile",
28        }
29    }
30}
31
32impl Engine {
33    pub fn new(version: String, target: String, build: Build) -> Engine {
34        Engine {
35            version,
36            target,
37            build,
38        }
39    }
40
41    pub fn download_url(&self) -> String {
42        let build = self.build.build();
43        let platform = match self.target.as_str() {
44            "x86_64-unknown-linux-gnu" => format!("linux_x64-host_{}", build),
45            "armv7-linux-androideabi" => format!("linux_x64-android_{}", build),
46            "aarch64-linux-android" => format!("linux_x64-android_{}_arm64", build),
47            "i686-linux-android" => format!("linux_x64-android_{}_x64", build),
48            "x86_64-linux-android" => format!("linux_x64-android_{}_x86", build),
49            "x86_64-apple-darwin" => format!("macosx_x64-host_{}", build),
50            "armv7-apple-ios" => format!("macosx_x64-ios_{}_arm", build),
51            "aarch64-apple-ios" => format!("macosx_x64-ios_{}", build),
52            "x86_64-pc-windows-msvc" => format!("windows_x64-host_{}", build),
53            _ => panic!("unsupported platform"),
54        };
55        format!(
56            "https://github.com/flutter-rs/engine-builds/releases/download/f-{0}/{1}.zip",
57            &self.version, platform
58        )
59    }
60
61    pub fn library_name(&self) -> &'static str {
62        match self.target.as_str() {
63            "x86_64-unknown-linux-gnu" => "libflutter_engine.so",
64            "armv7-linux-androideabi" => "libflutter_engine.so",
65            "aarch64-linux-android" => "libflutter_engine.so",
66            "i686-linux-android" => "libflutter_engine.so",
67            "x86_64-linux-android" => "libflutter_engine.so",
68            "x86_64-apple-darwin" => "libflutter_engine.dylib",
69            "armv7-apple-ios" => "libflutter_engine.dylib",
70            "aarch64-apple-ios" => "libflutter_engine.dylib",
71            "x86_64-pc-windows-msvc" => "flutter_engine.dll",
72            _ => panic!("unsupported platform"),
73        }
74    }
75
76    pub fn engine_dir(&self) -> PathBuf {
77        dirs::cache_dir()
78            .expect("Cannot get cache dir")
79            .join("flutter-engine")
80            .join(&self.version)
81            .join(&self.target)
82            .join(self.build.build())
83    }
84
85    pub fn engine_path(&self) -> PathBuf {
86        self.engine_dir().join(self.library_name())
87    }
88
89    pub fn download(&self, quiet: bool) -> Result<(), ExitFailure> {
90        let url = self.download_url();
91        let path = self.engine_path();
92        let dir = path.parent().unwrap().to_owned();
93
94        if path.exists() {
95            return Ok(());
96        }
97
98        std::fs::create_dir_all(&dir)?;
99
100        println!("Starting download from {}", url);
101        let download_file = dir.join("engine.zip");
102        let mut file = File::create(&download_file)?;
103        let mut last_done = 0.0;
104
105        let mut easy = Easy::new();
106        easy.fail_on_error(true)?;
107        easy.url(&url)?;
108        easy.follow_location(true)?;
109        easy.progress(true)?;
110        easy.progress_function(move |total, done, _, _| {
111            if done > last_done {
112                last_done = done;
113                if !quiet {
114                    println!("Downloading flutter engine {} of {}", done, total);
115                }
116            }
117            true
118        })?;
119        easy.write_function(move |data| Ok(file.write(data).unwrap()))?;
120
121        easy.perform()
122            .or_else(|_| Err(Error::EngineNotFound(self.version.clone())))?;
123        println!("Download finished");
124
125        println!("Extracting...");
126        crate::unzip::unzip(&download_file, &dir)?;
127
128        Ok(())
129    }
130
131    pub fn dart(&self) -> Result<PathBuf, Error> {
132        let host_engine_dir = self.engine_dir();
133        ["dart", "dart.exe"]
134            .iter()
135            .map(|bin| host_engine_dir.join(bin))
136            .find(|path| path.exists())
137            .ok_or(Error::DartNotFound)
138    }
139}