main.rs: changed command match err output to HopError

This commit is contained in:
Emma Tebibyte 2023-03-27 00:44:35 -04:00
parent 7eb530c9b0
commit 34993ceb13
Signed by: emma
GPG Key ID: 6D661C738815E7DD
3 changed files with 246 additions and 238 deletions

View File

@ -24,153 +24,163 @@ use std::{ collections::HashMap, fmt };
#[derive(Deserialize, Debug)]
pub struct SearchResponse {
pub hits: Vec<ModResult>,
pub offset: isize,
pub limit: isize,
pub total_hits: isize,
pub hits: Vec<ModResult>,
pub offset: isize,
pub limit: isize,
pub total_hits: isize,
}
#[derive(Deserialize, Debug)]
pub struct ModResult {
pub slug: String,
pub title: String,
pub description: String,
pub categories: Vec<String>,
pub display_categories: Vec<String>, // NOTE this is not in the OpenAPI docs
pub client_side: String,
pub server_side: String,
pub project_type: String, // NOTE this isn't in all search results?
pub downloads: isize,
pub icon_url: String,
pub project_id: String, // TODO parse to 'local-xxxx' with regex
pub author: String,
pub versions: Vec<String>,
pub follows: isize,
pub date_created: String,
pub date_modified: String,
pub latest_version: String,
pub license: String,
pub gallery: Vec<String>,
pub slug: String,
pub title: String,
pub description: String,
pub categories: Vec<String>,
// NOTE this is not in the OpenAPI docs
pub display_categories: Vec<String>,
pub client_side: String,
pub server_side: String,
// NOTE this isn't in all search results?
pub project_type: String,
pub downloads: isize,
pub icon_url: String,
// TODO parse to 'local-xxxx' with regex
pub project_id: String,
pub author: String,
pub versions: Vec<String>,
pub follows: isize,
pub date_created: String,
pub date_modified: String,
pub latest_version: String,
pub license: String,
pub gallery: Vec<String>,
}
impl ModResult {
pub fn format_info(&self) -> String {
let title = style(self.title.clone()).bold();
let downloads = style(self.downloads.clone()).bold().green();
if let Some(latest_release) = self.versions.last() {
// TODO fetch version numbers to display
let latest_release = style(latest_release).bold().blue();
format!("{} [{}] ({} downloads)", title, latest_release, downloads)
} else {
format!("{} [no releases]", title)
}
}
pub fn format_info(&self) -> String {
let title = style(self.title.clone()).bold();
let downloads = style(self.downloads.clone()).bold().green();
if let Some(latest_release) = self.versions.last() {
// TODO fetch version numbers to display
let latest_release = style(latest_release).bold().blue();
format!("{} [{}] ({} downloads)", title, latest_release, downloads)
} else {
format!("{} [no releases]", title)
}
}
pub fn format_description(&self) -> String {
self.description.to_owned()
}
pub fn format_description(&self) -> String {
self.description.to_owned()
}
pub fn display(&self, index: usize) {
let index = style(index).magenta();
let info = self.format_info();
let description = self.format_description();
println!("{:>2} {}\n {}", index, info, description);
}
pub fn display(&self, index: usize) {
let index = style(index).magenta();
let info = self.format_info();
let description = self.format_description();
println!("{:>2} {}\n {}", index, info, description);
}
}
#[derive(Deserialize, Debug)]
pub struct ModInfo {
pub slug: String,
pub title: String,
pub description: String,
pub categories: Vec<String>,
pub additional_categories: Vec<String>, // NOTE not listed in OpenAPI docs
pub client_side: String, // TODO serialize as enum
pub server_side: String, // TODO serialize as enum
pub body: String,
pub issues_url: Option<String>,
pub source_url: Option<String>,
pub wiki_url: Option<String>,
pub discord_url: Option<String>,
pub donation_urls: Option<Vec<DonationLink>>,
pub project_type: String,
pub downloads: isize,
pub icon_url: Option<String>,
pub id: String, // TODO serialize mod id?
pub team: String, // TODO serialize team id?
pub body_url: Option<String>, // NOTE deprecated
pub moderator_message: Option<String>,
pub published: String, // TODO serialize as datetime
pub updated: String, // TODO serialize as datetime
pub approved: Option<String>, // NOTE not listed in OpenAPI docs, TODO serialize as datetime
pub followers: isize,
pub status: String,
pub license: License,
pub versions: Vec<String>,
pub gallery: Option<Vec<GalleryEntry>>,
pub slug: String,
pub title: String,
pub description: String,
pub categories: Vec<String>,
pub additional_categories: Vec<String>, // NOTE not listed in OpenAPI docs
pub client_side: String, // TODO serialize as enum
pub server_side: String, // TODO serialize as enum
pub body: String,
pub issues_url: Option<String>,
pub source_url: Option<String>,
pub wiki_url: Option<String>,
pub discord_url: Option<String>,
pub donation_urls: Option<Vec<DonationLink>>,
pub project_type: String,
pub downloads: isize,
pub icon_url: Option<String>,
pub id: String, // TODO serialize mod id?
pub team: String, // TODO serialize team id?
pub body_url: Option<String>, // NOTE deprecated
pub moderator_message: Option<String>,
pub published: String, // TODO serialize as datetime
pub updated: String, // TODO serialize as datetime
// NOTE not listed in OpenAPI docs, TODO serialize as datetime
pub approved: Option<String>,
pub followers: isize,
pub status: String,
pub license: License,
pub versions: Vec<String>,
pub gallery: Option<Vec<GalleryEntry>>,
}
#[derive(Deserialize, Debug)]
pub struct GalleryEntry {
pub url: String,
pub featured: bool,
pub title: String,
pub description: String,
pub created: String,
pub url: String,
pub featured: bool,
pub title: String,
pub description: String,
pub created: String,
}
#[derive(Deserialize, Debug)]
pub struct License {
pub id: String,
pub name: String,
pub url: String,
pub id: String,
pub name: String,
pub url: String,
}
#[derive(Deserialize, Debug)]
pub struct DonationLink {
pub id: String,
pub platform: String,
pub url: String,
pub id: String,
pub platform: String,
pub url: String,
}
#[derive(Deserialize, Debug)]
pub struct ModVersion {
pub name: String,
pub version_number: String,
pub changelog: Option<String>,
// pub dependencies: Option<Vec<String>>, // TODO dependency wrangling, thank you modrinth, very cool
pub game_versions: Vec<String>,
pub version_type: String, // TODO {alpha | beta | release}
pub loaders: Vec<String>,
pub featured: bool,
pub id: String, // version id
pub project_id: String, // mod id
pub author_id: String, // user id
pub date_published: String, // TODO serialize datetime
pub downloads: isize,
pub changelog_url: Option<String>, // NOTE deprecated
pub files: Vec<ModVersionFile>,
pub name: String,
pub version_number: String,
pub changelog: Option<String>,
// TODO dependency wrangling, thank you modrinth, very cool
// pub dependencies: Option<Vec<String>>,
pub game_versions: Vec<String>,
pub version_type: String, // TODO {alpha | beta | release}
pub loaders: Vec<String>,
pub featured: bool,
pub id: String, // version id
pub project_id: String, // mod id
pub author_id: String, // user id
pub date_published: String, // TODO serialize datetime
pub downloads: isize,
pub changelog_url: Option<String>, // NOTE deprecated
pub files: Vec<ModVersionFile>,
}
#[derive(Deserialize, Debug)]
pub struct ModVersionFile {
pub hashes: HashMap<String, String>,
pub url: String,
pub filename: String,
pub primary: bool,
pub size: isize,
pub hashes: HashMap<String, String>,
pub url: String,
pub filename: String,
pub primary: bool,
pub size: isize,
}
#[derive(Deserialize, Debug)]
pub struct Error {
pub error: String,
pub description: String,
pub error: String,
pub description: String,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.error, self.description)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.error, self.description)
}
}
impl std::error::Error for Error {}

