wasm_pack/
lockfile.rs

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