1use std::{path::PathBuf, str::FromStr};
6
7const HELP: &str = "cargo [+toolchain] [OPTIONS] [SUBCOMMAND]";
8
9fn main() -> Result<(), lexopt::Error> {
10 use lexopt::prelude::*;
11
12 let mut settings = GlobalSettings {
13 toolchain: "stable".to_owned(),
14 color: Color::Auto,
15 offline: false,
16 quiet: false,
17 verbose: false,
18 };
19
20 let mut parser = lexopt::Parser::from_env();
21 while let Some(arg) = parser.next()? {
22 match arg {
23 Long("color") => {
24 settings.color = parser.value()?.parse()?;
25 }
26 Long("offline") => {
27 settings.offline = true;
28 }
29 Long("quiet") => {
30 settings.quiet = true;
31 settings.verbose = false;
32 }
33 Long("verbose") => {
34 settings.verbose = true;
35 settings.quiet = false;
36 }
37 Long("help") => {
38 println!("{}", HELP);
39 std::process::exit(0);
40 }
41 Value(value) => {
42 let value = value.string()?;
43 match value.as_str() {
44 value if value.starts_with('+') => {
45 settings.toolchain = value[1..].to_owned();
46 }
47 "install" => {
48 return install(settings, parser);
49 }
50 value => {
51 return Err(format!("unknown subcommand '{}'", value).into());
52 }
53 }
54 }
55 _ => return Err(arg.unexpected()),
56 }
57 }
58
59 println!("{}", HELP);
60 Ok(())
61}
62
63#[derive(Debug)]
64struct GlobalSettings {
65 toolchain: String,
66 color: Color,
67 offline: bool,
68 quiet: bool,
69 verbose: bool,
70}
71
72fn install(settings: GlobalSettings, mut parser: lexopt::Parser) -> Result<(), lexopt::Error> {
73 use lexopt::prelude::*;
74
75 let mut package: Option<String> = None;
76 let mut root: Option<PathBuf> = None;
77 let mut jobs: u16 = get_no_of_cpus();
78
79 while let Some(arg) = parser.next()? {
80 match arg {
81 Value(value) if package.is_none() => {
82 package = Some(value.string()?);
83 }
84 Long("root") => {
85 root = Some(parser.value()?.into());
86 }
87 Short('j') | Long("jobs") => {
88 jobs = parser.value()?.parse()?;
89 }
90 Long("help") => {
91 println!("cargo install [OPTIONS] CRATE");
92 std::process::exit(0);
93 }
94 _ => return Err(arg.unexpected()),
95 }
96 }
97
98 println!("Settings: {:#?}", settings);
99 println!(
100 "Installing {} into {:?} with {} jobs",
101 package.ok_or("missing CRATE argument")?,
102 root,
103 jobs
104 );
105
106 Ok(())
107}
108
109#[derive(Debug)]
110enum Color {
111 Auto,
112 Always,
113 Never,
114}
115
116impl FromStr for Color {
119 type Err = String;
120
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 match s.to_lowercase().as_str() {
123 "auto" => Ok(Color::Auto),
124 "always" => Ok(Color::Always),
125 "never" => Ok(Color::Never),
126 _ => Err(format!(
127 "Invalid style '{}' [pick from: auto, always, never]",
128 s
129 )),
130 }
131 }
132}
133
134fn get_no_of_cpus() -> u16 {
135 4
136}