cargo-flutter 0.1.7

Tool for building flutter-rs projects.
Documentation
use crate::error::Error;
use cargo::core::{Package, Workspace};
use cargo::util::important_paths::find_root_manifest_for_wd;
use cargo::util::Config;
use std::io::Read;
use std::path::PathBuf;
use std::process::{Command, Stdio};

pub struct Cargo<'a> {
    args: Vec<&'a str>,
    workspace: Workspace<'a>,
}

impl<'a> Cargo<'a> {
    pub fn new(config: &'a mut Config, args: Vec<&'a str>) -> Result<Self, Error> {
        let root_manifest = find_root_manifest_for_wd(config.cwd())?;
        let target_dir = root_manifest
            .parent()
            .unwrap()
            .join("target")
            .join("flutter");
        config
            .configure(0, None, &None, false, false, false, &Some(target_dir), &[])
            .unwrap();

        let workspace = Workspace::new(&root_manifest, config)?;
        Ok(Self { args, workspace })
    }

    fn arg<F: Fn(&str) -> bool>(&self, matches: F) -> Option<&str> {
        self.args
            .iter()
            .position(|f| matches(f))
            .map(|pos| self.args.get(pos + 1))
            .unwrap_or_default()
            .cloned()
    }

    pub fn cmd(&self) -> &str {
        self.args.iter().next().expect("Expected command")
    }

    pub fn target(&self) -> Option<&str> {
        self.arg(|f| f == "--target")
    }

    pub fn package(&self) -> Result<&Package, Error> {
        Ok(
            if let Some(package) = self.arg(|f| f == "--package" || f == "-p") {
                self.workspace()
                    .members()
                    .find(|pkg| pkg.name().as_str() == package)
                    .ok_or(Error::PackageNotMember)?
            } else {
                self.workspace().current()?
            },
        )
    }

    pub fn release(&self) -> bool {
        self.args.iter().any(|f| *f == "--release")
    }

    pub fn host_target(&self) -> Result<String, Error> {
        let rustc = self
            .workspace
            .config()
            .load_global_rustc(Some(&self.workspace))?;
        Ok(rustc.host.as_str().to_string())
    }

    pub fn triple(&self) -> Result<String, Error> {
        if let Some(target) = self.target() {
            Ok(target.to_string())
        } else {
            self.host_target()
        }
    }

    pub fn workspace(&self) -> &Workspace {
        &self.workspace
    }

    pub fn target_dir(&self) -> PathBuf {
        self.workspace().target_dir().into_path_unlocked()
    }

    pub fn build_dir(&self) -> PathBuf {
        let flutter_dir = self.target_dir();
        let triple_dir = if let Some(target) = self.target() {
            flutter_dir.join(target)
        } else {
            flutter_dir
        };
        if self.release() {
            triple_dir.join("release")
        } else {
            triple_dir.join("debug")
        }
    }

    fn cargo_command(&self) -> Command {
        let mut cmd = Command::new("cargo");
        cmd.current_dir(self.workspace.config().cwd())
            .args(&self.args)
            .arg("--target-dir")
            .arg(self.target_dir());
        cmd
    }

    pub fn build(&self) -> Result<(), Error> {
        let status = self.cargo_command().status().expect("Success");
        if status.code() != Some(0) {
            return Err(Error::CargoError);
        }
        Ok(())
    }

    pub fn run(&self) -> Result<String, Error> {
        let mut child = self
            .cargo_command()
            .stdout(Stdio::piped())
            .spawn()
            .expect("Success");
        let stdout = child.stdout.as_mut().unwrap();
        let mut buffer = [0; 70];
        stdout.read_exact(&mut buffer)?;
        let string = std::str::from_utf8(&buffer)?;
        Ok(string[34..].to_string())
    }
}