View File

@ -19,8 +19,8 @@
*/
use core::{
fmt,
str::FromStr,
fmt,
str::FromStr,
};
pub use arg::Args;
@ -28,137 +28,137 @@ use yacexits::EX_DATAERR;
#[derive(Args, Debug)]
pub struct Arguments {
pub argv0: String,
pub argv0: String,
#[arg(short = "v")]
pub v: Option<bool>,
#[arg(sub)]
pub sub: Command,
#[arg(short = "v")]
pub v: Option<bool>,
#[arg(sub)]
pub sub: Command,
}
#[derive(Args, Debug)]
pub enum Command {
Add(AddArgs),
Get(SearchArgs),
Init(InitArgs),
List(HopArgs),
Remove(RmArgs),
Update(HopArgs),
Add(AddArgs),
Get(SearchArgs),
Init(InitArgs),
List(HopArgs),
Remove(RmArgs),
Update(HopArgs),
}
#[derive(Args, Debug)]
pub struct AddArgs {
#[arg(short = "m")]
pub mc_version: String,
#[arg(short = "m")]
pub mc_version: String,
#[arg(short = "f")]
pub hopfiles: Vec<String>,
#[arg(short = "f")]
pub hopfiles: Vec<String>,
pub package_names: Vec<String>,
pub package_names: Vec<String>,
}
#[derive(Args, Debug)]
pub struct HopArgs {
#[arg(short = "f")]
pub hopfile: Vec<String>,
#[arg(short = "f")]
pub hopfile: Vec<String>,
#[arg(short = "m")]
pub mc_version: Vec<String>,
#[arg(short = "m")]
pub mc_version: Vec<String>,
#[arg(short = "t")]
pub package_type: Option<PackageType>,
#[arg(short = "t")]
pub package_type: Option<PackageType>,
}
#[derive(Args, Debug)]
pub struct InitArgs {
#[arg(short = "f")]
pub template: Option<String>,
#[arg(short = "f")]
pub template: Option<String>,
pub mc_version: String,
pub package_type: PackageType,
pub mc_version: String,
pub package_type: PackageType,
}
#[derive(Args, Debug)]
pub struct RmArgs {
#[arg(short = "f")]
pub hopfile: Option<String>,
#[arg(short = "f")]
pub hopfile: Option<String>,
pub package_type: PackageType,
pub package_type: PackageType,
pub mc_version: String,
pub package_names: Vec<String>,
pub mc_version: String,
pub package_names: Vec<String>,
}
#[derive(Args, Debug)]
pub struct SearchArgs {
#[arg(short = "n")]
pub no_confirm: bool,
#[arg(short = "n")]
pub no_confirm: bool,
/// Overrides the download directory
#[arg(short = "d")]
pub dir: Option<String>,
/// Overrides the download directory
#[arg(short = "d")]
pub dir: Option<String>,
/// Restricts the target Minecraft version
#[arg(short = "m")]
pub mc_version: Vec<String>,
/// Restricts the target Minecraft version
#[arg(short = "m")]
pub mc_version: Vec<String>,
/// Type of package to use
#[arg(short = "t")]
pub package_type: PackageType,
/// Type of package to use
#[arg(short = "t")]
pub package_type: PackageType,
pub package_name: String,
pub package_name: String,
}
#[derive(Clone, Copy, Debug)]
pub enum PackageType {
Dummy,
Mod(Loader),
Pack(Loader),
Plugin(Server),
ResourcePack,
Dummy,
Mod(Loader),
Pack(Loader),
Plugin(Server),
ResourcePack,
}
#[derive(Clone, Copy, Debug)]
pub enum Loader {
Fabric,
Forge,
Quilt,
Fabric,
Forge,
Quilt,
}
#[derive(Clone, Copy, Debug)]
pub enum Server {
Bukkit,
Paper,
Purpur,
Spigot,
Sponge,
Bukkit,
Paper,
Purpur,
Spigot,
Sponge,
}
impl fmt::Display for Command {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Command::Add(_) => write!(f, "add"),
Command::Get(_) => write!(f, "get"),
Command::Init(_) => write!(f, "init"),
Command::List(_) => write!(f, "list"),
Command::Remove(_) => write!(f, "remove"),
Command::Update(_) => write!(f, "update"),
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Command::Add(_) => write!(f, "add"),
Command::Get(_) => write!(f, "get"),
Command::Init(_) => write!(f, "init"),
Command::List(_) => write!(f, "list"),
Command::Remove(_) => write!(f, "remove"),
Command::Update(_) => write!(f, "update"),
}
}
}
#[derive(Clone, Debug)]
pub enum PackageParseError {
Invalid(String),
Invalid(String),
}
impl std::default::Default for PackageType { //TODO: Actually implement Default
fn default() -> Self { // for PackageType
PackageType::Dummy
}
impl std::default::Default for PackageType { // TODO: Actually implement Default
fn default() -> Self { // for PackageType
PackageType::Dummy
}
}
impl From<PackageParseError> for (String, u32) {
@ -170,43 +170,43 @@ impl From<PackageParseError> for (String, u32) {
}
impl FromStr for PackageType {
type Err = PackageParseError;
fn from_str(s: &str) -> Result<PackageType, PackageParseError> {
let pieces: Vec<&str> = s.split("-").collect();
type Err = PackageParseError;
fn from_str(s: &str) -> Result<PackageType, PackageParseError> {
let pieces: Vec<&str> = s.split("-").collect();
if pieces.len() > 2 || pieces.len() == 1 {
return Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", s)
));
}
if pieces.len() > 2 || pieces.len() == 1 {
return Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", s)
));
}
let (prefix, postfix) = (pieces[0], pieces[1]);
let (prefix, postfix) = (pieces[0], pieces[1]);
let loader = match prefix {
"bukkit" => return Ok(PackageType::Plugin(Server::Bukkit)),
"fabric" => Loader::Fabric,
"forge" => Loader::Forge,
"paper" => return Ok(PackageType::Plugin(Server::Paper)),
"purpur" => return Ok(PackageType::Plugin(Server::Purpur)),
"quilt" => Loader::Quilt,
"resource" => return Ok(PackageType::ResourcePack),
"spigot" => return Ok(PackageType::Plugin(Server::Spigot)),
"sponge" => return Ok(PackageType::Plugin(Server::Sponge)),
_ => {
return Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", prefix)
))
},
};
let loader = match prefix {
"bukkit" => return Ok(PackageType::Plugin(Server::Bukkit)),
"fabric" => Loader::Fabric,
"forge" => Loader::Forge,
"paper" => return Ok(PackageType::Plugin(Server::Paper)),
"purpur" => return Ok(PackageType::Plugin(Server::Purpur)),
"quilt" => Loader::Quilt,
"resource" => return Ok(PackageType::ResourcePack),
"spigot" => return Ok(PackageType::Plugin(Server::Spigot)),
"sponge" => return Ok(PackageType::Plugin(Server::Sponge)),
_ => {
return Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", prefix)
))
},
};
match postfix {
"mod" => Ok(PackageType::Mod(loader)),
"pack" => Ok(PackageType::Pack(loader)),
_ => {
Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", postfix)
))
},
}
}
match postfix {
"mod" => Ok(PackageType::Mod(loader)),
"pack" => Ok(PackageType::Pack(loader)),
_ => {
Err(PackageParseError::Invalid(
format!("{}: Invalid package type.", postfix)
))
},
}
}
}

