Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a couple things and added some comments and documentation #20

Merged
merged 2 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
438 changes: 199 additions & 239 deletions Cargo.lock

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions libprotonup/src/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum App {
// TODO: HeroicGamesLauncher,
}

// APP_VARIANTS is a shorthand to all app variants
/// APP_VARIANTS is a shorthand to all app variants
pub static APP_VARIANTS: &[App] = &[App::Steam, App::Lutris];

impl fmt::Display for App {
Expand All @@ -24,20 +24,23 @@ impl fmt::Display for App {
}

impl App {
/// Returns the version of Wine used for the App
pub fn app_wine_version(&self) -> Variant {
match *self {
Self::Steam => Variant::GEProton,
Self::Lutris => Variant::WineGE,
}
}

/// Returns the variantst of AppInstallations corresponding to the App
pub fn app_installations(&self) -> Vec<AppInstallations> {
match *self {
Self::Steam => vec![AppInstallations::Steam, AppInstallations::SteamFlatpak],
Self::Lutris => vec![AppInstallations::Lutris, AppInstallations::LutrisFlatpak],
}
}

/// Checks the versions (Native vs Flatpak) of the App that are installed
pub fn detect_installation_method(&self) -> Vec<AppInstallations> {
match *self {
Self::Steam => {
Expand Down Expand Up @@ -70,6 +73,7 @@ impl fmt::Display for AppInstallations {
}

impl AppInstallations {
/// Default directory that wine is extracted to
pub fn default_install_dir(&self) -> &'static str {
match *self {
Self::Steam => "~/.steam/steam/compatibilitytools.d/",
Expand All @@ -81,6 +85,7 @@ impl AppInstallations {
}
}

/// The app root folder
pub fn app_base_dir(&self) -> &'static str {
match *self {
Self::Steam => "~/.steam/steam/",
Expand All @@ -90,10 +95,12 @@ impl AppInstallations {
}
}

/// Get a list of the currently installed wine versions
pub fn list_installed_versions(&self) -> Result<Vec<String>, anyhow::Error> {
list_folders_in_path(self.default_install_dir())
}

/// Returns the base App
pub fn into_app(&self) -> App {
match *self {
Self::Steam | Self::SteamFlatpak => App::Steam,
Expand All @@ -107,7 +114,7 @@ pub fn list_installed_apps() -> Vec<AppInstallations> {
detect_installations(APP_INSTALLATIONS_VARIANTS)
}

/// detect_installations returns a vector of App variants that are detected based on the provided
/// detect_installations returns a vector of App variants that are detected
fn detect_installations(app_installations: &[AppInstallations]) -> Vec<AppInstallations> {
app_installations
.iter()
Expand All @@ -116,7 +123,7 @@ fn detect_installations(app_installations: &[AppInstallations]) -> Vec<AppInstal
.collect()
}

// APP_INSTALLATIONS_VARIANTS contains the subset of variants of the App enum that are actual apps
/// APP_INSTALLATIONS_VARIANTS contains the subset of variants of the App enum that are actual apps
pub static APP_INSTALLATIONS_VARIANTS: &[AppInstallations] = &[
AppInstallations::Steam,
AppInstallations::SteamFlatpak,
Expand Down
36 changes: 15 additions & 21 deletions libprotonup/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,7 @@ use std::sync::Arc;
use tar::Archive;
use xz2::read::XzDecoder;

fn path_result(path: &Path) -> String {
let spath = path.to_str();
match spath {
Some(p) => String::from(p),
None => String::from("path missing!"),
}
}

// decompress will detect the extension and decompress the file with the appropriate function
/// decompress will detect the extension and decompress the file with the appropriate function
pub fn decompress(from_path: &Path, destination_path: &Path) -> Result<()> {
let path_str = from_path.as_os_str().to_string_lossy();

Expand All @@ -42,7 +34,7 @@ fn decompress_gz(from_path: &Path, destination_path: &Path) -> Result<()> {
let file = File::open(from_path).with_context(|| {
format!(
"[Decompressing] Failed to open file from Path: {}",
path_result(from_path),
from_path.display(),
)
})?;

Expand All @@ -51,7 +43,7 @@ fn decompress_gz(from_path: &Path, destination_path: &Path) -> Result<()> {
archive.unpack(destination_path).with_context(|| {
format!(
"[Decompressing] Failed to unpack into destination : {}",
path_result(destination_path)
destination_path.display()
)
})?;
Ok(())
Expand All @@ -62,7 +54,7 @@ fn decompress_xz(from_path: &Path, destination_path: &Path) -> Result<()> {
let file = File::open(from_path).with_context(|| {
format!(
"[Decompressing] Failed to open file from Path: {}",
path_result(from_path),
from_path.display()
)
})?;

Expand All @@ -71,7 +63,7 @@ fn decompress_xz(from_path: &Path, destination_path: &Path) -> Result<()> {
archive.unpack(destination_path).with_context(|| {
format!(
"[Decompressing] Failed to unpack into destination : {}",
path_result(destination_path)
destination_path.display()
)
})?;
Ok(())
Expand All @@ -85,20 +77,20 @@ pub fn create_progress_trackers() -> (Arc<AtomicUsize>, Arc<AtomicBool>) {
)
}

// check_if_exists checks if a folder exists in a path
/// check_if_exists checks if a folder exists in a path
pub fn check_if_exists(path: &str, tag: &str) -> bool {
let f_path = utils::expand_tilde(format!("{path}{tag}/")).unwrap();
let p = f_path.as_path();
p.is_dir()
}

// list_folders_in_path returns a vector of strings of the folders in a path
/// list_folders_in_path returns a vector of strings of the folders in a path
pub fn list_folders_in_path(path: &str) -> Result<Vec<String>, anyhow::Error> {
let f_path = utils::expand_tilde(path).unwrap();
let p = f_path.as_path();
let paths: Vec<String> = p
.read_dir()
.with_context(|| format!("Failed to read directory : {}", path_result(p)))?
.with_context(|| format!("Failed to read directory : {}", p.display()))?
.filter_map(|e| e.ok())
.filter(|e| e.path().is_dir())
.map(|e| {
Expand All @@ -110,12 +102,12 @@ pub fn list_folders_in_path(path: &str) -> Result<Vec<String>, anyhow::Error> {
Ok(paths)
}

// removes a directory and all its contents
/// Removes a directory and all its contents
pub fn remove_dir_all(path: &str) -> Result<()> {
let f_path = utils::expand_tilde(path).unwrap();
let p = f_path.as_path();
std::fs::remove_dir_all(p)
.with_context(|| format!("[Remove] Failed to remove directory : {}", path_result(p)))?;
.with_context(|| format!("[Remove] Failed to remove directory : {}", p.display()))?;
Ok(())
}

Expand Down Expand Up @@ -143,7 +135,7 @@ pub async fn download_file_progress(
.with_context(|| {
format!(
"[Download] Failed creating destination file : {}",
path_result(install_dir)
install_dir.display()
)
})?;

Expand All @@ -156,7 +148,7 @@ pub async fn download_file_progress(
file.write_all(&chunk).with_context(|| {
format!(
"[Download] Failed creating destination file : {}",
path_result(install_dir)
install_dir.display()
)
})?;
let new = min(downloaded + (chunk.len() as u64), total_size);
Expand All @@ -168,6 +160,7 @@ pub async fn download_file_progress(
Ok(())
}

/// Downloads and returns the text response
pub async fn download_file_into_memory(url: &String) -> Result<String> {
let client = reqwest::Client::new();
let res = client
Expand All @@ -187,9 +180,10 @@ pub async fn download_file_into_memory(url: &String) -> Result<String> {
.with_context(|| format!("[Download SHA] Failed to read response from URL : {}", &url))
}

/// Checks the downloaded file integrity with the sha512sum
pub fn hash_check_file(file_dir: String, git_hash: String) -> Result<bool> {
let mut file = File::open(file_dir)
.context("[Hash Check] Failed oppening download file for checking. Was the file moved?")?;
.context("[Hash Check] Failed opening download file for checking. Was the file moved?")?;
let mut hasher = Sha512::new();
io::copy(&mut file, &mut hasher)
.context("[Hash Check] Failed reading download file for checking")?;
Expand Down
8 changes: 8 additions & 0 deletions libprotonup/src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

pub type ReleaseList = Vec<Release>;

/// Contains the information from one of the releases on GitHub
#[derive(Serialize, Deserialize, Debug)]
pub struct Release {
/// API URL of the Release
Expand All @@ -26,7 +27,7 @@
/// Returns a Download struct corresponding to the Release
pub fn get_download_info(&self) -> Download {
let mut download: Download = Download::default();
download.version = self.tag_name.clone();

Check warning on line 30 in libprotonup/src/github.rs

View workflow job for this annotation

GitHub Actions / clippy_check

field assignment outside of initializer for an instance created with Default::default()
for asset in &self.assets {
if asset.name.ends_with("sha512sum") {
download.sha512sum_url = asset.browser_download_url.clone();
Expand All @@ -40,6 +41,9 @@
}
}

/// Holds the information from the different Assets for each GitHub release
///
/// An Asset could be for the wine tar folder or for the sha512sum
#[derive(Serialize, Deserialize, Debug)]
pub struct Asset {
url: String,
Expand Down Expand Up @@ -68,11 +72,15 @@
Ok(r_list)
}

/// Contains all the information needed to download the corresponding release from GitHub
#[derive(Default, Debug, PartialEq, Clone)]
pub struct Download {
pub version: String,
/// Download URL for the release's file hash to check download integrity
pub sha512sum_url: String,
/// Download URL for the release's compressed tar file
pub download_url: String,
/// The reported size of the tar download
pub size: u64,
}

Expand All @@ -80,7 +88,7 @@
pub fn output_dir(&self, variant: &Variant) -> &str {
match variant {
Variant::GEProton => &self.version,
Variant::WineGE => &self.download_url.rsplit_once("/wine-").unwrap().1.rsplit_once(".tar.xz").unwrap().0

Check warning on line 91 in libprotonup/src/github.rs

View workflow job for this annotation

GitHub Actions / clippy_check

this expression creates a reference which is immediately dereferenced by the compiler
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions libprotonup/src/variants.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use super::constants::*;
use std::{fmt, str::FromStr};

/// Struct used to build GitHub api request URLs.
/// Contains the GitHub URL, username for GE, the repository name for either Wine GE or Proton GE, and a Variant Enum for identifying the parameters type
/// Struct used to build GitHub API request URLs.
///
/// Contains the GitHub URL, the username for GE,
/// the repository name for either Wine GE or Proton GE,
/// and a Variant Enum for identifying the parameters type
pub struct VariantGithubParameters {
/// this is a link back to the enum variant
variant_ref: Variant,
Expand Down Expand Up @@ -44,7 +47,7 @@ pub enum Variant {
}

impl fmt::Display for Variant {
/// returns a string representation of this variant
/// Returns a string representation of this Variant
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Variant::GEProton => write!(f, "GEProton"),
Expand All @@ -65,7 +68,7 @@ impl FromStr for Variant {
}

impl Variant {
/// returns the application target for the Variant. Steam and Lutris are the current options
/// Returns the application target for the Variant. Steam and Lutris are the current options
pub fn intended_application(&self) -> &str {
match self {
Variant::GEProton => "Steam",
Expand All @@ -92,5 +95,5 @@ impl Variant {
}
}

// ALL_VARIANTS is a shorthand to all app variants
/// ALL_VARIANTS is a shorthand to all app variants
pub static ALL_VARIANTS: &[Variant] = &[Variant::GEProton, Variant::WineGE];
14 changes: 9 additions & 5 deletions protonup-rs/src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
variants::{self, Variant},
};

/// Downloads the requested file to the /tmp directory
pub(crate) async fn download_file(download: Download) -> Result<PathBuf, String> {
let mut temp_dir = utils::expand_tilde(constants::TEMP_DIR).unwrap();

Expand Down Expand Up @@ -87,8 +88,11 @@
Ok(temp_dir)
}

/// Prepares downloaded file to be decompressed
///
/// Parses the passed in data and ensures the destination directory is created
pub(crate) async fn unpack_file(
dowaload_path: &Path,
download_path: &Path,
install_path: &str,
wine_version: &Variant,
) -> Result<(), String> {
Expand All @@ -97,7 +101,7 @@
fs::create_dir_all(&install_dir).unwrap();

println!("Unpacking files into install location. Please wait");
files::decompress(dowaload_path, install_dir.as_path()).unwrap();
files::decompress(download_path, install_dir.as_path()).unwrap();
println!(
"Done! Restart {}. {} installed in {}",
wine_version.intended_application(),
Expand All @@ -107,6 +111,7 @@
Ok(())
}

/// Downloads the latest wine version for all the apps found
pub async fn run_quick_downloads(force: bool) {
let found_apps = apps::list_installed_apps();
if found_apps.is_empty() {
Expand Down Expand Up @@ -161,6 +166,7 @@
}

/// Start the Download for the selected app
///
/// If no app is provided, the user is prompted for which version of Wine/Proton to use and what directory to extract to
pub async fn download_to_selected_app(app: Option<apps::App>) {
// Get the version of Wine/Proton to install
Expand All @@ -180,12 +186,11 @@
let install_dir: String = match app {
// If the user selected an app (Steam/Lutris)...
Some(app) => match app.detect_installation_method() {
installed_apps if installed_apps.len() == 0 => {

Check warning on line 189 in protonup-rs/src/download.rs

View workflow job for this annotation

GitHub Actions / clippy_check

length comparison to zero
println!("Install location for selected app(s) not found. Exiting.");
std::process::exit(0);
}


// Figure out which versions of the App the user has (Native/Flatpak)
installed_apps if installed_apps.len() == 1 => {
println!(
Expand Down Expand Up @@ -231,8 +236,6 @@
}
};

// versions_to_install = vec![];

// Let the user choose which releases they want to use
let mut release_list = helper_menus::multiple_select_menu(
"Select the versions you want to download :",
Expand Down Expand Up @@ -266,12 +269,13 @@
}

/// Checks if the selected Release/version is already installed.
///
/// Will prompt the user to overwrite existing files
async fn check_if_already_downloaded(release_list: &mut Vec<Release>, install_dir: &str) {
release_list.retain(|release| {
// Check if versions exist in disk.
// If they do, ask the user if it should be overwritten
!(files::check_if_exists(&install_dir, &release.tag_name)

Check warning on line 278 in protonup-rs/src/download.rs

View workflow job for this annotation

GitHub Actions / clippy_check

this boolean expression can be simplified

Check warning on line 278 in protonup-rs/src/download.rs

View workflow job for this annotation

GitHub Actions / clippy_check

this expression creates a reference which is immediately dereferenced by the compiler
&& !helper_menus::confirm_menu(
format!(
"Version {} exists in the installation path. Overwrite?",
Expand Down
3 changes: 2 additions & 1 deletion protonup-rs/src/file_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ impl FilePathCompleter {
let mut ret: String = String::new();

let mut sorted = self.paths.clone();
sorted.sort();
if sorted.is_empty() {
return ret;
}
sorted.sort();


let mut first_word = sorted.first().unwrap().chars();
let mut last_word = sorted.last().unwrap().chars();
Expand Down
7 changes: 6 additions & 1 deletion protonup-rs/src/helper_menus.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use inquire::{Confirm, InquireError, MultiSelect};

/// Creates a inquire::MultiSelect menu with the first option selected
/// Prompt the user to select multiple possible options with an inquire::MultiSelect menu
///
/// The first option is selected
pub(crate) fn multiple_select_menu<T>(
message: &str,
options: Vec<T>,
Expand All @@ -13,6 +15,9 @@ where
.prompt()
}

/// Prompt the user [Y/n] with an inquire::Confirm menu
///
/// `help_text` and `default` are used to set default values
pub(crate) fn confirm_menu(text: String, help_text: String, default: bool) -> bool {
let answer = Confirm::new(&text)
.with_default(default)
Expand Down