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

Fix selecting a Proton version not downloading #17

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
513 changes: 265 additions & 248 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ Options:
wget https://github.com/auyer/Protonup-rs/releases/latest/download/protonup-rs-linux-amd64.tar.gz -O - | tar -xz && zenity --password | sudo -S mv protonup-rs /usr/bin/
```

This assumes `/usr/bin` is in your path. You may change this to any other location (in your path `echo $PATH`).

This assumes `/usr/bin` is in your path. You may change this to any other location (in your path ```echo $PATH```).


### Or manually:

Expand Down
9 changes: 1 addition & 8 deletions libprotonup/src/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,7 @@ impl fmt::Display for App {
}

impl App {
pub fn app_available_variants(&self) -> Vec<Variant> {
match *self {
Self::Steam => vec![Variant::GEProton],
Self::Lutris => vec![Variant::WineGE, Variant::GEProton],
}
}

pub fn app_default_variant(&self) -> Variant {
pub fn app_wine_version(&self) -> Variant {
match *self {
Self::Steam => Variant::GEProton,
Self::Lutris => Variant::WineGE,
Expand Down
167 changes: 63 additions & 104 deletions libprotonup/src/github.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,65 @@
use crate::constants;
use crate::variants::VariantParameters;
use crate::variants::VariantGithubParameters;
use anyhow::Result;
use serde::{Deserialize, Serialize};

pub type ReleaseList = Vec<Release>;

#[derive(Serialize, Deserialize, Debug)]
pub struct Release {
url: String,
/// API URL of the Release
url: Option<String>,
/// Tag name of the Release, examples "8.7-GE-1-Lol" "GE-Proton8-5"
pub tag_name: String,
/// Release post name, examples "Wine-GE-Proton8-5 Released" " Lutris-GE-8.7-1-LoL"
name: String,
published_at: String,
/// Asset list for each Release, usually the tar.gz/tar.xz file and a sha512sum file for integrity checking
assets: Vec<Asset>,
}

impl std::fmt::Display for Release {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.tag_name)
}
}

impl Release {
/// 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();
} else if asset.name.ends_with("tar.gz") || asset.name.ends_with("tar.xz") {
download.download_url = asset.browser_download_url.clone();
download.size = asset.size as u64;
}
}

download
}
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Asset {
/// API URL of the Asset
url: String,
/// API ID of the Asset
id: i64,
/// File name of the Asset
name: String,
/// Size in Bytes, divide by 1_000_000 for MB
size: i64,
created_at: String,
updated_at: String,
/// Direct download URL
browser_download_url: String,
}

pub async fn list_releases(source: &VariantParameters) -> Result<ReleaseList, reqwest::Error> {
/// Returns a Vec of Releases from a GitHub repository, the URL used for the request is built from the passed in VariantParameters
pub async fn list_releases(
source: &VariantGithubParameters,
) -> Result<ReleaseList, reqwest::Error> {
let agent = format!("{}/v{}", constants::USER_AGENT, constants::VERSION,);

let url = format!(
Expand All @@ -42,131 +76,48 @@

#[derive(Default, Debug, PartialEq, Clone)]
pub struct Download {
/// Proton or Wine GE version, based off tag
pub version: String,
pub sha512sum: String,
pub download: String,
/// URL to download the sha512sum for this Download
pub sha512sum_url: String,
/// URL to download the Wine or Proton archive
pub download_url: String,
/// Size of Wine or Proton archive in Bytes
pub size: u64,
pub created_at: String,
}

pub async fn fetch_data_from_tag(
tag: &str,
source: &VariantParameters,
) -> Result<Download, reqwest::Error> {
let agent = format!("{}/v{}", constants::USER_AGENT, constants::VERSION,);

let client = reqwest::Client::builder().user_agent(agent).build()?;

let mut download = Download::default();
let release = match tag {
"latest" => {
let url = format!(
"{}/{}/{}/releases/latest",
source.repository_url, source.repository_account, source.repository_name,
);
let rel: Release = client.get(url).send().await?.json().await?;
rel
}
_ => {
let url = format!(
"{}/{}/{}/releases/tags/{}",
source.repository_url, source.repository_account, source.repository_name, &tag
);
let rel: Release = client.get(url).send().await?.json().await?;
rel
}
};

download.version = release.tag_name;
for asset in &release.assets {
if asset.name.ends_with("sha512sum") {
download.sha512sum = asset.browser_download_url.as_str().to_string();
}
if asset.name.ends_with("tar.gz") {
download.created_at = asset.created_at.clone();
download.download = asset.browser_download_url.as_str().to_string();
download.size = asset.size as u64;
}
if asset.name.ends_with("tar.xz") {
download.created_at = asset.created_at.clone();
download.download = asset.browser_download_url.as_str().to_string();
download.size = asset.size as u64;
}
}
Ok(download)
}
#[cfg(test)]
mod tests {
use crate::variants;

use super::*;

#[tokio::test]
async fn test_fetch_data_from_tag() {
async fn test_list_releases() {
let conditions = &[
(
variants::Variant::WineGE.parameters(),
"latest",
"Get Steam",
variants::Variant::WineGE.get_github_parameters(),
"List WineGE",
),
(
variants::Variant::GEProton.parameters(),
"latest",
"Download Lutris",
variants::Variant::GEProton.get_github_parameters(),
"List GEProton",
),
];
for (source_parameters, tag, desc) in conditions {
let result = fetch_data_from_tag(tag, source_parameters).await;

assert!(
result.is_ok(),
"case :{} test: fetch_data_from_tag returned error",
desc
);

let result = result.unwrap();

assert!(
result.download.len() > 5,
"case : '{}' test: fetch_data_from_tag returned an wrong download link",
desc
);
assert!(
result.sha512sum.len() > 5,
"case : '{}' test: fetch_data_from_tag returned an wrong sha512sum",
desc
);
assert!(
result.size > 100,
"case : '{}' test: fetch_data_from_tag returned an wrong sha512sum",
desc
);
assert!(
result.version.len() > 2,
"case : '{}' test: fetch_data_from_tag returned an wrong version",
desc
);
}
}

#[tokio::test]
async fn test_list_releases() {
let conditions = &[
(variants::Variant::WineGE.parameters(), "List WineGE"),
(variants::Variant::GEProton.parameters(), "List GEProton"),
];

for (source_parameters, desc) in conditions {
let result = list_releases(source_parameters).await;

assert!(
result.is_ok(),
"case : '{}' test: fetch_data_from_tag returned error",
"case : '{}' test: list_releases returned error",
desc
);

let result = result.unwrap();

println!("Got result: {result:?}");

assert!(
result.len() > 1,
"case : '{}' test: test_list_releases returned an empty list",
Expand All @@ -188,8 +139,14 @@
};

let conditions = &[
(variants::Variant::WineGE.parameters(), "Get WineGE"),
(variants::Variant::GEProton.parameters(), "Get GEProton"),
(
variants::Variant::WineGE.get_github_parameters(),
"Get WineGE",
),
(
variants::Variant::GEProton.get_github_parameters(),
"Get GEProton",
),
];
for (source_parameters, desc) in conditions {
let url = format!(
Expand All @@ -208,6 +165,8 @@
.json::<Release>()
.await;

println!("Got result: {rel:?}");

assert!(
rel.is_ok(),
"case : '{}' test: test_get_release wrong",
Expand Down
2 changes: 2 additions & 0 deletions libprotonup/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::path::{Path, PathBuf};

/// Will convert the ~ tilde character to the user's home directory, fixes reading PathBufs that have a ~ tilde.
pub fn expand_tilde<P: AsRef<Path>>(path_user_input: P) -> Option<PathBuf> {
let p = path_user_input.as_ref();
if !p.starts_with("~") {
return Some(p.to_path_buf());
}
// If the path is just a tilde, simply return the user's home
if p == Path::new("~") {
return dirs::home_dir();
}
Expand Down
23 changes: 13 additions & 10 deletions libprotonup/src/variants.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::constants::*;
use std::{fmt, str::FromStr};
// VariantParameters stores the parameters for a variant of Proton
pub struct VariantParameters {

/// 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
pub struct VariantGithubParameters {
/// this is a link back to the enum variant
variant_ref: Variant,
/// URL of the repository server (GitHub compatible URL only at the moment)
Expand All @@ -12,23 +14,23 @@ pub struct VariantParameters {
pub repository_name: String,
}

impl VariantParameters {
impl VariantGithubParameters {
/// new_custom is a generator for custom VariantParameters
pub fn new_custom(
variant: Variant,
repository_url: String,
repository_account: String,
repository_name: String,
) -> VariantParameters {
VariantParameters {
) -> VariantGithubParameters {
VariantGithubParameters {
variant_ref: variant,
repository_url,
repository_account,
repository_name,
}
}

///
/// Returns the VariantParameters' Variant enum
pub fn variant_type(&self) -> &Variant {
&self.variant_ref
}
Expand All @@ -53,6 +55,7 @@ impl fmt::Display for Variant {

impl FromStr for Variant {
type Err = ();
/// Converts a "GEProton" or "WineGE" string into its respective Variant
fn from_str(input: &str) -> Result<Variant, Self::Err> {
match input {
"GEProton" => Ok(Variant::GEProton),
Expand All @@ -71,16 +74,16 @@ impl Variant {
}
}

/// returns the default parameters for this Variant.
pub fn parameters(&self) -> VariantParameters {
/// Returns the default parameters for this Variant, used to build the GitHub URL
pub fn get_github_parameters(&self) -> VariantGithubParameters {
match self {
Variant::GEProton => VariantParameters {
Variant::GEProton => VariantGithubParameters {
variant_ref: Variant::GEProton,
repository_url: GITHUB_URL.to_owned(),
repository_name: GEPROTON_GITHUB_REPO.to_owned(),
repository_account: GE_GITHUB_ACCOUNT.to_owned(),
},
Variant::WineGE => VariantParameters {
Variant::WineGE => VariantGithubParameters {
variant_ref: Variant::WineGE,
repository_url: GITHUB_URL.to_owned(),
repository_name: WINEGE_GITHUB_REPO.to_owned(),
Expand Down
Loading
Loading