diff --git a/babylonia-terminal-cli/Cargo.toml b/babylonia-terminal-cli/Cargo.toml index 9053afc..b2b2752 100644 --- a/babylonia-terminal-cli/Cargo.toml +++ b/babylonia-terminal-cli/Cargo.toml @@ -14,7 +14,9 @@ name = "babylonia-terminal-cli" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.83" babylonia-terminal-sdk = { path = "./../babylonia-terminal-sdk" } +dialoguer = "0.11.0" downloader = { git = "https://github.com/ALEZ-DEV/downloader" } # version = "0.2.7", indicatif = "0.17.8" log = "0.4.21" diff --git a/babylonia-terminal-cli/src/main.rs b/babylonia-terminal-cli/src/main.rs index c9af70d..c40442d 100644 --- a/babylonia-terminal-cli/src/main.rs +++ b/babylonia-terminal-cli/src/main.rs @@ -1,7 +1,12 @@ use std::{path::PathBuf, str::FromStr}; use babylonia_terminal_sdk::{ - components::proton_component::ProtonComponent, game_manager::GameManager, game_state::GameState, + components::{ + dxvk_component::{DXVK_DEV, DXVK_REPO}, + proton_component::{ProtonComponent, PROTON_DEV, PROTON_REPO}, + }, + game_manager::GameManager, + game_state::GameState, }; use log::{debug, info, LevelFilter}; use simple_logger::SimpleLogger; @@ -9,6 +14,7 @@ use tokio::io::{AsyncBufReadExt, BufReader}; use wincompatlib::prelude::*; pub mod reporter; +pub mod utils; use crate::reporter::DownloadReporter; @@ -49,10 +55,24 @@ async fn main() { match state { GameState::ProtonNotInstalled => { + let release; + if utils::use_latest("Do you want to install latest version of Proton GE or a specific version of it?") { + release = 0; + } else { + release = utils::choose_release_version( + PROTON_DEV, + PROTON_REPO, + "Please, select a version of Proton GE to install.", + ) + .await + .expect("Failed to fetch proton version!"); + } + info!("Proton not installed, installing it..."); proton_component = Some( GameManager::install_wine( GameState::get_config_directory().await, + release, Some(DownloadReporter::create(false)), ) .await @@ -61,11 +81,27 @@ async fn main() { info!("Proton installed"); } GameState::DXVKNotInstalled => { + let release; + if utils::use_latest( + "Do you want to install latest version of DXVK or a specific version of it?", + ) { + release = 0; + } else { + release = utils::choose_release_version( + DXVK_DEV, + DXVK_REPO, + "Please, select a version of DXVK to install.", + ) + .await + .expect("Failed to fetch DXVK version!"); + } + info!("DXVK not installed, installing it..."); debug!("{:?}", proton_component); GameManager::install_dxvk( &proton.clone().unwrap(), GameState::get_config_directory().await, + release, Some(DownloadReporter::create(false)), ) .await diff --git a/babylonia-terminal-cli/src/utils.rs b/babylonia-terminal-cli/src/utils.rs new file mode 100644 index 0000000..0a752fe --- /dev/null +++ b/babylonia-terminal-cli/src/utils.rs @@ -0,0 +1,43 @@ +use babylonia_terminal_sdk::utils::github_requester::GithubRequester; +use dialoguer::{theme::ColorfulTheme, Select}; + +pub fn use_latest(prompt: &str) -> bool { + let choices = ["Install latest", "Choose specific version"]; + + let index = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(prompt) + .default(0) + .items(&choices) + .interact() + .unwrap(); + + if choices[index] == "Install latest" { + true + } else { + false + } +} + +struct Chooser; +impl GithubRequester for Chooser { + fn set_github_release_index(&mut self, _: usize) {} +} + +pub async fn choose_release_version( + github_username: &str, + repo_name: &str, + prompt: &str, +) -> anyhow::Result { + let releases = Chooser::get_github_releases(github_username, repo_name).await?; + let releases_names: Vec = releases.iter().map(|r| r.tag_name.to_owned()).collect(); + + let index = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(prompt) + .default(0) + .items(&releases_names) + .max_length(5) + .interact() + .unwrap(); + + Ok(index) +} diff --git a/babylonia-terminal-sdk/src/components/component_downloader.rs b/babylonia-terminal-sdk/src/components/component_downloader.rs index 2eedf76..c845d9c 100644 --- a/babylonia-terminal-sdk/src/components/component_downloader.rs +++ b/babylonia-terminal-sdk/src/components/component_downloader.rs @@ -9,6 +9,7 @@ pub trait ComponentDownloader { //the 'static is something to change, I don't very like it, but it's for testing purpose #[allow(async_fn_in_trait)] async fn download( + &self, output_dir: &PathBuf, progress: Option>, ) -> anyhow::Result; diff --git a/babylonia-terminal-sdk/src/components/dxvk_component.rs b/babylonia-terminal-sdk/src/components/dxvk_component.rs index 20aa033..872dc24 100644 --- a/babylonia-terminal-sdk/src/components/dxvk_component.rs +++ b/babylonia-terminal-sdk/src/components/dxvk_component.rs @@ -16,9 +16,13 @@ use crate::utils::github_requester::GithubRequester; use super::component_downloader::ComponentDownloader; +pub static DXVK_DEV: &str = "doitsujin"; +pub static DXVK_REPO: &str = "dxvk"; + pub struct DXVKComponent<'a> { wine: &'a Wine, path: PathBuf, + github_release_index: usize, } impl<'a> DXVKComponent<'a> { @@ -26,11 +30,16 @@ impl<'a> DXVKComponent<'a> { DXVKComponent { wine, path: path.join("dxvk"), + github_release_index: 0, } } } -impl<'a> GithubRequester for DXVKComponent<'a> {} +impl<'a> GithubRequester for DXVKComponent<'a> { + fn set_github_release_index(&mut self, new_release_index: usize) { + self.github_release_index = new_release_index; + } +} impl<'a> ComponentDownloader for DXVKComponent<'a> { async fn install( @@ -42,7 +51,7 @@ impl<'a> ComponentDownloader for DXVKComponent<'a> { .parent() .expect("Failed to get parent folder for DXVK") .to_path_buf(); - let file_output = Self::download(&dir, progress).await?; + let file_output = self.download(&dir, progress).await?; Self::uncompress(file_output.clone(), self.path.clone()).await?; @@ -64,12 +73,15 @@ impl<'a> ComponentDownloader for DXVKComponent<'a> { } async fn download( + &self, output_dir: &std::path::PathBuf, progress: Option>, ) -> anyhow::Result { - let releases = Self::get_latest_github_release("doitsujin", "dxvk").await?; + let releases = + Self::get_github_release_version(DXVK_DEV, DXVK_REPO, self.github_release_index) + .await?; - let asset = releases[0] + let asset = releases .assets .first() .expect("Asset not found in the github release"); diff --git a/babylonia-terminal-sdk/src/components/game_component.rs b/babylonia-terminal-sdk/src/components/game_component.rs index 89e3398..2042dbe 100644 --- a/babylonia-terminal-sdk/src/components/game_component.rs +++ b/babylonia-terminal-sdk/src/components/game_component.rs @@ -90,7 +90,9 @@ impl GameComponent { } } -impl GithubRequester for GameComponent {} +impl GithubRequester for GameComponent { + fn set_github_release_index(&mut self, _: usize) {} +} impl ComponentDownloader for GameComponent { async fn install( @@ -98,12 +100,13 @@ impl ComponentDownloader for GameComponent { progress: Option>, ) -> anyhow::Result<()> { let _ = create_dir_all(&self.game_dir).await; - Self::download(&self.game_dir, progress).await?; + self.download(&self.game_dir, progress).await?; Ok(()) } async fn download( + &self, output_dir: &std::path::PathBuf, progress: Option>, ) -> anyhow::Result { @@ -179,6 +182,6 @@ impl ComponentDownloader for GameComponent { _file: std::path::PathBuf, _new_filename: std::path::PathBuf, ) -> anyhow::Result<()> { - panic!("How did you run this function??!!") + anyhow::bail!("How did you run this function??!!") } } diff --git a/babylonia-terminal-sdk/src/components/proton_component.rs b/babylonia-terminal-sdk/src/components/proton_component.rs index e8f6fa2..9f0e765 100644 --- a/babylonia-terminal-sdk/src/components/proton_component.rs +++ b/babylonia-terminal-sdk/src/components/proton_component.rs @@ -14,37 +14,48 @@ use wincompatlib::wine::ext::WineBootExt; use super::component_downloader::ComponentDownloader; use crate::utils::github_requester::GithubRequester; +pub static PROTON_DEV: &str = "GloriousEggroll"; +pub static PROTON_REPO: &str = "proton-ge-custom"; + #[derive(Debug, PartialEq, Eq)] pub struct ProtonComponent { path: PathBuf, + github_release_index: usize, } -impl GithubRequester for ProtonComponent {} +impl GithubRequester for ProtonComponent { + fn set_github_release_index(&mut self, new_release_index: usize) { + self.github_release_index = new_release_index; + } +} impl ComponentDownloader for ProtonComponent { async fn install(&self, progress: Option>) -> anyhow::Result<()> { - let file_output = Self::download( - &self - .path - .parent() - .expect("Failed to get the parent directory of Wine") - .to_path_buf(), - progress, - ) - .await?; + let file_output = self + .download( + &self + .path + .parent() + .expect("Failed to get the parent directory of Wine") + .to_path_buf(), + progress, + ) + .await?; Self::uncompress(file_output.clone(), self.path.clone()).await?; Ok(()) } async fn download( + &self, output_dir: &PathBuf, progress: Option>, ) -> anyhow::Result { let release = - Self::get_latest_github_release("GloriousEggroll", "proton-ge-custom").await?; + Self::get_github_release_version(PROTON_DEV, PROTON_REPO, self.github_release_index) + .await?; - let asset = release[0] + let asset = release .assets .get(1) .expect("Asset not found in the github release"); @@ -91,6 +102,7 @@ impl ProtonComponent { pub fn new(path: PathBuf) -> Self { ProtonComponent { path: path.join("proton"), + github_release_index: 0, } } diff --git a/babylonia-terminal-sdk/src/game_manager.rs b/babylonia-terminal-sdk/src/game_manager.rs index a4f8274..4693f1e 100644 --- a/babylonia-terminal-sdk/src/game_manager.rs +++ b/babylonia-terminal-sdk/src/game_manager.rs @@ -12,7 +12,7 @@ use crate::{ }, game_patcher, game_state::GameState, - utils::{get_game_name, get_game_name_with_executable}, + utils::{get_game_name, get_game_name_with_executable, github_requester::GithubRequester}, }; pub struct GameManager; @@ -20,12 +20,14 @@ pub struct GameManager; impl GameManager { pub async fn install_wine

