mirror of
				https://github.com/WarrenHood/MCModpackManager.git
				synced 2025-11-04 07:58:40 +00:00 
			
		
		
		
	Automatically pin transitive deps
This commit is contained in:
		
							parent
							
								
									844350ab09
								
							
						
					
					
						commit
						72407055ca
					
				| 
						 | 
					@ -80,15 +80,15 @@ impl ModpackMeta {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_mod(mut self, mod_meta: &ModMeta) -> Self {
 | 
					    pub fn add_mod(mut self, mod_meta: &ModMeta) -> Self {
 | 
				
			||||||
        if let Some(old_mod_meta) = self.mods.get(&mod_meta.name) {
 | 
					        // if let Some(old_mod_meta) = self.mods.get(&mod_meta.name) {
 | 
				
			||||||
            println!("Updating {} version constraints: {} -> {}", mod_meta.name, old_mod_meta.version, mod_meta.version);
 | 
					        //     println!("Updating {} version constraints: {} -> {}", mod_meta.name, old_mod_meta.version, mod_meta.version);
 | 
				
			||||||
        }
 | 
					        // }
 | 
				
			||||||
        else {
 | 
					        // else {
 | 
				
			||||||
            println!(
 | 
					        //     println!(
 | 
				
			||||||
                "Adding {}@{} to modpack '{}'...",
 | 
					        //         "Adding {}@{} to modpack '{}'...",
 | 
				
			||||||
                mod_meta.name, mod_meta.version, self.pack_name
 | 
					        //         mod_meta.name, mod_meta.version, self.pack_name
 | 
				
			||||||
            );
 | 
					        //     );
 | 
				
			||||||
        }
 | 
					        // }
 | 
				
			||||||
        self.mods.insert(mod_meta.name.to_string(), mod_meta.clone());
 | 
					        self.mods.insert(mod_meta.name.to_string(), mod_meta.clone());
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,7 @@ impl ModpackMeta {
 | 
				
			||||||
            path,
 | 
					            path,
 | 
				
			||||||
            toml::to_string(self).expect("MC Modpack Meta should be serializable"),
 | 
					            toml::to_string(self).expect("MC Modpack Meta should be serializable"),
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        println!("Saved modpack metadata to {}", path.display());
 | 
					        // println!("Saved modpack metadata to {}", path.display());
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::{collections::HashSet, path::PathBuf};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use crate::mod_meta::ModMeta;
 | 
					use crate::mod_meta::ModMeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,5 +18,5 @@ pub struct PinnedMod {
 | 
				
			||||||
    /// Version of mod
 | 
					    /// Version of mod
 | 
				
			||||||
    pub version: semver::Version,
 | 
					    pub version: semver::Version,
 | 
				
			||||||
    /// Pinned dependencies of a pinned mod
 | 
					    /// Pinned dependencies of a pinned mod
 | 
				
			||||||
    pub deps: Option<Vec<ModMeta>>
 | 
					    pub deps: Option<HashSet<ModMeta>>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,43 @@
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use std::error::Error;
 | 
					use std::{collections::HashSet, error::Error};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::PinnedMod;
 | 
					use super::PinnedMod;
 | 
				
			||||||
use crate::{mod_meta::ModMeta, modpack::ModpackMeta, providers::FileSource};
 | 
					use crate::{
 | 
				
			||||||
 | 
					    mod_meta::{ModMeta, ModProvider},
 | 
				
			||||||
 | 
					    modpack::ModpackMeta,
 | 
				
			||||||
 | 
					    providers::FileSource,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Modrinth {
 | 
					pub struct Modrinth {
 | 
				
			||||||
    client: reqwest::Client,
 | 
					    client: reqwest::Client,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					struct DonationUrls1 {
 | 
				
			||||||
 | 
					    id: String,
 | 
				
			||||||
 | 
					    platform: String,
 | 
				
			||||||
 | 
					    url: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					struct Gallery1 {
 | 
				
			||||||
 | 
					    created: String,
 | 
				
			||||||
 | 
					    description: String,
 | 
				
			||||||
 | 
					    featured: bool,
 | 
				
			||||||
 | 
					    ordering: i64,
 | 
				
			||||||
 | 
					    title: String,
 | 
				
			||||||
 | 
					    url: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					struct License1 {
 | 
				
			||||||
 | 
					    id: String,
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    url: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					struct ModrinthProject {
 | 
				
			||||||
 | 
					    slug: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
struct VersionDeps {
 | 
					struct VersionDeps {
 | 
				
			||||||
    dependency_type: String,
 | 
					    dependency_type: String,
 | 
				
			||||||
| 
						 | 
					@ -40,8 +70,9 @@ struct ModrinthProjectVersion {
 | 
				
			||||||
    // downloads: i64,
 | 
					    // downloads: i64,
 | 
				
			||||||
    files: Vec<VersionFiles>,
 | 
					    files: Vec<VersionFiles>,
 | 
				
			||||||
    // loaders: Vec<String>,
 | 
					    // loaders: Vec<String>,
 | 
				
			||||||
    // name: String,
 | 
					    name: String,
 | 
				
			||||||
    // project_id: String,
 | 
					    project_id: String,
 | 
				
			||||||
 | 
					    id: String,
 | 
				
			||||||
    version_number: semver::Version,
 | 
					    version_number: semver::Version,
 | 
				
			||||||
    // version_type: String,
 | 
					    // version_type: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -53,15 +84,49 @@ impl Modrinth {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn get_project_slug(&self, project_id: &str) -> Result<String, Box<dyn Error>> {
 | 
				
			||||||
 | 
					        let mut project: ModrinthProject = self
 | 
				
			||||||
 | 
					            .client
 | 
				
			||||||
 | 
					            .get(format!("https://api.modrinth.com/v2/project/{project_id}"))
 | 
				
			||||||
 | 
					            .send()
 | 
				
			||||||
 | 
					            .await?
 | 
				
			||||||
 | 
					            .json()
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(project.slug)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn get_mod_meta(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        project_id: &str,
 | 
				
			||||||
 | 
					        project_version: Option<&str>,
 | 
				
			||||||
 | 
					        pack_meta: &ModpackMeta,
 | 
				
			||||||
 | 
					    ) -> Result<ModMeta, Box<dyn Error>> {
 | 
				
			||||||
 | 
					        let project_versions = self.get_project_versions(project_id, pack_meta).await?;
 | 
				
			||||||
 | 
					        let project_slug = self.get_project_slug(project_id).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for version in project_versions.into_iter() {
 | 
				
			||||||
 | 
					            if project_version.is_none() || project_version.unwrap_or("*") == version.id {
 | 
				
			||||||
 | 
					                return Ok(ModMeta::new(&project_slug)?
 | 
				
			||||||
 | 
					                    .provider(ModProvider::Modrinth)
 | 
				
			||||||
 | 
					                    .version(&version.version_number.to_string()));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Err(format!(
 | 
				
			||||||
 | 
					            "Couldn't find project '{}' with version '{}'",
 | 
				
			||||||
 | 
					            project_id,
 | 
				
			||||||
 | 
					            project_version.unwrap_or("*")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .into())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Resolve a list of mod candidates in order of newest to oldest
 | 
					    /// Resolve a list of mod candidates in order of newest to oldest
 | 
				
			||||||
    pub async fn resolve(
 | 
					    pub async fn resolve(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        mod_meta: &ModMeta,
 | 
					        mod_meta: &ModMeta,
 | 
				
			||||||
        pack_meta: &ModpackMeta,
 | 
					        pack_meta: &ModpackMeta,
 | 
				
			||||||
    ) -> Result<PinnedMod, Box<dyn Error>> {
 | 
					    ) -> Result<PinnedMod, Box<dyn Error>> {
 | 
				
			||||||
        let mut versions = self.get_project_versions(&mod_meta.name, pack_meta).await?;
 | 
					        let versions = self.get_project_versions(&mod_meta.name, pack_meta).await?;
 | 
				
			||||||
        versions.sort_by_key(|v| v.version_number.clone());
 | 
					 | 
				
			||||||
        versions.reverse();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let package = if mod_meta.version == "*" {
 | 
					        let package = if mod_meta.version == "*" {
 | 
				
			||||||
            versions.last().ok_or(format!(
 | 
					            versions.last().ok_or(format!(
 | 
				
			||||||
| 
						 | 
					@ -82,6 +147,18 @@ impl Modrinth {
 | 
				
			||||||
                ))?
 | 
					                ))?
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut deps_meta = HashSet::new();
 | 
				
			||||||
 | 
					        for dep in package
 | 
				
			||||||
 | 
					            .dependencies
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .filter(|dep| dep.dependency_type == "required")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            deps_meta.insert(
 | 
				
			||||||
 | 
					                self.get_mod_meta(&dep.project_id, dep.version_id.as_deref(), pack_meta)
 | 
				
			||||||
 | 
					                    .await?,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(PinnedMod {
 | 
					        Ok(PinnedMod {
 | 
				
			||||||
            source: package
 | 
					            source: package
 | 
				
			||||||
                .files
 | 
					                .files
 | 
				
			||||||
| 
						 | 
					@ -93,7 +170,11 @@ impl Modrinth {
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .collect(),
 | 
					                .collect(),
 | 
				
			||||||
            version: package.version_number.clone(),
 | 
					            version: package.version_number.clone(),
 | 
				
			||||||
            deps: None, // TODO: Get deps
 | 
					            deps: if package.dependencies.len() > 0 {
 | 
				
			||||||
 | 
					                Some(deps_meta)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,7 +183,7 @@ impl Modrinth {
 | 
				
			||||||
        mod_id: &str,
 | 
					        mod_id: &str,
 | 
				
			||||||
        pack_meta: &ModpackMeta,
 | 
					        pack_meta: &ModpackMeta,
 | 
				
			||||||
    ) -> Result<Vec<ModrinthProjectVersion>, Box<dyn Error>> {
 | 
					    ) -> Result<Vec<ModrinthProjectVersion>, Box<dyn Error>> {
 | 
				
			||||||
        let project_Versions: Vec<ModrinthProjectVersion> = self
 | 
					        let mut project_versions: Vec<ModrinthProjectVersion> = self
 | 
				
			||||||
            .client
 | 
					            .client
 | 
				
			||||||
            .get(format!(
 | 
					            .get(format!(
 | 
				
			||||||
                "https://api.modrinth.com/v2/project/{mod_id}/version"
 | 
					                "https://api.modrinth.com/v2/project/{mod_id}/version"
 | 
				
			||||||
| 
						 | 
					@ -119,7 +200,10 @@ impl Modrinth {
 | 
				
			||||||
            .json()
 | 
					            .json()
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(project_Versions)
 | 
					        project_versions.sort_by_key(|v| v.version_number.clone());
 | 
				
			||||||
 | 
					        project_versions.reverse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(project_versions)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,12 +45,19 @@ impl PinnedPackMeta {
 | 
				
			||||||
        let mut deps =
 | 
					        let mut deps =
 | 
				
			||||||
            HashSet::from_iter(self.pin_mod(mod_metadata, pack_metadata).await?.into_iter());
 | 
					            HashSet::from_iter(self.pin_mod(mod_metadata, pack_metadata).await?.into_iter());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pinned_version = self
 | 
				
			||||||
 | 
					            .mods
 | 
				
			||||||
 | 
					            .get(&mod_metadata.name)
 | 
				
			||||||
 | 
					            .expect("should be in pinned mods")
 | 
				
			||||||
 | 
					            .version
 | 
				
			||||||
 | 
					            .clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while !deps.is_empty() {
 | 
					        while !deps.is_empty() {
 | 
				
			||||||
            let mut next_deps = HashSet::new();
 | 
					            let mut next_deps = HashSet::new();
 | 
				
			||||||
            for dep in deps.iter() {
 | 
					            for dep in deps.iter() {
 | 
				
			||||||
                println!(
 | 
					                println!(
 | 
				
			||||||
                    "Adding mod {}@{} (dependency of {}@{})",
 | 
					                    "Adding mod {}@{} (dependency of {}@{})",
 | 
				
			||||||
                    dep.name, dep.version, mod_metadata.name, mod_metadata.version
 | 
					                    dep.name, dep.version, mod_metadata.name, pinned_version
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                next_deps.extend(self.pin_mod(dep, &pack_metadata).await?);
 | 
					                next_deps.extend(self.pin_mod(dep, &pack_metadata).await?);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -129,7 +136,7 @@ impl PinnedPackMeta {
 | 
				
			||||||
            path,
 | 
					            path,
 | 
				
			||||||
            toml::to_string(self).expect("Pinned pack meta should be serializable"),
 | 
					            toml::to_string(self).expect("Pinned pack meta should be serializable"),
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        println!("Saved modpack.lock to {}", path.display());
 | 
					        // println!("Saved modpack.lock to {}", path.display());
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue