Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I25581b8de945284b4ce7c2c85601a86f6a6a6964
629 lines
13 KiB
Rust
629 lines
13 KiB
Rust
pub mod commands;
|
|
|
|
use clap::{Args, Parser, Subcommand};
|
|
|
|
use crate::model::{
|
|
enums::{ProjectSide, ProjectType, UpdateStrategy},
|
|
fork::RefType,
|
|
};
|
|
|
|
#[derive(Parser)]
|
|
#[clap(name = "pakker")]
|
|
#[clap(about = "A multiplatform modpack manager for Minecraft", long_about = None)]
|
|
pub struct Cli {
|
|
/// Enable verbose output (-v for info, -vv for debug, -vvv for trace)
|
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
|
pub verbose: u8,
|
|
|
|
#[clap(subcommand)]
|
|
pub command: Commands,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
pub enum Commands {
|
|
/// Initialize a new modpack project
|
|
Init(InitArgs),
|
|
|
|
/// Import an existing modpack
|
|
Import(ImportArgs),
|
|
|
|
/// Add projects to the modpack
|
|
Add(AddArgs),
|
|
|
|
/// Add projects with explicit platform specification (non-interactive)
|
|
#[clap(name = "add-prj", alias = "prj")]
|
|
AddPrj(AddPrjArgs),
|
|
|
|
/// Remove projects from the modpack
|
|
Rm(RmArgs),
|
|
|
|
/// Update projects
|
|
Update(UpdateArgs),
|
|
|
|
/// List projects in the modpack
|
|
Ls(LsArgs),
|
|
|
|
/// Set project properties
|
|
Set(SetArgs),
|
|
|
|
/// Link projects together
|
|
Link(LinkArgs),
|
|
|
|
/// Unlink projects
|
|
Unlink(UnlinkArgs),
|
|
|
|
/// Show differences between local and remote
|
|
Diff(DiffArgs),
|
|
|
|
/// Fetch project files
|
|
Fetch(FetchArgs),
|
|
|
|
/// Sync projects (fetch + update)
|
|
Sync(SyncArgs),
|
|
|
|
/// Export modpack
|
|
Export(ExportArgs),
|
|
|
|
/// Manage remote repositories
|
|
Remote(RemoteArgs),
|
|
|
|
/// Update modpack from remote Git repository
|
|
RemoteUpdate(RemoteUpdateArgs),
|
|
|
|
/// Check for available updates
|
|
Status(StatusArgs),
|
|
|
|
/// Inspect project details
|
|
Inspect(InspectArgs),
|
|
|
|
/// Manage API credentials
|
|
Credentials(CredentialsArgs),
|
|
|
|
/// Configure modpack properties
|
|
Cfg(CfgArgs),
|
|
|
|
/// Manage fork configuration
|
|
Fork(ForkArgs),
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct InitArgs {
|
|
/// Modpack name
|
|
#[clap(short, long)]
|
|
pub name: Option<String>,
|
|
|
|
/// Modpack version
|
|
#[clap(short = 'V', long)]
|
|
pub version: Option<String>,
|
|
|
|
/// Target platform
|
|
#[clap(short, long)]
|
|
pub target: Option<String>,
|
|
|
|
/// Minecraft versions (space-separated)
|
|
#[clap(short, long = "mc-versions", value_delimiter = ' ', num_args = 1..)]
|
|
pub mc_versions: Option<Vec<String>>,
|
|
|
|
/// Mod loaders (format: name=version, can be specified multiple times)
|
|
#[clap(short, long = "loaders", value_delimiter = ',')]
|
|
pub loaders: Option<Vec<String>>,
|
|
|
|
/// Skip interactive prompts (use defaults)
|
|
#[clap(short, long)]
|
|
pub yes: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct ImportArgs {
|
|
/// Path to modpack file
|
|
pub file: String,
|
|
|
|
/// Resolve dependencies
|
|
#[clap(short = 'D', long = "deps")]
|
|
pub deps: bool,
|
|
|
|
/// Skip confirmation prompts
|
|
#[clap(short, long)]
|
|
pub yes: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct AddArgs {
|
|
/// Project identifiers to add
|
|
#[clap(required = true)]
|
|
pub inputs: Vec<String>,
|
|
|
|
/// Project type (mod, resourcepack, shader, datapack, world)
|
|
#[clap(short = 't', long = "type")]
|
|
pub project_type: Option<ProjectType>,
|
|
|
|
/// Skip resolving dependencies
|
|
#[clap(short = 'D', long)]
|
|
pub no_deps: bool,
|
|
|
|
/// Update if already exists
|
|
#[clap(short, long)]
|
|
pub update: bool,
|
|
|
|
/// Skip confirmation prompts
|
|
#[clap(short, long)]
|
|
pub yes: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct AddPrjArgs {
|
|
/// `CurseForge` project slug or ID (optional file ID: `slug#file_id`)
|
|
#[clap(long = "cf", alias = "curseforge")]
|
|
pub curseforge: Option<String>,
|
|
|
|
/// Modrinth project slug or ID (optional file ID: `slug#file_id`)
|
|
#[clap(long = "mr", alias = "modrinth")]
|
|
pub modrinth: Option<String>,
|
|
|
|
/// GitHub repository (format: owner/repo or owner/repo#tag)
|
|
#[clap(long = "gh", alias = "github")]
|
|
pub github: Option<String>,
|
|
|
|
/// Project type (mod, resourcepack, shader, datapack, world)
|
|
#[clap(short = 't', long = "type")]
|
|
pub project_type: Option<ProjectType>,
|
|
|
|
/// Project side (client, server, both)
|
|
#[clap(long)]
|
|
pub side: Option<ProjectSide>,
|
|
|
|
/// Update strategy (latest, none)
|
|
#[clap(long)]
|
|
pub strategy: Option<UpdateStrategy>,
|
|
|
|
/// Redistributable flag
|
|
#[clap(long)]
|
|
pub redistributable: Option<bool>,
|
|
|
|
/// Subpath for project file placement
|
|
#[clap(long)]
|
|
pub subpath: Option<String>,
|
|
|
|
/// Project aliases (can be specified multiple times)
|
|
#[clap(long = "alias")]
|
|
pub aliases: Vec<String>,
|
|
|
|
/// Export flag (whether to include in exports)
|
|
#[clap(long)]
|
|
pub export: Option<bool>,
|
|
|
|
/// Skip resolving dependencies
|
|
#[clap(short = 'D', long = "no-deps")]
|
|
pub no_deps: bool,
|
|
|
|
/// Skip confirmation prompts
|
|
#[clap(short, long)]
|
|
pub yes: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct RmArgs {
|
|
/// Project identifiers to remove
|
|
#[clap(required = true)]
|
|
pub inputs: Vec<String>,
|
|
|
|
/// Remove all projects
|
|
#[clap(short = 'a', long)]
|
|
pub all: bool,
|
|
|
|
/// Skip confirmation prompt
|
|
#[clap(short, long)]
|
|
pub yes: bool,
|
|
|
|
/// Skip removing dependent projects
|
|
#[clap(short = 'D', long = "no-deps")]
|
|
pub no_deps: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct UpdateArgs {
|
|
/// Projects to update (empty = all)
|
|
#[arg(value_name = "PROJECT")]
|
|
pub inputs: Vec<String>,
|
|
|
|
/// Update all projects
|
|
#[arg(short, long)]
|
|
pub all: bool,
|
|
|
|
/// Skip confirmation prompts
|
|
#[arg(short, long)]
|
|
pub yes: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct LsArgs {
|
|
/// Show detailed information
|
|
#[clap(short, long)]
|
|
pub detailed: bool,
|
|
|
|
/// Add update information for projects
|
|
#[clap(short = 'c', long = "check-updates")]
|
|
pub check_updates: bool,
|
|
|
|
/// Maximum length for project names
|
|
#[clap(long = "name-max-length")]
|
|
pub name_max_length: Option<usize>,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct SetArgs {
|
|
/// Project identifier (optional for lockfile properties)
|
|
pub input: Option<String>,
|
|
|
|
/// Project type
|
|
#[clap(long)]
|
|
pub r#type: Option<String>,
|
|
|
|
/// Project side (client/server/both)
|
|
#[clap(long)]
|
|
pub side: Option<String>,
|
|
|
|
/// Update strategy (latest/none)
|
|
#[clap(long)]
|
|
pub strategy: Option<String>,
|
|
|
|
/// Redistributable flag
|
|
#[clap(long)]
|
|
pub redistributable: Option<bool>,
|
|
|
|
/// Change the target of the pack (curseforge, modrinth, multiplatform)
|
|
#[clap(short = 't', long)]
|
|
pub target: Option<String>,
|
|
|
|
/// Change the minecraft versions (comma-separated)
|
|
#[clap(short = 'v', long)]
|
|
pub mc_versions: Option<String>,
|
|
|
|
/// Change the mod loaders (format: name=version,name=version)
|
|
#[clap(short = 'l', long)]
|
|
pub loaders: Option<String>,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct LinkArgs {
|
|
/// Source project
|
|
pub from: String,
|
|
|
|
/// Target project
|
|
pub to: String,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct UnlinkArgs {
|
|
/// Source project
|
|
pub from: String,
|
|
|
|
/// Target project
|
|
pub to: String,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct DiffArgs {
|
|
/// Path to old lockfile
|
|
pub old_lockfile: String,
|
|
|
|
/// Path to current lockfile (optional, defaults to pakku-lock.json)
|
|
pub current_lockfile: Option<String>,
|
|
|
|
/// Export markdown diff
|
|
#[clap(long)]
|
|
pub markdown_diff: Option<String>,
|
|
|
|
/// Export markdown (formatted)
|
|
#[clap(long)]
|
|
pub markdown: Option<String>,
|
|
|
|
/// Verbose output (show file changes)
|
|
#[clap(short, long)]
|
|
pub verbose: bool,
|
|
|
|
/// Header size for markdown (0-5)
|
|
#[clap(short = 'H', long, default_value = "2")]
|
|
pub header_size: usize,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct FetchArgs {
|
|
/// Timeout for waiting on conflicting operations (seconds)
|
|
#[clap(short, long)]
|
|
pub timeout: Option<u64>,
|
|
|
|
/// Number of retry attempts for failed downloads
|
|
#[clap(short = 'r', long, default_value = "2")]
|
|
pub retry: u32,
|
|
|
|
/// Move unknown files to shelf instead of deleting
|
|
#[clap(long)]
|
|
pub shelve: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct SyncArgs {
|
|
/// Sync additions only
|
|
#[clap(short = 'A', long)]
|
|
pub additions: bool,
|
|
|
|
/// Sync removals only
|
|
#[clap(short = 'R', long)]
|
|
pub removals: bool,
|
|
|
|
/// Sync updates only (apply pending updates)
|
|
#[clap(short = 'U', long)]
|
|
pub updates: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct ExportArgs {
|
|
/// Export profile (curseforge, modrinth, serverpack)
|
|
/// If not specified, all profiles will be exported
|
|
#[clap(short, long)]
|
|
pub profile: Option<String>,
|
|
|
|
/// Output directory
|
|
#[clap(short, long)]
|
|
pub output: Option<String>,
|
|
|
|
/// Use Pakker-compatible output layout (build/<profile>/...)
|
|
/// Default is Pakker layout (exports/...)
|
|
#[clap(long)]
|
|
pub pakker_layout: bool,
|
|
|
|
/// Show file IO errors during export
|
|
#[clap(long = "show-io-errors")]
|
|
pub show_io_errors: bool,
|
|
|
|
/// Export modpack without server content
|
|
/// Modrinth: exclude server-overrides and SERVER mods
|
|
/// `ServerPack`: skip export
|
|
#[clap(long = "no-server")]
|
|
pub no_server: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct RemoteArgs {
|
|
/// Git URL to install from (if empty, shows status)
|
|
pub url: Option<String>,
|
|
|
|
/// Branch to checkout (instead of remote's HEAD)
|
|
#[clap(short, long)]
|
|
pub branch: Option<String>,
|
|
|
|
/// Install server pack
|
|
#[clap(short = 'S', long)]
|
|
pub server_pack: bool,
|
|
|
|
/// Retry count for downloads
|
|
#[clap(short, long, default_value = "2")]
|
|
pub retry: u32,
|
|
|
|
/// Remove remote from modpack
|
|
#[clap(long = "rm", long = "remove")]
|
|
pub remove: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct RemoteUpdateArgs {
|
|
/// Branch to checkout instead of remote's HEAD
|
|
#[clap(short, long)]
|
|
pub branch: Option<String>,
|
|
|
|
/// Install server pack instead of full modpack
|
|
#[clap(short, long)]
|
|
pub server_pack: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct StatusArgs {
|
|
/// Check updates in parallel
|
|
#[clap(short, long)]
|
|
pub parallel: bool,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct InspectArgs {
|
|
/// Project identifiers to inspect
|
|
#[clap(required = true)]
|
|
pub projects: Vec<String>,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct CredentialsArgs {
|
|
/// Delete stored credentials (defaults to deleting both file and keyring)
|
|
#[clap(short, long)]
|
|
pub delete: bool,
|
|
|
|
/// Delete credentials file (~/.pakku/credentials)
|
|
#[clap(long)]
|
|
pub delete_file: bool,
|
|
|
|
/// Delete credentials from keyring (service: pakker)
|
|
#[clap(long)]
|
|
pub delete_keyring: bool,
|
|
|
|
#[clap(subcommand)]
|
|
pub subcommand: Option<CredentialsSubcommand>,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
pub enum CredentialsSubcommand {
|
|
/// Set API credentials
|
|
Set(CredentialsSetArgs),
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct CredentialsSetArgs {
|
|
/// `CurseForge` API key
|
|
#[clap(long)]
|
|
pub cf_api_key: Option<String>,
|
|
|
|
/// Modrinth API token
|
|
#[clap(long)]
|
|
pub modrinth_token: Option<String>,
|
|
|
|
/// GitHub access token
|
|
#[clap(long)]
|
|
pub gh_access_token: Option<String>,
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct CfgArgs {
|
|
/// Modpack name
|
|
#[clap(long)]
|
|
pub name: Option<String>,
|
|
|
|
/// Modpack version
|
|
#[clap(long)]
|
|
pub version: Option<String>,
|
|
|
|
/// Modpack description
|
|
#[clap(long)]
|
|
pub description: Option<String>,
|
|
|
|
/// Modpack author
|
|
#[clap(long)]
|
|
pub author: Option<String>,
|
|
|
|
/// Path for mods
|
|
#[clap(long)]
|
|
pub mods_path: Option<String>,
|
|
|
|
/// Path for resource packs
|
|
#[clap(long)]
|
|
pub resource_packs_path: Option<String>,
|
|
|
|
/// Path for data packs
|
|
#[clap(long)]
|
|
pub data_packs_path: Option<String>,
|
|
|
|
/// Path for worlds
|
|
#[clap(long)]
|
|
pub worlds_path: Option<String>,
|
|
|
|
/// Path for shaders
|
|
#[clap(long)]
|
|
pub shaders_path: Option<String>,
|
|
|
|
#[clap(subcommand)]
|
|
pub subcommand: Option<CfgSubcommand>,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
pub enum CfgSubcommand {
|
|
/// Configure per-project settings
|
|
Prj(CfgPrjArgs),
|
|
}
|
|
|
|
#[derive(Args)]
|
|
pub struct CfgPrjArgs {
|
|
/// Project identifier
|
|
pub project: String,
|
|
|
|
/// Project type
|
|
#[clap(long)]
|
|
pub r#type: Option<String>,
|
|
|
|
/// Project side (client/server/both)
|
|
#[clap(long)]
|
|
pub side: Option<String>,
|
|
|
|
/// Update strategy (latest/none)
|
|
#[clap(long)]
|
|
pub update_strategy: Option<String>,
|
|
|
|
/// Redistributable flag
|
|
#[clap(long)]
|
|
pub redistributable: Option<bool>,
|
|
|
|
/// Subpath for project
|
|
#[clap(long)]
|
|
pub subpath: Option<String>,
|
|
|
|
/// Add alias
|
|
#[clap(long)]
|
|
pub add_alias: Option<String>,
|
|
|
|
/// Remove alias
|
|
#[clap(long)]
|
|
pub remove_alias: Option<String>,
|
|
|
|
/// Export flag
|
|
#[clap(long)]
|
|
pub export: Option<bool>,
|
|
}
|
|
|
|
/// Fork subcommand arguments
|
|
#[derive(Debug, Args)]
|
|
#[command(args_conflicts_with_subcommands = true)]
|
|
pub struct ForkArgs {
|
|
#[clap(subcommand)]
|
|
pub subcommand: ForkSubcommand,
|
|
}
|
|
|
|
#[derive(Debug, Subcommand)]
|
|
pub enum ForkSubcommand {
|
|
/// Initialize fork from parent repository
|
|
Init {
|
|
/// Git URL of parent repository
|
|
#[clap(long, conflicts_with = "from_path")]
|
|
git_url: Option<String>,
|
|
|
|
/// Use current repository as parent
|
|
#[clap(long, conflicts_with = "from_path")]
|
|
from_current: bool,
|
|
|
|
/// Use an already-cloned repository as parent (path to worktree or .git)
|
|
#[clap(long, value_parser, conflicts_with_all = &["git_url", "from_current"])]
|
|
from_path: Option<String>,
|
|
|
|
/// Branch/tag/commit to track
|
|
#[clap(long)]
|
|
ref_name: Option<String>,
|
|
|
|
/// Type of ref (branch/tag/commit)
|
|
#[clap(long, value_enum)]
|
|
ref_type: Option<RefType>,
|
|
|
|
/// Remote name
|
|
#[clap(long, default_value = "origin")]
|
|
remote: Option<String>,
|
|
},
|
|
|
|
/// Update fork configuration
|
|
Set {
|
|
/// New git URL (optional)
|
|
#[clap(long)]
|
|
git_url: Option<String>,
|
|
|
|
/// Branch/tag/commit to track
|
|
#[clap(long)]
|
|
ref_name: String,
|
|
|
|
/// Type of ref (branch/tag/commit)
|
|
#[clap(long, value_enum)]
|
|
ref_type: Option<RefType>,
|
|
|
|
/// Remote name
|
|
#[clap(long)]
|
|
remote: Option<String>,
|
|
},
|
|
|
|
/// Show fork configuration
|
|
Show,
|
|
|
|
/// Remove fork configuration
|
|
Unset,
|
|
|
|
/// Sync with parent repository
|
|
Sync,
|
|
|
|
/// Promote projects to parent (legacy)
|
|
Promote {
|
|
/// Project identifiers to promote
|
|
projects: Vec<String>,
|
|
},
|
|
}
|