View File

@ -38,40 +38,38 @@ use error::*;
use yacexits::{
exit,
EX_OSERR,
EX_SOFTWARE,
EX_SOFTWARE,
};
struct AppContext {
args: Arguments,
config: Config,
args: Arguments,
config: Config,
}
#[tokio::main]
#[no_mangle]
async fn rust_main(arguments: yacexits::Args) -> Result<u32, (String, u32)> {
let argv: Vec<&str> = arguments.into_iter().collect();
let argv: Vec<&str> = arguments.into_iter().collect();
let args = match Arguments::from_args(argv.clone().into_iter()) {
let args = match Arguments::from_args(argv.clone().into_iter()) {
Ok(args) => args,
Err(_) => {
return Err((format!("Unable to ascertain arguments."), EX_OSERR));
}
};
let config = Config::read_config()?;
let ctx = AppContext { args, config };
let config = Config::read_config()?;
let ctx = AppContext { args, config };
match ctx.args.sub {
// Command::Get(search_args) => cmd_get(&ctx, search_args).await,
// Command::Init(hopfile_args) => cmd_init(hopfile_args).await,
_ => {
return Err((
format!(
"{}: Unimplemented subcommand.",
ctx.args.sub
),
EX_SOFTWARE,
));
},
};
match ctx.args.sub {
// Command::Get(search_args) => cmd_get(&ctx, search_args).await,
// Command::Init(hopfile_args) => cmd_init(hopfile_args).await,
_ => {
let message = format!(
"{}: Unimplemented subcommand.", ctx.args.sub
);
let code = EX_SOFTWARE;
Err(HopError { message, code })
},
}?
}