( config_dir: PathBuf, + release_index: usize, progress: Option>, ) -> anyhow::Result where P: Reporter + 'static, { - let wine_component = ProtonComponent::new(config_dir); + let mut wine_component = ProtonComponent::new(config_dir); + wine_component.set_github_release_index(release_index); wine_component.install(progress).await?; @@ -39,12 +41,15 @@ impl GameManager { pub async fn install_dxvk

( proton: &Proton, config_dir: PathBuf, + release_index: usize, progress: Option>, ) -> anyhow::Result<()> where P: Reporter + 'static, { - let dxvk_component = DXVKComponent::from_wine(proton.wine(), config_dir); + let mut dxvk_component = DXVKComponent::from_wine(proton.wine(), config_dir); + dxvk_component.set_github_release_index(release_index); + dxvk_component.install(progress).await?; let mut config = GameState::get_config().await; @@ -107,7 +112,11 @@ impl GameManager { let winetricks = Winetricks::from_wine("/bin/winetricks", wine_with_proton_prefix); //winetricks.install("corefonts")?; - winetricks.install("vcrun2022")?; + let mut child = winetricks.install("vcrun2022")?; + + child + .wait() + .expect("Something failed when waiting for the installation"); let mut config = GameState::get_config().await; config.is_dependecies_installed = true; diff --git a/babylonia-terminal-sdk/src/utils/github_requester.rs b/babylonia-terminal-sdk/src/utils/github_requester.rs index 6a2dd37..113d6e6 100644 --- a/babylonia-terminal-sdk/src/utils/github_requester.rs +++ b/babylonia-terminal-sdk/src/utils/github_requester.rs @@ -64,7 +64,7 @@ pub trait GithubRequester { } #[allow(async_fn_in_trait)] - async fn get_latest_github_release( + async fn get_github_releases( user: &str, repo_name: &str, ) -> anyhow::Result> { @@ -80,4 +80,23 @@ pub trait GithubRequester { let releases: Vec = serde_json::from_str(&body)?; Ok(releases) } + + #[allow(async_fn_in_trait)] + async fn get_github_release_version( + user: &str, + repo_name: &str, + release_index: usize, + ) -> anyhow::Result { + let releases = Self::get_github_releases(user, repo_name).await?; + + let release = releases.get(release_index); + + if release.is_none() { + anyhow::bail!("Wrong index when trying to get the github release"); + } + + Ok(release.unwrap().to_owned()) + } + + fn set_github_release_index(&mut self, new_release_index: usize); }