diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..560944124 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,37 @@ +name: Clippy + +on: + push: + branches: [ master ] + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Cache build artifacts + id: cache-build + uses: actions/cache@v2 + with: + path: target/** + key: ${{ runner.os }}-build-cache + - name: Theseus Clippy + uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --bin theseus + - name: Theseus CLI Clippy + uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --bin theseus_cli \ No newline at end of file diff --git a/COPYING.md b/COPYING.md new file mode 100644 index 000000000..e7563b93d --- /dev/null +++ b/COPYING.md @@ -0,0 +1,13 @@ +# Copying + +The source code of the knossos repository is licensed under the GNU Affero General Public License, Version 3 only, which is provided in the file [LICENSE](./LICENSE). However, some files listed below are licensed under a different license. + +## Modrinth logo + +Any files depicting the Modrinth branding, including the wrench-in-labyrinth logo, the landing image, and variations thereof, are licensed as follows: + +> All rights reserved. © 2020-2023 Rinth, Inc. + +This includes, but may not be limited to, the following files: + +- theseus_gui/src-tauri/icons diff --git a/theseus/src/api/auth.rs b/theseus/src/api/auth.rs index 8e9951824..5a2c3a13d 100644 --- a/theseus/src/api/auth.rs +++ b/theseus/src/api/auth.rs @@ -88,7 +88,7 @@ pub async fn has_user(user: uuid::Uuid) -> crate::Result { let state = State::get().await?; let users = state.users.read().await; - Ok(users.contains(user)?) + users.contains(user) } /// Get a copy of the list of all user credentials diff --git a/theseus/src/api/profile.rs b/theseus/src/api/profile.rs index 68f059e08..de4820e84 100644 --- a/theseus/src/api/profile.rs +++ b/theseus/src/api/profile.rs @@ -68,12 +68,7 @@ pub async fn is_managed(profile: &Path) -> crate::Result { pub async fn is_loaded(profile: &Path) -> crate::Result { let state = State::get().await?; let profiles = state.profiles.read().await; - Ok(profiles - .0 - .get(profile) - .map(Option::as_ref) - .flatten() - .is_some()) + Ok(profiles.0.get(profile).and_then(Option::as_ref).is_some()) } /// Edit a profile using a given asynchronous closure @@ -138,8 +133,8 @@ pub async fn run( })?; let version_info = d::minecraft::fetch_version_info(version).await?; - let ref pre_launch_hooks = - profile.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch; + let pre_launch_hooks = + &profile.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch; for hook in pre_launch_hooks.iter() { // TODO: hook parameters let mut cmd = hook.split(' '); @@ -190,7 +185,7 @@ pub async fn run( .as_error()); } - let ref java_args = profile + let java_args = profile .java .as_ref() .and_then(|it| it.extra_arguments.as_ref()) @@ -201,18 +196,18 @@ pub async fn run( .as_ref() .map_or(&settings.hooks.wrapper, |it| &it.wrapper); - let ref memory = profile.memory.unwrap_or(settings.memory); - let ref resolution = profile.resolution.unwrap_or(settings.game_resolution); + let memory = profile.memory.unwrap_or(settings.memory); + let resolution = profile.resolution.unwrap_or(settings.game_resolution); crate::launcher::launch_minecraft( &profile.metadata.game_version, &profile.metadata.loader_version, &profile.path, - &java_install, - &java_args, - &wrapper, - memory, - resolution, + java_install, + java_args, + wrapper, + &memory, + &resolution, credentials, ) .await diff --git a/theseus/src/launcher/args.rs b/theseus/src/launcher/args.rs index 20d9becaf..9724adf5b 100644 --- a/theseus/src/launcher/args.rs +++ b/theseus/src/launcher/args.rs @@ -68,7 +68,7 @@ pub fn get_class_paths_jar>( pub fn get_lib_path(libraries_path: &Path, lib: &str) -> crate::Result { let mut path = libraries_path.to_path_buf(); - path.push(get_path_from_artifact(lib.as_ref())?); + path.push(get_path_from_artifact(lib)?); let path = &path.canonicalize().map_err(|_| { crate::ErrorKind::LauncherError(format!( @@ -164,8 +164,7 @@ fn parse_jvm_argument( )) .as_error() })? - .to_string_lossy() - .to_string(), + .to_string_lossy(), ) .replace("${classpath_separator}", classpath_separator()) .replace("${launcher_name}", "theseus") @@ -219,7 +218,6 @@ pub fn get_minecraft_arguments( resolution, )? .split(' ') - .into_iter() .map(|x| x.to_string()) .collect()) } else { @@ -260,8 +258,7 @@ fn parse_minecraft_argument( )) .as_error() })? - .to_string_lossy() - .to_owned(), + .to_string_lossy(), ) .replace( "${assets_root}", @@ -274,8 +271,7 @@ fn parse_minecraft_argument( )) .as_error() })? - .to_string_lossy() - .to_owned(), + .to_string_lossy(), ) .replace( "${game_assets}", @@ -288,8 +284,7 @@ fn parse_minecraft_argument( )) .as_error() })? - .to_string_lossy() - .to_owned(), + .to_string_lossy(), ) .replace("${version_type}", version_type.as_str()) .replace("${resolution_width}", &resolution.0.to_string()) @@ -366,7 +361,7 @@ pub fn get_processor_arguments>( pub async fn get_processor_main_class( path: String, ) -> crate::Result> { - Ok(tokio::task::spawn_blocking(move || { + tokio::task::spawn_blocking(move || { let zipfile = std::fs::File::open(&path)?; let mut archive = zip::ZipArchive::new(zipfile).map_err(|_| { crate::ErrorKind::LauncherError(format!( @@ -400,5 +395,5 @@ pub async fn get_processor_main_class( Ok::, crate::Error>(None) }) .await - .unwrap()?) + .unwrap() } diff --git a/theseus/src/launcher/auth.rs b/theseus/src/launcher/auth.rs index b12d1d428..c7410ee77 100644 --- a/theseus/src/launcher/auth.rs +++ b/theseus/src/launcher/auth.rs @@ -3,12 +3,14 @@ use async_tungstenite as ws; use bincode::{Decode, Encode}; use chrono::{prelude::*, Duration}; use futures::prelude::*; -use once_cell::sync::*; +use lazy_static::lazy_static; use serde::Deserialize; use url::Url; -pub const HYDRA_URL: Lazy = - Lazy::new(|| Url::parse("https://hydra.modrinth.com").unwrap()); +lazy_static! { + static ref HYDRA_URL: Url = + Url::parse("https://hydra.modrinth.com").unwrap(); +} // Socket messages #[derive(Deserialize)] @@ -65,7 +67,7 @@ pub struct HydraAuthFlow { impl HydraAuthFlow { pub async fn new() -> crate::Result { let sock_url = wrap_ref_builder!( - it = HYDRA_URL => + it = HYDRA_URL.clone() => { it.set_scheme("wss").ok() } ); let (socket, _) = ws::tokio::connect_async(sock_url.clone()).await?; diff --git a/theseus/src/launcher/download.rs b/theseus/src/launcher/download.rs index af9a8d2e5..601b610dc 100644 --- a/theseus/src/launcher/download.rs +++ b/theseus/src/launcher/download.rs @@ -75,7 +75,7 @@ pub async fn download_client( st: &State, version_info: &GameVersionInfo, ) -> crate::Result<()> { - let ref version = version_info.id; + let version = &version_info.id; log::debug!("Locating client for version {version}"); let client_download = version_info .downloads @@ -143,7 +143,7 @@ pub async fn download_assets( stream::iter(index.objects.iter()) .map(Ok::<(&String, &Asset), crate::Error>) .try_for_each_concurrent(None, |(name, asset)| async move { - let ref hash = asset.hash; + let hash = &asset.hash; let resource_path = st.directories.object_dir(hash); let url = format!( "https://resources.download.minecraft.net/{sub_hash}/{hash}", @@ -158,7 +158,7 @@ pub async fn download_assets( let resource = fetch_cell .get_or_try_init(|| fetch(&url, Some(hash), &permit)) .await?; - write(&resource_path, &resource, &permit).await?; + write(&resource_path, resource, &permit).await?; log::info!("Fetched asset with hash {hash}"); } Ok::<_, crate::Error>(()) @@ -172,7 +172,7 @@ pub async fn download_assets( let resource_path = st.directories.legacy_assets_dir().join( name.replace('/', &String::from(std::path::MAIN_SEPARATOR)) ); - write(&resource_path, &resource, &permit).await?; + write(&resource_path, resource, &permit).await?; log::info!("Fetched legacy asset with hash {hash}"); } Ok::<_, crate::Error>(()) diff --git a/theseus/src/launcher/mod.rs b/theseus/src/launcher/mod.rs index 21ede9cfb..49c1b1d02 100644 --- a/theseus/src/launcher/mod.rs +++ b/theseus/src/launcher/mod.rs @@ -44,6 +44,7 @@ macro_rules! processor_rules { } } +#[allow(clippy::too_many_arguments)] #[tracing::instrument(skip_all, fields(path = ?instance_path))] pub async fn launch_minecraft( game_version: &str, @@ -75,7 +76,7 @@ pub async fn launch_minecraft( let mut version_info = download::download_version_info( &state, - &version, + version, loader_version.as_ref(), ) .await?; diff --git a/theseus/src/state/metadata.rs b/theseus/src/state/metadata.rs index 6fdef0839..89251efe0 100644 --- a/theseus/src/state/metadata.rs +++ b/theseus/src/state/metadata.rs @@ -57,7 +57,7 @@ impl Metadata { if let Some(ref meta_bin) = db.get(METADATA_DB_FIELD)? { match bincode::decode_from_slice::( - &meta_bin, + meta_bin, *BINCODE_CONFIG, ) { Ok((meta, _)) => metadata = Some(meta), diff --git a/theseus/src/state/profiles.rs b/theseus/src/state/profiles.rs index 9f6fd7d17..ce8049d48 100644 --- a/theseus/src/state/profiles.rs +++ b/theseus/src/state/profiles.rs @@ -18,7 +18,7 @@ pub(crate) struct Profiles(pub HashMap>); // TODO: possibly add defaults to some of these values pub const CURRENT_FORMAT_VERSION: u32 = 1; -pub const SUPPORTED_ICON_FORMATS: &[&'static str] = &[ +pub const SUPPORTED_ICON_FORMATS: &[&str] = &[ "bmp", "gif", "jpeg", "jpg", "jpe", "png", "svg", "svgz", "webp", "rgb", "mp4", ]; @@ -54,26 +54,23 @@ pub struct ProfileMetadata { } // TODO: Quilt? -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[derive( + Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default, +)] #[serde(rename_all = "lowercase")] pub enum ModLoader { + #[default] Vanilla, Forge, Fabric, } -impl Default for ModLoader { - fn default() -> Self { - ModLoader::Vanilla - } -} - impl std::fmt::Display for ModLoader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - &Self::Vanilla => "Vanilla", - &Self::Forge => "Forge", - &Self::Fabric => "Fabric", + f.write_str(match *self { + Self::Vanilla => "Vanilla", + Self::Forge => "Forge", + Self::Fabric => "Fabric", }) } } @@ -237,7 +234,7 @@ impl Profiles { // project path, parent profile path let mut files: HashMap = HashMap::new(); { - for (profile_path, _profile_optZA) in profiles.iter() { + for (profile_path, _profile_opt) in profiles.iter() { let mut read_paths = |path: &str| { for path in std::fs::read_dir(profile_path.join(path))? { files.insert(path?.path(), profile_path.clone()); @@ -252,17 +249,15 @@ impl Profiles { } } let inferred = super::projects::infer_data_from_files( - files.keys().into_iter().cloned().collect(), + files.keys().cloned().collect(), dirs.caches_dir(), ) .await?; for (key, value) in inferred { if let Some(profile_path) = files.get(&key) { - if let Some(profile) = profiles.get_mut(profile_path) { - if let Some(profile) = profile { - profile.projects.insert(key, value); - } + if let Some(Some(profile)) = profiles.get_mut(profile_path) { + profile.projects.insert(key, value); } } } diff --git a/theseus/src/state/projects.rs b/theseus/src/state/projects.rs index daa649032..c504ebc49 100644 --- a/theseus/src/state/projects.rs +++ b/theseus/src/state/projects.rs @@ -52,7 +52,7 @@ pub struct ModrinthProject { #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ProjectMetadata { - Modrinth(ModrinthProject), + Modrinth(Box), Inferred { title: Option, description: Option, @@ -126,7 +126,9 @@ pub async fn infer_data_from_files( Project { sha512: hash, disabled: false, - metadata: ProjectMetadata::Modrinth(project.clone()), + metadata: ProjectMetadata::Modrinth(Box::new( + project.clone(), + )), }, ); continue; @@ -342,10 +344,7 @@ pub async fn infer_data_from_files( if file.read_to_string(&mut file_str).is_ok() { if let Ok(pack) = serde_json::from_str::(&file_str) { let icon = read_icon_from_file( - pack.metadata - .as_ref() - .map(|x| x.icon.clone()) - .flatten(), + pack.metadata.as_ref().and_then(|x| x.icon.clone()), )?; return_projects.insert( @@ -357,15 +356,13 @@ pub async fn infer_data_from_files( title: Some( pack.metadata .as_ref() - .map(|x| x.name.clone()) - .flatten() + .and_then(|x| x.name.clone()) .unwrap_or(pack.id), ), description: pack .metadata .as_ref() - .map(|x| x.description.clone()) - .flatten(), + .and_then(|x| x.description.clone()), authors: pack .metadata .map(|x| { diff --git a/theseus/src/state/settings.rs b/theseus/src/state/settings.rs index 563998d11..ae688d514 100644 --- a/theseus/src/state/settings.rs +++ b/theseus/src/state/settings.rs @@ -103,7 +103,7 @@ impl Default for WindowSize { } /// Game initialization hooks -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(default)] pub struct Hooks { #[serde(skip_serializing_if = "HashSet::is_empty")] @@ -113,13 +113,3 @@ pub struct Hooks { #[serde(skip_serializing_if = "HashSet::is_empty")] pub post_exit: HashSet, } - -impl Default for Hooks { - fn default() -> Self { - Self { - pre_launch: HashSet::::new(), - wrapper: None, - post_exit: HashSet::::new(), - } - } -} diff --git a/theseus/src/util/fetch.rs b/theseus/src/util/fetch.rs index eea15f705..2787cb562 100644 --- a/theseus/src/util/fetch.rs +++ b/theseus/src/util/fetch.rs @@ -57,7 +57,7 @@ pub async fn fetch_mirrors( let _permits = sem.acquire_many(permits).await.unwrap(); let sem = Arc::new(Semaphore::new(permits.try_into().unwrap())); - future::select_ok(urls.into_iter().map(|url| { + future::select_ok(urls.iter().map(|url| { let sha1 = sha1.map(String::from); let url = String::from(*url); let sem = Arc::clone(&sem); diff --git a/theseus/src/util/jre.rs b/theseus/src/util/jre.rs index d29757e97..d433696c3 100644 --- a/theseus/src/util/jre.rs +++ b/theseus/src/util/jre.rs @@ -185,11 +185,11 @@ pub fn get_all_jre_path() -> Result, JREError> { #[cfg(target_os = "windows")] #[allow(dead_code)] -const JAVA_BIN: &'static str = "java.exe"; +const JAVA_BIN: &str = "java.exe"; #[cfg(not(target_os = "windows"))] #[allow(dead_code)] -const JAVA_BIN: &'static str = "java"; +const JAVA_BIN: &str = "java"; // For example filepath 'path', attempt to resolve it and get a Java version at this path // If no such path exists, or no such valid java at this path exists, returns None diff --git a/theseus/src/util/platform.rs b/theseus/src/util/platform.rs index b403d8844..c41534548 100644 --- a/theseus/src/util/platform.rs +++ b/theseus/src/util/platform.rs @@ -31,11 +31,7 @@ pub fn os_rule(rule: &OsRule) -> bool { let mut rule_match = true; if let Some(ref arch) = rule.arch { - rule_match &= match arch.as_str() { - "x86" => cfg!(any(target_arch = "x86", target_arch = "x86_64")), - "arm" => cfg!(target_arch = "arm"), - _ => true, - }; + rule_match &= !matches!(arch.as_str(), "x86" | "arm"); } if let Some(name) = &rule.name { diff --git a/theseus_gui/src-tauri/tauri.conf.json b/theseus_gui/src-tauri/tauri.conf.json index e555e8375..5d0697a57 100644 --- a/theseus_gui/src-tauri/tauri.conf.json +++ b/theseus_gui/src-tauri/tauri.conf.json @@ -26,7 +26,13 @@ "depends": [] }, "externalBin": [], - "icon": ["icons/favicon.ico"], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], "identifier": "com.modrinth.theseus", "longDescription": "", "macOS": {