1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use std::path::{Path, PathBuf};
use std::process::Command;

use cargo::core::{EitherManifest, Manifest, SourceId};
use cargo::util::toml::read_manifest;
use cargo::Config;
use failure::ResultExt;
use rustc_serialize::json::Json;

use crate::error::{Error, ErrorKind, Result};

pub fn load_cargo_toml(path: &Path) -> Result<Manifest> {
    let config = Config::default().expect("Unable to get config.");
    let source_id = SourceId::for_path(path).with_context(|err| {
        let message = format!(
            "Can't generate SourceId for Cargo.toml file. Reason: {:?}",
            err
        );
        ErrorKind::Io { reason: message }
    })?;

    let (manifest, _path) = read_manifest(path, source_id, &config).with_context(|err| {
        let message = format!("Can't read Cargo.toml file. Reason: {:?}", err);
        ErrorKind::Io { reason: message }
    })?;

    let cargo_toml = match manifest {
        EitherManifest::Real(manifest) => manifest,
        _ => {
            let description = String::from("Received a virtual Cargo.toml data.");
            return Err(Error::from(ErrorKind::Other { description }));
        }
    };

    Ok(cargo_toml)
}

pub fn get_project_location() -> Result<PathBuf> {
    let output = Command::new("cargo")
        .arg("locate-project")
        .output()
        .context(ErrorKind::InvalidCommand {
            description: String::from("Can't execute the `cargo locate-project` command."),
        })?;

    let response =
        String::from_utf8(output.stdout.clone()).with_context(|err| ErrorKind::Utf8 {
            value: output.stdout,
            index: err.clone().utf8_error().valid_up_to(),
        })?;

    let json = Json::from_str(&response).context(ErrorKind::Other {
        description: String::from(
            "Can't parse a response from the `cargo locate-project` command.",
        ),
    })?;
    let cargo_toml_path = json["root"].as_string().unwrap_or("").to_string();
    let project_location = Path::new(&cargo_toml_path)
        .parent()
        .expect("An attempt to get a parent for the root directory.");

    Ok(project_location.to_path_buf())
}