cargo-warp 0.1.11

Build then copy your project binary to a remote host.
use cargo_metadata::Message;
use serde::Deserialize;
use std::{
    path::PathBuf,
    process::{Command, Stdio},
};

pub enum BuildType {
    Cargo,
    Cross,
}

pub fn cargo_build(
    package: Option<&str>,
    target: Option<&str>,
    release: bool,
    build_type: BuildType,
) -> Vec<std::path::PathBuf> {
    let mut args: Vec<&str> = vec![
        "--color",
        "always",
        "build",
        "--message-format=json-render-diagnostics",
    ];

    if let Some(package) = package {
        args.push("--package");
        args.push(package)
    }

    if let Some(target) = target {
        args.push("--target");
        args.push(target)
    }

    if release {
        args.push("--release");
    }

    let path = match build_type {
        BuildType::Cargo => std::path::PathBuf::from("/"),
        BuildType::Cross => locate_project(),
    };

    let mut command = Command::new(match build_type {
        BuildType::Cargo => "cargo",
        BuildType::Cross => "cross",
    })
    .args(args)
    .stdout(Stdio::piped())
    .spawn()
    .unwrap();

    let reader = std::io::BufReader::new(command.stdout.take().unwrap());
    let mut files: Vec<std::path::PathBuf> = vec![];
    for message in cargo_metadata::Message::parse_stream(reader) {
        if let Message::CompilerArtifact(artifact) = message.unwrap() {
            if artifact.executable.is_some() {
                let mut p: std::path::PathBuf = path.clone();
                p.push(
                    std::path::PathBuf::from(
                        artifact
                            .executable
                            .unwrap()
                            .into_os_string()
                            .into_string()
                            .unwrap(),
                    )
                    .strip_prefix("/")
                    .unwrap(),
                );

                files.push(p.clone());
            }
        }
    }

    let _output = command.wait().expect("Couldn't get cargo's exit status");

    files
}

#[derive(Deserialize)]
struct LocateProjectOutput {
    root: String,
}

fn locate_project() -> PathBuf {
    let output = Command::new("cargo")
        .arg("locate-project")
        .output()
        .expect("Failed to execute cargo locate-project");

    if !output.status.success() {
        panic!("cargo locate-project failed with status: {}", output.status);
    }

    let locate_project_output: LocateProjectOutput = serde_json::from_slice(&output.stdout)
        .expect("Failed to parse JSON output from cargo locate-project");

    let mut path = PathBuf::from(locate_project_output.root);
    path.pop();
    path
}