mirror of
				https://github.com/WarrenHood/MCModpackManager.git
				synced 2025-11-04 01:38:41 +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 {
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            println!(
 | 
			
		||||
                "Adding {}@{} to modpack '{}'...",
 | 
			
		||||
                mod_meta.name, mod_meta.version, self.pack_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);
 | 
			
		||||
        // }
 | 
			
		||||
        // else {
 | 
			
		||||
        //     println!(
 | 
			
		||||
        //         "Adding {}@{} to modpack '{}'...",
 | 
			
		||||
        //         mod_meta.name, mod_meta.version, self.pack_name
 | 
			
		||||
        //     );
 | 
			
		||||
        // }
 | 
			
		||||
        self.mods.insert(mod_meta.name.to_string(), mod_meta.clone());
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ impl ModpackMeta {
 | 
			
		|||
            path,
 | 
			
		||||
            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(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
use std::path::PathBuf;
 | 
			
		||||
use std::{collections::HashSet, path::PathBuf};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::mod_meta::ModMeta;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,5 +18,5 @@ pub struct PinnedMod {
 | 
			
		|||
    /// Version of mod
 | 
			
		||||
    pub version: semver::Version,
 | 
			
		||||
    /// 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 std::error::Error;
 | 
			
		||||
use std::{collections::HashSet, error::Error};
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
    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)]
 | 
			
		||||
struct VersionDeps {
 | 
			
		||||
    dependency_type: String,
 | 
			
		||||
| 
						 | 
				
			
			@ -40,8 +70,9 @@ struct ModrinthProjectVersion {
 | 
			
		|||
    // downloads: i64,
 | 
			
		||||
    files: Vec<VersionFiles>,
 | 
			
		||||
    // loaders: Vec<String>,
 | 
			
		||||
    // name: String,
 | 
			
		||||
    // project_id: String,
 | 
			
		||||
    name: String,
 | 
			
		||||
    project_id: String,
 | 
			
		||||
    id: String,
 | 
			
		||||
    version_number: semver::Version,
 | 
			
		||||
    // 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
 | 
			
		||||
    pub async fn resolve(
 | 
			
		||||
        &self,
 | 
			
		||||
        mod_meta: &ModMeta,
 | 
			
		||||
        pack_meta: &ModpackMeta,
 | 
			
		||||
    ) -> Result<PinnedMod, Box<dyn Error>> {
 | 
			
		||||
        let mut versions = self.get_project_versions(&mod_meta.name, pack_meta).await?;
 | 
			
		||||
        versions.sort_by_key(|v| v.version_number.clone());
 | 
			
		||||
        versions.reverse();
 | 
			
		||||
        let versions = self.get_project_versions(&mod_meta.name, pack_meta).await?;
 | 
			
		||||
 | 
			
		||||
        let package = if mod_meta.version == "*" {
 | 
			
		||||
            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 {
 | 
			
		||||
            source: package
 | 
			
		||||
                .files
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +170,11 @@ impl Modrinth {
 | 
			
		|||
                })
 | 
			
		||||
                .collect(),
 | 
			
		||||
            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,
 | 
			
		||||
        pack_meta: &ModpackMeta,
 | 
			
		||||
    ) -> Result<Vec<ModrinthProjectVersion>, Box<dyn Error>> {
 | 
			
		||||
        let project_Versions: Vec<ModrinthProjectVersion> = self
 | 
			
		||||
        let mut project_versions: Vec<ModrinthProjectVersion> = self
 | 
			
		||||
            .client
 | 
			
		||||
            .get(format!(
 | 
			
		||||
                "https://api.modrinth.com/v2/project/{mod_id}/version"
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +200,10 @@ impl Modrinth {
 | 
			
		|||
            .json()
 | 
			
		||||
            .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 =
 | 
			
		||||
            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() {
 | 
			
		||||
            let mut next_deps = HashSet::new();
 | 
			
		||||
            for dep in deps.iter() {
 | 
			
		||||
                println!(
 | 
			
		||||
                    "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?);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +136,7 @@ impl PinnedPackMeta {
 | 
			
		|||
            path,
 | 
			
		||||
            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(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue