wasm_js/
lockfile.rs

1//! Reading Cargo.lock lock file.
2
3use std::fs;
4use std::path::PathBuf;
5
6use anyhow::{anyhow, bail, Context, Result};
7use console::style;
8use toml;
9
10use crate::manifest::CrateData;
11
12/// This struct represents the contents of `Cargo.lock`.
13#[derive(Clone, Debug, Deserialize)]
14pub struct Lockfile {
15    package: Vec<Package>,
16}
17
18/// This struct represents a single package entry in `Cargo.lock`
19#[derive(Clone, Debug, Deserialize)]
20struct Package {
21    name: String,
22    version: String,
23}
24
25impl Lockfile {
26    /// Read the `Cargo.lock` file for the crate at the given path.
27    pub fn new(crate_data: &CrateData) -> Result<Lockfile> {
28        let lock_path = get_lockfile_path(crate_data)?;
29        let lockfile = fs::read_to_string(&lock_path)
30            .with_context(|| anyhow!("failed to read: {}", lock_path.display()))?;
31        let lockfile = toml::from_str(&lockfile)
32            .with_context(|| anyhow!("failed to parse: {}", lock_path.display()))?;
33        Ok(lockfile)
34    }
35
36    /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
37    pub fn wasm_bindgen_version(&self) -> Option<&str> {
38        self.get_package_version("wasm-bindgen")
39    }
40
41    /// Like `wasm_bindgen_version`, except it returns an error instead of
42    /// `None`.
43    pub fn require_wasm_bindgen(&self) -> Result<&str> {
44        self.wasm_bindgen_version().ok_or_else(|| {
45            anyhow!(
46                "Ensure that you have \"{}\" as a dependency in your Cargo.toml file:\n\
47                 [dependencies]\n\
48                 wasm-bindgen = \"0.2\"",
49                style("wasm-bindgen").bold().dim(),
50            )
51        })
52    }
53
54    /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
55    pub fn wasm_bindgen_test_version(&self) -> Option<&str> {
56        self.get_package_version("wasm-bindgen-test")
57    }
58
59    fn get_package_version(&self, package: &str) -> Option<&str> {
60        self.package
61            .iter()
62            .find(|p| p.name == package)
63            .map(|p| &p.version[..])
64    }
65}
66
67/// Given the path to the crate that we are building, return a `PathBuf`
68/// containing the location of the lock file, by finding the workspace root.
69fn get_lockfile_path(crate_data: &CrateData) -> Result<PathBuf> {
70    // Check that a lock file can be found in the directory. Return an error
71    // if it cannot, otherwise return the path buffer.
72    let lockfile_path = crate_data.workspace_root().join("Cargo.lock");
73    if !lockfile_path.is_file() {
74        bail!("Could not find lockfile at {:?}", lockfile_path)
75    } else {
76        Ok(lockfile_path)
77    }
78}