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
//! Cargo.lock-related utilities

use rustsec::{Error, ErrorKind};
use std::{
    path::{Path, PathBuf},
    process::Command,
};

/// Name of `Cargo.lock`
const CARGO_LOCK_FILE: &str = "Cargo.lock";

/// Tries to locate the lockfile at the specified file path. If it's missing, tries to generate it from `Cargo.toml`.
/// Defaults to `Cargo.lock` in the current directory if passed `None` as the path.
pub fn locate_or_generate(maybe_lockfile_path: Option<&Path>) -> rustsec::Result<PathBuf> {
    match maybe_lockfile_path {
        Some(p) => Ok(p.into()),
        None => {
            let path = Path::new(CARGO_LOCK_FILE);
            if !path.exists() && Path::new("Cargo.toml").exists() {
                generate()?;
            }
            Ok(path.into())
        }
    }
}

/// Run `cargo generate-lockfile`
pub fn generate() -> rustsec::Result<()> {
    let status = Command::new("cargo").arg("generate-lockfile").status();

    if let Err(e) = status {
        return Err(Error::new(
            ErrorKind::Io,
            &format!("couldn't run `cargo generate-lockfile`: {}", e),
        ));
    }
    let status = status.unwrap();

    if !status.success() {
        let msg = match status.code() {
            Some(code) => format!(
                "non-zero exit status running `cargo generate-lockfile`: {}",
                code
            ),
            _ => "no exit status running `cargo generate-lockfile`!".to_string(),
        };

        return Err(Error::new(ErrorKind::Io, &msg));
    }
    Ok(())
}