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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! # crate_installer
//!
//! Installs crates via rustup/cargo.
//!

#[cfg(test)]
#[path = "crate_installer_test.rs"]
mod crate_installer_test;

use crate::command;
use crate::installer::crate_version_check;
use crate::installer::{cargo_plugin_installer, rustup_component_installer};
use crate::toolchain::wrap_command;
use crate::types::{CommandSpec, InstallCrateInfo, InstallRustupComponentInfo, ToolchainSpecifier};

fn invoke_rustup_install(toolchain: &Option<ToolchainSpecifier>, info: &InstallCrateInfo) -> bool {
    match info.rustup_component_name {
        Some(ref component) => {
            let rustup_component_info = InstallRustupComponentInfo {
                rustup_component_name: component.to_string(),
                binary: Some(info.binary.clone()),
                test_arg: Some(info.test_arg.clone()),
            };
            rustup_component_installer::invoke_rustup_install(&toolchain, &rustup_component_info)
        }
        None => false,
    }
}

fn invoke_cargo_install(
    toolchain: &Option<ToolchainSpecifier>,
    info: &InstallCrateInfo,
    args: &Option<Vec<String>>,
    validate: bool,
) {
    let (automatic_lock_version, version_option) = if info.min_version.is_some() {
        (false, &info.min_version)
    } else {
        (info.version.is_some(), &info.version)
    };

    let remove_lock =
        if automatic_lock_version && !envmnt::is("CARGO_MAKE_CRATE_INSTALLATION_LOCKED") {
            envmnt::set_bool("CARGO_MAKE_CRATE_INSTALLATION_LOCKED", true);
            true
        } else {
            false
        };

    let install_args = cargo_plugin_installer::get_install_crate_args(
        &info.crate_name,
        info.force.unwrap_or(true),
        &args,
        version_option,
        &info.install_command,
    );

    let command_spec = match toolchain {
        Some(ref toolchain_string) => wrap_command(toolchain_string, "cargo", &Some(install_args)),
        None => CommandSpec {
            command: "cargo".to_string(),
            args: Some(install_args),
        },
    };

    command::run_command(&command_spec.command, &command_spec.args, validate);

    if remove_lock {
        envmnt::remove("CARGO_MAKE_CRATE_INSTALLATION_LOCKED");
    }
}

fn is_crate_only_info(info: &InstallCrateInfo) -> bool {
    match info.rustup_component_name {
        Some(_) => false,
        None => true,
    }
}

pub(crate) fn install(
    toolchain: &Option<ToolchainSpecifier>,
    info: &InstallCrateInfo,
    args: &Option<Vec<String>>,
    validate: bool,
) {
    let installed =
        rustup_component_installer::is_installed(&toolchain, &info.binary, &info.test_arg);
    let crate_only_info = is_crate_only_info(&info);
    let run_installation = if !installed {
        true
    } else if crate_only_info && toolchain.is_none() {
        match info.min_version {
            Some(ref version) => !crate_version_check::is_min_version_valid(
                &info.crate_name,
                version,
                Some(&info.binary),
            ),
            None => match info.version {
                Some(ref version) => !crate_version_check::is_version_valid(
                    &info.crate_name,
                    version,
                    Some(&info.binary),
                ),
                None => false,
            },
        }
    } else {
        false
    };

    if run_installation {
        debug!("Crate: {} not installed.", &info.crate_name);

        if !invoke_rustup_install(&toolchain, &info) {
            invoke_cargo_install(&toolchain, &info, &args, validate);
        }
    }
}