pakker/crates/pakker-cli/src/cli/commands/remote.rs
NotAShelf d445b1814a
treewide: migrate to multi-crate layout
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I11a2103f3530f07409177404577b90136a6a6964
2026-05-03 03:44:54 +03:00

151 lines
4 KiB
Rust

use std::{
fs,
path::{Path, PathBuf},
};
use crate::{
cli::RemoteArgs,
error::{PakkerError, Result},
fetch::Fetcher,
git,
model::{config::Config, lockfile::LockFile},
};
const REMOTE_DIR: &str = ".pakku-remote";
pub async fn execute(args: RemoteArgs) -> Result<()> {
let remote_path = PathBuf::from(REMOTE_DIR);
// Handle --remove flag
if args.remove {
if remote_path.exists() {
fs::remove_dir_all(&remote_path)?;
log::info!("Removed remote from modpack");
} else {
log::warn!("No remote configured");
}
return Ok(());
}
// If no URL provided, show status
if args.url.is_none() {
show_remote_status(&remote_path);
return Ok(());
}
let url = args
.url
.ok_or_else(|| PakkerError::InvalidInput("URL is required".to_string()))?;
log::info!("Installing modpack from: {url}");
// Clone or update repository
if remote_path.exists() {
log::info!("Remote directory exists, updating...");
let remote_name = "origin";
let ref_name = args.branch.as_deref().unwrap_or("HEAD");
git::fetch_updates(&remote_path, remote_name, ref_name, None)?;
git::reset_to_ref(&remote_path, remote_name, ref_name)?;
} else {
log::info!("Cloning repository...");
let ref_name = args.branch.as_deref().unwrap_or("HEAD");
git::clone_repository(&url, &remote_path, ref_name, None)?;
}
// Load lockfile and config from remote
let remote_lockfile_path = remote_path.join("pakku-lock.json");
if !remote_lockfile_path.exists() {
return Err(PakkerError::ConfigError(
"Remote repository does not contain pakku-lock.json".to_string(),
));
}
let remote_lockfile = LockFile::load(&remote_path)?;
let remote_config = Config::load(&remote_path).ok();
// Copy lockfile to current directory
let current_lockfile_path = PathBuf::from("pakku-lock.json");
fs::copy(&remote_lockfile_path, &current_lockfile_path)?;
log::info!("Copied lockfile from remote");
// Copy config if exists
if remote_config.is_some() {
let remote_config_path = remote_path.join("pakku.json");
let current_config_path = PathBuf::from("pakku.json");
if remote_config_path.exists() {
fs::copy(&remote_config_path, &current_config_path)?;
log::info!("Copied config from remote");
}
}
// Fetch project files
log::info!("Fetching project files...");
let fetcher = Fetcher::new(&remote_path);
fetcher
.fetch_all(&remote_lockfile, &remote_config.unwrap_or_default())
.await?;
// Sync overrides
sync_overrides(&remote_path, args.server_pack)?;
log::info!("Successfully installed modpack from remote");
Ok(())
}
fn show_remote_status(remote_path: &Path) {
if !remote_path.exists() {
println!("No remote configured");
return;
}
println!("Remote status:");
println!(" Directory: {}", remote_path.display());
if git::is_git_repository(remote_path) {
if let Ok(url) = git::get_remote_url(remote_path, "origin") {
println!(" URL: {url}");
}
if let Ok(sha) = git::get_current_commit_sha(remote_path, None) {
println!(" Commit: {}", &sha[..8]);
}
}
}
fn sync_overrides(remote_path: &Path, server_pack: bool) -> Result<()> {
let override_dirs = if server_pack {
vec!["overrides", "server_overrides"]
} else {
vec!["overrides", "client_overrides"]
};
for dir_name in override_dirs {
let src_dir = remote_path.join(dir_name);
if src_dir.exists() && src_dir.is_dir() {
log::info!("Syncing {dir_name} directory...");
copy_dir_recursive(&src_dir, Path::new("."))?;
}
}
Ok(())
}
fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
if !dst.exists() {
fs::create_dir_all(dst)?;
}
for entry in fs::read_dir(src)? {
let entry = entry?;
let src_path = entry.path();
let file_name = entry.file_name();
let dst_path = dst.join(file_name);
if src_path.is_dir() {
copy_dir_recursive(&src_path, &dst_path)?;
} else {
fs::copy(&src_path, &dst_path)?;
}
}
Ok(())
}