mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-17 09:36:40 +00:00
137 lines
3.6 KiB
Rust
137 lines
3.6 KiB
Rust
//! A very partial unfaithful implementation of cargo's command line.
|
|
//!
|
|
//! This showcases some hairier patterns, like subcommands and custom value parsing.
|
|
|
|
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,
|
|
}
|
|
|
|
// clap has a macro for this: https://docs.rs/clap/2.33.3/clap/macro.arg_enum.html
|
|
// We have to do it manually.
|
|
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
|
|
}
|