pesde/src/main.rs

239 lines
6.6 KiB
Rust
Raw Normal View History

2024-07-26 17:47:53 +01:00
use crate::cli::{
auth::get_token,
home_dir,
2024-08-08 16:59:59 +01:00
scripts::update_scripts_folder,
2024-07-26 17:47:53 +01:00
version::{check_for_updates, current_version, get_or_download_version, max_installed_version},
2024-07-28 17:19:54 +01:00
HOME_DIR,
2024-07-26 17:47:53 +01:00
};
use anyhow::Context;
2024-07-12 23:09:37 +01:00
use clap::Parser;
use colored::Colorize;
use indicatif::MultiProgress;
use indicatif_log_bridge::LogWrapper;
2024-07-12 23:09:37 +01:00
use pesde::{AuthConfig, Project};
2024-07-28 17:19:54 +01:00
use std::{fs::create_dir_all, path::PathBuf};
2024-03-04 20:18:49 +00:00
2024-07-12 23:09:37 +01:00
mod cli;
2024-07-22 21:00:09 +01:00
pub mod util;
2024-03-04 20:18:49 +00:00
2024-07-12 23:09:37 +01:00
#[derive(Parser, Debug)]
#[clap(version, about = "pesde is a feature-rich package manager for Luau")]
#[command(disable_version_flag = true)]
struct Cli {
/// Print version
#[arg(short = 'v', short_alias = 'V', long, action = clap::builder::ArgAction::Version)]
version: (),
2024-03-04 20:18:49 +00:00
2024-07-12 23:09:37 +01:00
#[command(subcommand)]
2024-07-26 17:47:53 +01:00
subcommand: cli::commands::Subcommand,
2024-07-12 23:09:37 +01:00
}
2024-07-28 17:19:54 +01:00
#[cfg(windows)]
fn get_root(path: &std::path::Path) -> PathBuf {
match path.components().next().unwrap() {
std::path::Component::Prefix(prefix) => {
let mut string = prefix.as_os_str().to_string_lossy().to_string();
if string.ends_with(':') {
string.push(std::path::MAIN_SEPARATOR);
}
std::path::PathBuf::from(&string)
}
_ => unreachable!(),
}
}
#[cfg(unix)]
fn get_root(path: &std::path::Path) -> PathBuf {
use std::os::unix::fs::MetadataExt;
let path = std::fs::canonicalize(path).unwrap();
let mut current = path.as_path();
while let Some(parent) = current.parent() {
if std::fs::metadata(parent).unwrap().dev() != std::fs::metadata(current).unwrap().dev() {
break;
}
current = parent;
}
current.to_path_buf()
}
2024-07-26 17:47:53 +01:00
fn run() -> anyhow::Result<()> {
2024-07-25 15:32:48 +01:00
#[cfg(windows)]
2024-07-26 17:47:53 +01:00
'scripts: {
2024-07-25 15:32:48 +01:00
let exe = std::env::current_exe().expect("failed to get current executable path");
2024-07-26 17:47:53 +01:00
if exe.parent().is_some_and(|parent| {
parent.as_os_str() != "bin"
|| parent
.parent()
2024-08-03 21:18:38 +01:00
.is_some_and(|parent| parent.as_os_str() != HOME_DIR)
2024-07-26 17:47:53 +01:00
}) {
break 'scripts;
}
2024-07-25 15:32:48 +01:00
let exe_name = exe.with_extension("");
let exe_name = exe_name.file_name().unwrap();
2024-07-26 17:47:53 +01:00
if exe_name == env!("CARGO_BIN_NAME") {
break 'scripts;
}
2024-07-25 15:32:48 +01:00
2024-07-26 17:47:53 +01:00
let status = std::process::Command::new("lune")
.arg("run")
.arg(exe.with_extension("luau"))
.args(std::env::args_os().skip(1))
.current_dir(std::env::current_dir().unwrap())
.status()
.expect("failed to run lune");
2024-07-25 15:32:48 +01:00
2024-07-26 17:47:53 +01:00
std::process::exit(status.code().unwrap());
2024-07-25 15:32:48 +01:00
}
let multi = {
let logger = pretty_env_logger::formatted_builder()
.parse_env(pretty_env_logger::env_logger::Env::default().default_filter_or("info"))
.build();
let multi = MultiProgress::new();
LogWrapper::new(multi.clone(), logger).try_init().unwrap();
multi
};
2024-07-12 23:09:37 +01:00
let cwd = std::env::current_dir().expect("failed to get current working directory");
2024-07-26 17:47:53 +01:00
let data_dir = home_dir()?.join("data");
create_dir_all(&data_dir).expect("failed to create data directory");
2024-07-28 17:19:54 +01:00
let token = get_token()?;
let home_cas_dir = data_dir.join("cas");
let project_root = get_root(&cwd);
let cas_dir = if get_root(&home_cas_dir) == project_root {
home_cas_dir
} else {
project_root.join(HOME_DIR).join("cas")
};
2024-07-26 17:47:53 +01:00
let project = Project::new(
cwd,
2024-07-28 17:19:54 +01:00
data_dir,
cas_dir,
2024-08-08 16:59:59 +01:00
AuthConfig::new().with_github_token(token.as_ref()),
2024-07-26 17:47:53 +01:00
);
let reqwest = {
let mut headers = reqwest::header::HeaderMap::new();
if let Some(token) = token {
headers.insert(
reqwest::header::AUTHORIZATION,
format!("Bearer {token}")
.parse()
.context("failed to create auth header")?,
);
}
headers.insert(
reqwest::header::ACCEPT,
"application/json"
.parse()
.context("failed to create accept header")?,
);
reqwest::blocking::Client::builder()
.user_agent(concat!(
env!("CARGO_PKG_NAME"),
"/",
env!("CARGO_PKG_VERSION")
))
.default_headers(headers)
.build()?
};
let target_version = project
.deser_manifest()
.ok()
.and_then(|manifest| manifest.pesde_version);
2024-07-12 23:09:37 +01:00
2024-07-26 17:47:53 +01:00
// store the current version in case it needs to be used later
get_or_download_version(&reqwest, &current_version())?;
let exe_path = if let Some(version) = target_version {
Some(get_or_download_version(&reqwest, &version)?)
} else {
None
};
let exe_path = if let Some(exe_path) = exe_path {
exe_path
} else {
get_or_download_version(&reqwest, &max_installed_version()?)?
};
if let Some(exe_path) = exe_path {
let status = std::process::Command::new(exe_path)
.args(std::env::args_os().skip(1))
.status()
.expect("failed to run new version");
std::process::exit(status.code().unwrap());
}
match check_for_updates(&reqwest) {
Ok(_) => {}
Err(e) => {
println!(
"{}",
format!("failed to check for updates: {e}\n\n").red().bold()
);
}
}
match update_scripts_folder(&project) {
Ok(_) => {}
Err(e) => {
println!(
"{}",
format!("failed to update scripts: {e}\n\n").red().bold()
);
}
}
2024-07-26 17:47:53 +01:00
Cli::parse().subcommand.run(project, multi, reqwest)
}
fn main() {
if let Err(err) = run() {
2024-07-17 18:38:01 +01:00
eprintln!("{}: {err}\n", "error".red().bold());
2024-03-04 20:18:49 +00:00
2024-07-12 23:09:37 +01:00
let cause = err.chain().skip(1).collect::<Vec<_>>();
2024-03-04 20:18:49 +00:00
2024-07-12 23:09:37 +01:00
if !cause.is_empty() {
eprintln!("{}:", "caused by".red().bold());
for err in cause {
2024-07-17 18:38:01 +01:00
eprintln!(" - {err}");
2024-07-12 23:09:37 +01:00
}
}
2024-07-17 18:38:01 +01:00
let backtrace = err.backtrace();
match backtrace.status() {
std::backtrace::BacktraceStatus::Disabled => {
eprintln!(
"\n{}: set RUST_BACKTRACE=1 for a backtrace",
"help".yellow().bold()
);
}
std::backtrace::BacktraceStatus::Captured => {
eprintln!("\n{}:\n{backtrace}", "backtrace".yellow().bold());
}
_ => {
eprintln!("\n{}: not captured", "backtrace".yellow().bold());
}
}
2024-07-12 23:09:37 +01:00
std::process::exit(1);
2024-03-04 20:18:49 +00:00
}
}