use std::collections::{BTreeSet, HashMap};
use crate::{Creeper, Id, cmd::Execute, index::VersionRev};
use anyhow::ensure;
use clap::Parser;
use colored::Colorize;
use indexmap::IndexMap;
use semver::Version;
use stop::fatal;
use url::Url;
#[derive(Clone, Debug, Parser)]
pub enum Tool {
LoadInst(LoadInst),
FetchManifest(FetchManifest),
FetchMcVersion(FetchMcVersion),
Resolve(Resolve),
GetPackage(GetPackage),
ListNeoforgeVersion(ListNeoforgeVersion),
GetInstall(GetInstall),
GetUserInstall(GetUserInstall),
DiscoverYggdrasil(DiscoverYggdrasil),
}
impl Execute for Tool {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
match self {
Tool::LoadInst(load_inst) => lib.execute(load_inst).await,
Tool::FetchManifest(fetch_manifest) => lib.execute(fetch_manifest).await,
Tool::FetchMcVersion(fetch_mc_version) => lib.execute(fetch_mc_version).await,
Tool::Resolve(resolve) => lib.execute(resolve).await,
Tool::GetPackage(get_package) => lib.execute(get_package).await,
Tool::ListNeoforgeVersion(list_neoforge_version) => {
lib.execute(list_neoforge_version).await
}
Tool::GetInstall(get_install) => lib.execute(get_install).await,
Tool::GetUserInstall(get_user_install) => lib.execute(get_user_install).await,
Tool::DiscoverYggdrasil(discover_yggdrasil) => lib.execute(discover_yggdrasil).await,
}
}
}
#[derive(Clone, Debug, Parser)]
pub struct LoadInst;
impl Execute for LoadInst {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let inst = lib.game.pack().await?;
let toml = toml::to_string_pretty(&inst)?;
println!("{toml}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct FetchManifest;
impl Execute for FetchManifest {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let manifest = lib.vanilla_manifest().await?;
let json = serde_json::to_string(manifest)?;
println!("{json}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct FetchMcVersion {
#[arg(value_name = "VERSION")]
version: Version,
}
impl Execute for FetchMcVersion {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let mc_version = lib.vanilla_version(self.version).await?;
let json = serde_json::to_string(&mc_version)?;
println!("{json}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct Resolve {
#[arg(long)]
pub req: Vec<String>,
#[arg(long)]
pub sort: bool,
}
impl Execute for Resolve {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let mut req = HashMap::new();
for s in self.req {
let parts = s.split("@").collect::<Vec<_>>();
if parts.len() != 2 {
fatal!(
"invalid requirement {}, expected <package>@<version-req>",
s
);
}
req.insert(parts[0].parse()?, parts[1].parse()?);
}
lib.update_all().await?;
let sol = match lib.resolve(req) {
Ok(x) => x,
Err(e) => {
fatal!("dependency resolution failed: {}", e);
}
};
eprintln!("{} {} packages", "Resolved".bold().green(), sol.len());
if self.sort {
let sorted = lib.sort_dependency(sol)?;
let mut map = IndexMap::new();
for (k, v) in sorted {
map.insert(k, v);
}
eprintln!(
"{} {} packages (from dependencies to dependents)",
"Sorted".bold().green(),
map.len()
);
println!("{}", toml::to_string_pretty(&map)?);
return Ok(());
};
println!("{}", toml::to_string_pretty(&sol)?);
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct GetPackage {
#[arg(value_name = "PACKAGE")]
pub package: String,
#[arg(long, default_value_t = 0)]
pub rev: u32,
}
impl Execute for GetPackage {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let pieces = self.package.split('@').collect::<Vec<_>>();
ensure!(
pieces.len() == 2,
"invalid package version {}, expected <id>@<version>",
self.package
);
let (id, version) = (pieces[0].parse()?, pieces[1].parse()?);
let package = lib.query_registry(&id, &version, self.rev).await?;
let toml = toml::to_string_pretty(&package)?;
println!("{toml}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct GetInstall {
#[arg(value_name = "PACKAGE")]
pub package: String,
#[arg(long, default_value_t = 0)]
pub rev: u32,
#[arg(short, long, default_value_t = false)]
pub recursive: bool,
}
impl Execute for GetInstall {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let pieces = self.package.split('@').collect::<Vec<_>>();
ensure!(
pieces.len() == 2,
"invalid package version {}, expected <id>@<version>",
self.package
);
let (id, version) = (pieces[0].parse()?, pieces[1].parse()?);
let install = if self.recursive {
let package = lib.query_registry(&id, &version, 0).await?;
lib.recursive_install(package).await?
} else {
lib.install(&id, version).await?
};
let json = serde_json::to_string(&install)?;
println!("{json}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct ListNeoforgeVersion;
impl Execute for ListNeoforgeVersion {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let index = lib.blocking_get_index(&Id::neoforge())?;
let versions = index
.into_keys()
.map(|VersionRev(version, _rev)| version)
.collect::<BTreeSet<_>>();
let json = serde_json::to_string(&versions)?;
println!("{json}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct GetUserInstall;
impl Execute for GetUserInstall {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let install = lib.user_install().await?;
let json = serde_json::to_string(&install)?;
println!("{json}");
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
pub struct DiscoverYggdrasil {
#[arg(value_name = "URL")]
pub url: Url,
}
impl Execute for DiscoverYggdrasil {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
let url = lib.user.discover_yggdrasil(self.url).await?;
println!("{url}");
Ok(())
}
}