cargo-flutter 0.1.12

Tool for building flutter-rs projects.
Documentation
use crate::error::Error;
use curl::easy::Easy;
use exitfailure::ExitFailure;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Engine {
    version: String,
    target: String,
    build: Build,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Build {
    Debug,
    Release,
    Profile,
}

impl Build {
    pub fn build(&self) -> &str {
        match self {
            Self::Debug => "debug_unopt",
            Self::Release => "release",
            Self::Profile => "profile",
        }
    }
}

impl Engine {
    pub fn new(version: String, target: String, build: Build) -> Engine {
        Engine {
            version,
            target,
            build,
        }
    }

    pub fn download_url(&self) -> String {
        let build = self.build.build();
        let platform = match self.target.as_str() {
            "x86_64-unknown-linux-gnu" => format!("linux_x64-host_{}", build),
            "armv7-linux-androideabi" => format!("linux_x64-android_{}", build),
            "aarch64-linux-android" => format!("linux_x64-android_{}_arm64", build),
            "i686-linux-android" => format!("linux_x64-android_{}_x64", build),
            "x86_64-linux-android" => format!("linux_x64-android_{}_x86", build),
            "x86_64-apple-darwin" => format!("macosx_x64-host_{}", build),
            "armv7-apple-ios" => format!("macosx_x64-ios_{}_arm", build),
            "aarch64-apple-ios" => format!("macosx_x64-ios_{}", build),
            "x86_64-pc-windows-msvc" => format!("windows_x64-host_{}", build),
            _ => panic!("unsupported platform"),
        };
        format!(
            "https://github.com/flutter-rs/engine-builds/releases/download/f-{0}/{1}.zip",
            &self.version, platform
        )
    }

    pub fn library_name(&self) -> &'static str {
        match self.target.as_str() {
            "x86_64-unknown-linux-gnu" => "libflutter_engine.so",
            "armv7-linux-androideabi" => "libflutter_engine.so",
            "aarch64-linux-android" => "libflutter_engine.so",
            "i686-linux-android" => "libflutter_engine.so",
            "x86_64-linux-android" => "libflutter_engine.so",
            "x86_64-apple-darwin" => "libflutter_engine.dylib",
            "armv7-apple-ios" => "libflutter_engine.dylib",
            "aarch64-apple-ios" => "libflutter_engine.dylib",
            "x86_64-pc-windows-msvc" => "flutter_engine.dll",
            _ => panic!("unsupported platform"),
        }
    }

    pub fn engine_dir(&self) -> PathBuf {
        dirs::cache_dir()
            .expect("Cannot get cache dir")
            .join("flutter-engine")
            .join(&self.version)
            .join(&self.target)
            .join(self.build.build())
    }

    pub fn engine_path(&self) -> PathBuf {
        self.engine_dir().join(self.library_name())
    }

    pub fn download(&self, quiet: bool) -> Result<(), ExitFailure> {
        let url = self.download_url();
        let path = self.engine_path();
        let dir = path.parent().unwrap().to_owned();

        if path.exists() {
            return Ok(());
        }

        std::fs::create_dir_all(&dir)?;

        println!("Starting download from {}", url);
        let download_file = dir.join("engine.zip");
        let mut file = File::create(&download_file)?;
        let mut last_done = 0.0;

        let mut easy = Easy::new();
        easy.fail_on_error(true)?;
        easy.url(&url)?;
        easy.follow_location(true)?;
        easy.progress(true)?;
        easy.progress_function(move |total, done, _, _| {
            if done > last_done {
                last_done = done;
                if !quiet {
                    println!("Downloading flutter engine {} of {}", done, total);
                }
            }
            true
        })?;
        easy.write_function(move |data| Ok(file.write(data).unwrap()))?;

        easy.perform()
            .or_else(|_| Err(Error::EngineNotFound(self.version.clone())))?;
        println!("Download finished");

        println!("Extracting...");
        crate::unzip::unzip(&download_file, &dir)?;

        Ok(())
    }

    pub fn dart(&self) -> Result<PathBuf, Error> {
        let host_engine_dir = self.engine_dir();
        ["dart", "dart.exe"]
            .iter()
            .map(|bin| host_engine_dir.join(bin))
            .find(|path| path.exists())
            .ok_or(Error::DartNotFound)
    }
}