mod artifact;
mod builtin;
mod checksum;
mod cmd;
mod dev;
mod fabric;
mod game;
mod id;
mod index;
mod install;
mod java;
mod launch;
mod lock;
mod maven;
mod mc;
mod neoforge;
mod pack;
mod path;
mod pbar;
mod prelude;
mod pubgrub;
mod registry;
mod tool;
mod user;
mod util;
mod vanilla;
mod yggdrasil;
mod zip;
use clap::Parser;
use reqwest::Client;
use std::{ops::Deref, path::PathBuf, sync::Arc};
use stop::fatal;
use tokio::runtime;
use tracing::{Level, level_filters::LevelFilter};
use tracing_indicatif::IndicatifLayer;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt};
use url::Url;
use crate::{
artifact::ArtifactManager,
cmd::Execute,
dev::Dev,
fabric::{FabricManager, IntermediaryManager},
game::GameManager,
index::IndexCache,
neoforge::NeoforgeManager,
path::init_creeper_dirs,
registry::Registry,
tool::Tool,
user::UserManager,
vanilla::VanillaManager,
};
pub use prelude::*;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub struct CreeperInner {
pub args: CreeperConfig,
artifact: ArtifactManager,
vanilla: VanillaManager,
http: Client,
registry: Registry,
index_cache: IndexCache,
game: GameManager,
neoforge: NeoforgeManager,
fabric: FabricManager,
intermediary: IntermediaryManager,
user: UserManager,
}
#[derive(Clone)]
pub struct Creeper(Arc<CreeperInner>);
impl Deref for Creeper {
type Target = CreeperInner;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Creeper {
pub async fn new(args: CreeperConfig) -> anyhow::Result<Self> {
init_creeper_dirs().await?;
let http = Client::default();
let registry = Registry::new(args.registry.clone(), http.clone())?;
let game = GameManager::new(args.working_dir.clone());
let neoforge = NeoforgeManager::new(http.clone());
let vanilla = VanillaManager::new(http.clone());
let artifact = ArtifactManager::new(http.clone()).await?;
let user = UserManager::new();
let fabric = FabricManager::new(http.clone());
let intermediary = IntermediaryManager::new(http.clone());
let val = CreeperInner {
args,
artifact,
vanilla,
http,
registry,
index_cache: IndexCache::new(),
neoforge,
game,
user,
fabric,
intermediary,
};
Ok(Self(Arc::new(val)))
}
pub async fn execute(&self, cmd: impl Execute) -> anyhow::Result<()> {
cmd.execute(self).await
}
pub async fn update_all(&self) -> anyhow::Result<()> {
self.update_registry().await?;
self.update_vanilla().await?;
self.update_neoforge().await?;
self.update_fabric().await?;
self.update_intermediary().await?;
Ok(())
}
}
#[derive(Clone, Debug, Parser)]
#[command(version)]
pub struct CreeperConfig {
#[arg(name = "dir", short, long)]
pub working_dir: Option<PathBuf>,
#[arg(long, default_value = "https://creeper-registry.pages.dev/")]
pub registry: Url,
#[arg(long, default_value_t = 4)]
pub parallel_download: usize,
}
pub const CREEPER_TEXT_ART: &str = r#"
🟩🟩🟩⬜⬜🟩🟩🟩
🟩🟩🟩🟩🟩🟩🟩⬜
🟩⬛⬛🟩🟩⬛⬛⬜
🟩⬛⬛🟩🟩⬛⬛🟩
🟩🟩🟩⬛⬛⬜🟩🟩
🟩🟩⬛⬛⬛⬛🟩⬜
⬜🟩⬛⬛⬛⬛🟩🟩
🟩🟩⬛🟩🟩⬛🟩🟩
"#;
#[derive(Clone, Debug, Parser)]
struct Args {
#[clap(flatten)]
cfg: CreeperConfig,
#[arg(name = "loglevel", long, default_value_t = Level::INFO)]
log_level: Level,
#[arg(short, long)]
verbose: bool,
#[arg(short, long)]
noisy: bool,
#[command(subcommand)]
cmd: SubCommand,
}
#[derive(Clone, Debug, Parser)]
enum SubCommand {
#[command(subcommand)]
Tool(Tool),
Add(cmd::Add),
Launch(cmd::Launch),
BuildIndex(cmd::BuildIndex),
Install(cmd::Install),
Nuke(cmd::Nuke),
Login(cmd::Login),
Init(cmd::Init),
#[command(subcommand)]
Dev(Dev),
#[clap(hide = true)]
AwwMan,
}
impl Execute for SubCommand {
async fn execute(self, lib: &Creeper) -> anyhow::Result<()> {
match self {
SubCommand::Tool(tool) => lib.execute(tool).await,
SubCommand::AwwMan => Ok(println!("{CREEPER_TEXT_ART}")),
SubCommand::BuildIndex(build_index) => lib.execute(build_index).await,
SubCommand::Install(install) => lib.execute(install).await,
SubCommand::Launch(launch) => lib.execute(launch).await,
SubCommand::Nuke(nuke) => lib.execute(nuke).await,
SubCommand::Login(login) => lib.execute(login).await,
SubCommand::Init(init) => lib.execute(init).await,
SubCommand::Add(add) => lib.execute(add).await,
SubCommand::Dev(_dev) => todo!(),
}
}
}
fn main() {
let Args {
cfg,
cmd,
log_level,
verbose,
noisy,
} = Args::parse();
let log_level = if noisy {
Level::TRACE
} else if verbose {
Level::DEBUG
} else {
log_level
};
let layer = IndicatifLayer::new();
tracing_subscriber::registry()
.with(LevelFilter::from_level(log_level))
.with(fmt::layer().with_writer(layer.get_stderr_writer()))
.with(layer)
.init();
let run = runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap_or_else(fatal!());
let creeper = run.block_on(Creeper::new(cfg)).unwrap_or_else(fatal!());
run.block_on(creeper.execute(cmd)).unwrap_or_else(fatal!());
}