Skip to content

Commit

Permalink
support for new dependencies syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
HJfod committed Jan 14, 2025
1 parent b0736a2 commit e6f4899
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "geode"
version = "3.4.0"
version = "3.5.0"
authors = [
"HJfod <[email protected]>",
"Camila314 <[email protected]>",
Expand Down
4 changes: 2 additions & 2 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@ pub fn subcommand(cmd: Index) {
let config = &mut _config;
match cmd {
Index::Install { id, version } => {
let mut config = Config::new().assert_is_setup();
let config = Config::new().assert_is_setup();
install_mod(
&mut config,
&config,
&id,
&version.unwrap_or(VersionReq::STAR),
false,
Expand Down
20 changes: 8 additions & 12 deletions src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ pub fn check_dependencies(
});

// check all dependencies
for dep in mod_info.dependencies {
for dep in &mod_info.dependencies {
// Skip dependencies not on this platform
if !dep.platforms.contains(&platform) {
continue;
Expand Down Expand Up @@ -349,7 +349,7 @@ pub fn check_dependencies(
// otherwise try to find it on installed mods and then on index

// check index
let found_in_index = match find_index_dependency(&dep, &config) {
let found_in_index = match find_index_dependency(dep, &config) {
Ok(f) => f,
Err(e) => {
warn!("Failed to fetch dependency {} from index: {}", &dep.id, e);
Expand All @@ -358,16 +358,14 @@ pub fn check_dependencies(
};
// check installed mods
let found_in_installed =
find_dependency(&dep, &config.get_current_profile().mods_dir(), true, false)
find_dependency(dep, &config.get_current_profile().mods_dir(), true, false)
.nice_unwrap("Unable to read installed mods");

// if not found in either hjfod code
if !matches!(found_in_index, Found::Some(_, _))
&& !matches!(found_in_installed, Found::Some(_, _))
{
if dep.importance == DependencyImportance::Required
|| dep.required.is_some() && dep.required.unwrap()
{
if dep.importance == DependencyImportance::Required {
fail!(
"Dependency '{0}' not found in installed mods nor index! \
If this is a mod that hasn't been published yet, install it \
Expand Down Expand Up @@ -515,12 +513,10 @@ pub fn check_dependencies(
// add a note saying if the dependencey is required or not (for cmake to
// know if to link or not)
fs::write(
dep_dir.join(dep.id).join("geode-dep-options.json"),
dep_dir.join(&dep.id).join("geode-dep-options.json"),
format!(
r#"{{ "required": {} }}"#,
if dep.importance == DependencyImportance::Required
|| dep.required.is_some() && dep.required.unwrap()
{
if dep.importance == DependencyImportance::Required {
"true"
} else {
"false"
Expand Down Expand Up @@ -552,7 +548,7 @@ fn add_resource(dir: &Path, resource: ResourceType, files: Vec<PathBuf>) {
let mut new_resource: Vec<Value> = resource.into_iter().chain(files.clone().into_iter().filter_map(|x| {
if !x.exists() {
warn!("{} {} does not exist", othername, x.display());
return None
None
} else {
Some(Value::String(x.as_os_str().to_str().unwrap().to_string()))
}
Expand Down Expand Up @@ -584,7 +580,7 @@ fn add_resource(dir: &Path, resource: ResourceType, files: Vec<PathBuf>) {
let mut new_fonts: Vec<Value> = fonts.into_iter().chain(files.into_iter().filter_map(|x| {
if !x.exists() {
warn!("Font {} does not exist", x.display());
return None
None
} else {
Some(json!({
"path": x.as_os_str().to_str().unwrap().to_string(),
Expand Down
98 changes: 92 additions & 6 deletions src/util/mod_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::spritesheet::SpriteSheet;
use crate::NiceUnwrap;
use clap::ValueEnum;
use semver::{Version, VersionReq};
use serde::{Deserialize, Deserializer};
use serde::{Deserialize, Deserializer, de::Error};
use std::collections::{HashMap, HashSet};
use std::fmt::Display;
use std::fs;
Expand Down Expand Up @@ -122,7 +122,7 @@ where
Ok(<HashMap<String, BitmapFont>>::deserialize(deserializer)?
.into_iter()
.map(|(name, mut font)| {
font.name = name.clone();
font.name.clone_from(&name);
font.path = std::env::current_dir().unwrap().join(font.path);
(name, font)
})
Expand Down Expand Up @@ -286,18 +286,104 @@ pub enum DependencyImportance {
Suggested,
}

#[derive(Default, Deserialize, PartialEq)]
#[derive(Deserialize, PartialEq)]
pub struct Dependency {
#[serde(skip)]
pub id: String,
#[serde(deserialize_with = "parse_comparable_version")]
pub version: VersionReq,
#[serde(default)]
pub importance: DependencyImportance,
pub required: Option<bool>,
#[serde(default = "all_platforms")]
pub platforms: HashSet<PlatformName>,
}

#[derive(Deserialize, PartialEq)]
pub struct LegacyDependency {
pub id: String,
#[serde(deserialize_with = "parse_comparable_version")]
pub version: VersionReq,
#[serde(default)]
pub importance: DependencyImportance,
#[serde(default = "all_platforms")]
pub platforms: HashSet<PlatformName>,
}

#[derive(PartialEq)]
pub struct Dependencies(HashMap<String, Dependency>);

impl Dependencies {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}

impl<'a> IntoIterator for &'a Dependencies {
type IntoIter = std::collections::hash_map::Values<'a, String, Dependency>;
type Item = &'a Dependency;
fn into_iter(self) -> Self::IntoIter {
self.0.values()
}
}

// No it can't clippy Dependency doesn't impl Default
#[allow(clippy::derivable_impls)]
impl Default for Dependencies {
fn default() -> Self {
Self(HashMap::new())
}
}

fn parse_dependencies<'de, D>(deserializer: D) -> Result<Dependencies, D::Error>
where
D: Deserializer<'de>,
{
// This is all to avoid union types having terrible errors
// (they just log "failed to parse any variant of X")

// This is needed because deserializer is moved
let value = serde_json::Value::deserialize(deserializer)?;

match <HashMap<String, serde_json::Value>>::deserialize(value.clone()) {
Ok(deps) => Ok(Dependencies(
deps.into_iter().map(|(id, json)| {
// Shorthand is just "[mod.id]": "[version]"
match parse_comparable_version(json.clone()) {
Ok(version) => Ok(Dependency {
id: id.clone(),
version,
importance: DependencyImportance::Required,
platforms: all_platforms(),
}),
// Longhand is "[mod.id]": { ... }
Err(_) => Dependency::deserialize(json)
// The ID isn't parsed from the object itself but is the key
.map(|mut d| { d.id.clone_from(&id); d })
.map_err(D::Error::custom)
}.map(|r| (id, r))
}).collect::<Result<_, _>>()?
)),
Err(e) => {
// Can be removed after Geode hits v5
match <Vec<LegacyDependency>>::deserialize(value) {
Ok(deps) => {
let mut res = Dependencies::default();
for dep in deps {
res.0.insert(dep.id.clone(), Dependency {
id: dep.id,
version: dep.version,
importance: dep.importance,
platforms: dep.platforms
});
}
Ok(res)
}
Err(_) => Err(D::Error::custom(e))
}
}
}
}

#[derive(Default, Deserialize, PartialEq)]
pub struct ModApi {
#[serde(deserialize_with = "parse_glob_rel")]
Expand Down Expand Up @@ -347,8 +433,8 @@ pub struct ModFileInfo {
pub description: String,
#[serde(default)]
pub resources: ModResources,
#[serde(default)]
pub dependencies: Vec<Dependency>,
#[serde(default, deserialize_with = "parse_dependencies")]
pub dependencies: Dependencies,
pub api: Option<ModApi>,
}

Expand Down

0 comments on commit e6f4899

Please sign in to comment.