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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Reading Cargo.lock lock file.

#![allow(clippy::new_ret_no_self)]

use std::fs;
use std::path::PathBuf;

use console::style;
use failure::{Error, ResultExt};
use manifest::CrateData;
use toml;

/// This struct represents the contents of `Cargo.lock`.
#[derive(Clone, Debug, Deserialize)]
pub struct Lockfile {
    package: Vec<Package>,
}

/// This struct represents a single package entry in `Cargo.lock`
#[derive(Clone, Debug, Deserialize)]
struct Package {
    name: String,
    version: String,
}

impl Lockfile {
    /// Read the `Cargo.lock` file for the crate at the given path.
    pub fn new(crate_data: &CrateData) -> Result<Lockfile, Error> {
        let lock_path = get_lockfile_path(crate_data)?;
        let lockfile = fs::read_to_string(&lock_path)
            .with_context(|_| format!("failed to read: {}", lock_path.display()))?;
        let lockfile = toml::from_str(&lockfile)
            .with_context(|_| format!("failed to parse: {}", lock_path.display()))?;
        Ok(lockfile)
    }

    /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
    pub fn wasm_bindgen_version(&self) -> Option<&str> {
        self.get_package_version("wasm-bindgen")
    }

    /// Like `wasm_bindgen_version`, except it returns an error instead of
    /// `None`.
    pub fn require_wasm_bindgen(&self) -> Result<&str, Error> {
        self.wasm_bindgen_version().ok_or_else(|| {
            format_err!(
                "Ensure that you have \"{}\" as a dependency in your Cargo.toml file:\n\
                 [dependencies]\n\
                 wasm-bindgen = \"0.2\"",
                style("wasm-bindgen").bold().dim(),
            )
        })
    }

    /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
    pub fn wasm_bindgen_test_version(&self) -> Option<&str> {
        self.get_package_version("wasm-bindgen-test")
    }

    fn get_package_version(&self, package: &str) -> Option<&str> {
        self.package
            .iter()
            .find(|p| p.name == package)
            .map(|p| &p.version[..])
    }
}

/// Given the path to the crate that we are buliding, return a `PathBuf`
/// containing the location of the lock file, by finding the workspace root.
fn get_lockfile_path(crate_data: &CrateData) -> Result<PathBuf, Error> {
    // Check that a lock file can be found in the directory. Return an error
    // if it cannot, otherwise return the path buffer.
    let lockfile_path = crate_data.workspace_root().join("Cargo.lock");
    if !lockfile_path.is_file() {
        bail!("Could not find lockfile at {:?}", lockfile_path)
    } else {
        Ok(lockfile_path)
    }
}