1 use crate::command_prelude::*;
2 
3 use cargo::core::{GitReference, SourceId};
4 use cargo::ops;
5 use cargo::util::IntoUrl;
6 
cli() -> App7 pub fn cli() -> App {
8     subcommand("install")
9         .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
10         .arg(opt("quiet", "Do not print cargo log messages").short("q"))
11         .arg(Arg::with_name("crate").empty_values(false).multiple(true))
12         .arg(
13             opt("version", "Specify a version to install")
14                 .alias("vers")
15                 .value_name("VERSION")
16                 .requires("crate"),
17         )
18         .arg(
19             opt("git", "Git URL to install the specified crate from")
20                 .value_name("URL")
21                 .conflicts_with_all(&["path", "index", "registry"]),
22         )
23         .arg(
24             opt("branch", "Branch to use when installing from git")
25                 .value_name("BRANCH")
26                 .requires("git"),
27         )
28         .arg(
29             opt("tag", "Tag to use when installing from git")
30                 .value_name("TAG")
31                 .requires("git"),
32         )
33         .arg(
34             opt("rev", "Specific commit to use when installing from git")
35                 .value_name("SHA")
36                 .requires("git"),
37         )
38         .arg(
39             opt("path", "Filesystem path to local crate to install")
40                 .value_name("PATH")
41                 .conflicts_with_all(&["git", "index", "registry"]),
42         )
43         .arg(opt(
44             "list",
45             "list all installed packages and their versions",
46         ))
47         .arg_jobs()
48         .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
49         .arg(opt("no-track", "Do not save tracking information"))
50         .arg_features()
51         .arg_profile("Install artifacts with the specified profile")
52         .arg(opt("debug", "Build in debug mode instead of release mode"))
53         .arg_targets_bins_examples(
54             "Install only the specified binary",
55             "Install all binaries",
56             "Install only the specified example",
57             "Install all examples",
58         )
59         .arg_target_triple("Build for the target triple")
60         .arg_target_dir()
61         .arg(opt("root", "Directory to install packages into").value_name("DIR"))
62         .arg(
63             opt("index", "Registry index to install from")
64                 .value_name("INDEX")
65                 .requires("crate")
66                 .conflicts_with_all(&["git", "path", "registry"]),
67         )
68         .arg(
69             opt("registry", "Registry to use")
70                 .value_name("REGISTRY")
71                 .requires("crate")
72                 .conflicts_with_all(&["git", "path", "index"]),
73         )
74         .arg_message_format()
75         .after_help("Run `cargo help install` for more detailed information.\n")
76 }
77 
exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult78 pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
79     if let Some(path) = args.value_of_path("path", config) {
80         config.reload_rooted_at(path)?;
81     } else {
82         // TODO: Consider calling set_search_stop_path(home).
83         config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
84     }
85 
86     let krates = args
87         .values_of("crate")
88         .unwrap_or_default()
89         .collect::<Vec<_>>();
90 
91     let mut from_cwd = false;
92 
93     let source = if let Some(url) = args.value_of("git") {
94         let url = url.into_url()?;
95         let gitref = if let Some(branch) = args.value_of("branch") {
96             GitReference::Branch(branch.to_string())
97         } else if let Some(tag) = args.value_of("tag") {
98             GitReference::Tag(tag.to_string())
99         } else if let Some(rev) = args.value_of("rev") {
100             GitReference::Rev(rev.to_string())
101         } else {
102             GitReference::DefaultBranch
103         };
104         SourceId::for_git(&url, gitref)?
105     } else if let Some(path) = args.value_of_path("path", config) {
106         SourceId::for_path(&path)?
107     } else if krates.is_empty() {
108         from_cwd = true;
109         SourceId::for_path(config.cwd())?
110     } else if let Some(registry) = args.registry(config)? {
111         SourceId::alt_registry(config, &registry)?
112     } else if let Some(index) = args.value_of("index") {
113         SourceId::for_registry(&index.into_url()?)?
114     } else {
115         SourceId::crates_io(config)?
116     };
117 
118     let version = args.value_of("version");
119     let root = args.value_of("root");
120 
121     // We only provide workspace information for local crate installation from
122     // one of the following sources:
123     // - From current working directory (only work for edition 2015).
124     // - From a specific local file path.
125     let workspace = if from_cwd || args.is_present("path") {
126         args.workspace(config).ok()
127     } else {
128         None
129     };
130 
131     let mut compile_opts = args.compile_options(
132         config,
133         CompileMode::Build,
134         workspace.as_ref(),
135         ProfileChecking::Custom,
136     )?;
137 
138     compile_opts.build_config.requested_profile =
139         args.get_profile_name(config, "release", ProfileChecking::Custom)?;
140 
141     if args.is_present("list") {
142         ops::install_list(root, config)?;
143     } else {
144         ops::install(
145             config,
146             root,
147             krates,
148             source,
149             from_cwd,
150             version,
151             &compile_opts,
152             args.is_present("force"),
153             args.is_present("no-track"),
154         )?;
155     }
156     Ok(())
157 }
158