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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::{path::PathBuf, str::FromStr};
const HELP: &str = "cargo [+toolchain] [OPTIONS] [SUBCOMMAND]";
fn main() -> Result<(), lexopt::Error> {
use lexopt::prelude::*;
let mut settings = GlobalSettings {
toolchain: "stable".to_owned(),
color: Color::Auto,
offline: false,
quiet: false,
verbose: false,
};
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Long("color") => {
settings.color = parser.value()?.parse()?;
}
Long("offline") => {
settings.offline = true;
}
Long("quiet") => {
settings.quiet = true;
settings.verbose = false;
}
Long("verbose") => {
settings.verbose = true;
settings.quiet = false;
}
Long("help") => {
println!("{}", HELP);
std::process::exit(0);
}
Value(value) => {
let value = value.string()?;
match value.as_str() {
value if value.starts_with('+') => {
settings.toolchain = value[1..].to_owned();
}
"install" => {
return install(settings, parser);
}
value => {
return Err(format!("unknown subcommand '{}'", value).into());
}
}
}
_ => return Err(arg.unexpected()),
}
}
println!("{}", HELP);
Ok(())
}
#[derive(Debug)]
struct GlobalSettings {
toolchain: String,
color: Color,
offline: bool,
quiet: bool,
verbose: bool,
}
fn install(settings: GlobalSettings, mut parser: lexopt::Parser) -> Result<(), lexopt::Error> {
use lexopt::prelude::*;
let mut package: Option<String> = None;
let mut root: Option<PathBuf> = None;
let mut jobs: u16 = get_no_of_cpus();
while let Some(arg) = parser.next()? {
match arg {
Value(value) if package.is_none() => {
package = Some(value.string()?);
}
Long("root") => {
root = Some(parser.value()?.into());
}
Short('j') | Long("jobs") => {
jobs = parser.value()?.parse()?;
}
Long("help") => {
println!("cargo install [OPTIONS] CRATE");
std::process::exit(0);
}
_ => return Err(arg.unexpected()),
}
}
println!("Settings: {:#?}", settings);
println!(
"Installing {} into {:?} with {} jobs",
package.ok_or("missing CRATE argument")?,
root,
jobs
);
Ok(())
}
#[derive(Debug)]
enum Color {
Auto,
Always,
Never,
}
impl FromStr for Color {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"auto" => Ok(Color::Auto),
"always" => Ok(Color::Always),
"never" => Ok(Color::Never),
_ => Err(format!(
"Invalid style '{}' [pick from: auto, always, never]",
s
)),
}
}
}
fn get_no_of_cpus() -> u16 {
4
}