mirror of
				https://github.com/WarrenHood/MCModpackManager.git
				synced 2025-11-04 01:58:41 +00:00 
			
		
		
		
	Add support for ignoring transitive dep versions
This commit is contained in:
		
							parent
							
								
									6a18ac39bb
								
							
						
					
					
						commit
						86fa34d9a2
					
				
							
								
								
									
										14
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -59,6 +59,9 @@ enum Commands {
 | 
			
		|||
        /// URL to download the mod from
 | 
			
		||||
        #[arg(long)]
 | 
			
		||||
        url: Option<String>,
 | 
			
		||||
        /// Whether to ignore exact transitive mod versions
 | 
			
		||||
        #[arg(long, short, action)]
 | 
			
		||||
        ignore_transitive_versions: bool,
 | 
			
		||||
    },
 | 
			
		||||
    /// Remove a mod from the modpack
 | 
			
		||||
    Remove {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +106,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		|||
                    mc_modpack_meta = mc_modpack_meta.provider(provider);
 | 
			
		||||
                }
 | 
			
		||||
                mc_modpack_meta.init_project(&dir)?;
 | 
			
		||||
                let modpack_lock = resolver::PinnedPackMeta::load_from_directory(&dir).await?;
 | 
			
		||||
                let modpack_lock = resolver::PinnedPackMeta::load_from_directory(&dir, false).await?;
 | 
			
		||||
                modpack_lock.save_to_dir(&dir)?;
 | 
			
		||||
            }
 | 
			
		||||
            Commands::New {
 | 
			
		||||
| 
						 | 
				
			
			@ -126,13 +129,14 @@ async fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		|||
                }
 | 
			
		||||
                mc_modpack_meta.init_project(&dir)?;
 | 
			
		||||
 | 
			
		||||
                let modpack_lock = resolver::PinnedPackMeta::load_from_directory(&dir).await?;
 | 
			
		||||
                let modpack_lock = resolver::PinnedPackMeta::load_from_directory(&dir, false).await?;
 | 
			
		||||
                modpack_lock.save_to_dir(&dir)?;
 | 
			
		||||
            }
 | 
			
		||||
            Commands::Add {
 | 
			
		||||
                name,
 | 
			
		||||
                providers,
 | 
			
		||||
                url,
 | 
			
		||||
                ignore_transitive_versions,
 | 
			
		||||
            } => {
 | 
			
		||||
                let mut modpack_meta = ModpackMeta::load_from_current_directory()?;
 | 
			
		||||
                let old_modpack_meta = modpack_meta.clone();
 | 
			
		||||
| 
						 | 
				
			
			@ -155,10 +159,10 @@ async fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		|||
                    panic!("Reverted modpack meta:\n{}", e);
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                match resolver::PinnedPackMeta::load_from_current_directory().await {
 | 
			
		||||
                match resolver::PinnedPackMeta::load_from_current_directory(ignore_transitive_versions).await {
 | 
			
		||||
                    Ok(mut modpack_lock) => {
 | 
			
		||||
                        let pin_result = modpack_lock
 | 
			
		||||
                            .pin_mod_and_deps(&mod_meta, &modpack_meta)
 | 
			
		||||
                            .pin_mod_and_deps(&mod_meta, &modpack_meta, ignore_transitive_versions)
 | 
			
		||||
                            .await;
 | 
			
		||||
                        if let Err(e) = pin_result {
 | 
			
		||||
                            revert_modpack_meta(e);
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +192,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		|||
                    panic!("Reverted modpack meta:\n{}", e);
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                match resolver::PinnedPackMeta::load_from_current_directory().await {
 | 
			
		||||
                match resolver::PinnedPackMeta::load_from_current_directory(false).await {
 | 
			
		||||
                    Ok(mut modpack_lock) => {
 | 
			
		||||
                        let remove_result = modpack_lock.remove_mod(&name, &modpack_meta);
 | 
			
		||||
                        if let Err(e) = remove_result {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ pub struct PinnedMod {
 | 
			
		|||
    /// Source of the files for the mod
 | 
			
		||||
    source: Vec<FileSource>,
 | 
			
		||||
    /// Version of mod
 | 
			
		||||
    pub version: semver::Version,
 | 
			
		||||
    pub version: String,
 | 
			
		||||
    /// Pinned dependencies of a pinned mod
 | 
			
		||||
    pub deps: Option<HashSet<ModMeta>>
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -64,16 +64,16 @@ struct VersionFiles {
 | 
			
		|||
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug)]
 | 
			
		||||
struct ModrinthProjectVersion {
 | 
			
		||||
    author_id: String,
 | 
			
		||||
    date_published: String,
 | 
			
		||||
    dependencies: Vec<VersionDeps>,
 | 
			
		||||
    // author_id: String,
 | 
			
		||||
    // date_published: String,
 | 
			
		||||
    dependencies: Option<Vec<VersionDeps>>,
 | 
			
		||||
    // 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_number: String,
 | 
			
		||||
    // version_type: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,10 +102,12 @@ impl Modrinth {
 | 
			
		|||
        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_versions = self
 | 
			
		||||
            .get_project_versions(project_id, pack_meta, true)
 | 
			
		||||
            .await?;
 | 
			
		||||
        let project_slug = self.get_project_slug(project_id).await?;
 | 
			
		||||
 | 
			
		||||
        for version in project_versions.into_iter() {
 | 
			
		||||
        for version in project_versions.iter() {
 | 
			
		||||
            if project_version.is_none() || project_version.unwrap_or("*") == version.id {
 | 
			
		||||
                return Ok(ModMeta::new(&project_slug)?
 | 
			
		||||
                    .provider(ModProvider::Modrinth)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,20 +128,21 @@ impl Modrinth {
 | 
			
		|||
        mod_meta: &ModMeta,
 | 
			
		||||
        pack_meta: &ModpackMeta,
 | 
			
		||||
    ) -> Result<PinnedMod, Box<dyn Error>> {
 | 
			
		||||
        let versions = self.get_project_versions(&mod_meta.name, pack_meta).await?;
 | 
			
		||||
        let versions = self
 | 
			
		||||
            .get_project_versions(&mod_meta.name, pack_meta, false)
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        let package = if mod_meta.version == "*" {
 | 
			
		||||
            versions.last().ok_or(format!(
 | 
			
		||||
            versions.first().ok_or(format!(
 | 
			
		||||
                "Cannot find package {} for loader={} and mc version={}",
 | 
			
		||||
                mod_meta.name,
 | 
			
		||||
                pack_meta.modloader.to_string().to_lowercase(),
 | 
			
		||||
                pack_meta.mc_version
 | 
			
		||||
            ))?
 | 
			
		||||
        } else {
 | 
			
		||||
            let expected_version = semver::Version::parse(&mod_meta.version)?;
 | 
			
		||||
            versions
 | 
			
		||||
                .iter()
 | 
			
		||||
                .filter(|v| v.version_number == expected_version)
 | 
			
		||||
                .filter(|v| v.version_number == mod_meta.version)
 | 
			
		||||
                .nth(0)
 | 
			
		||||
                .ok_or(format!(
 | 
			
		||||
                    "Cannot find package {}@{}",
 | 
			
		||||
| 
						 | 
				
			
			@ -148,15 +151,13 @@ 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?,
 | 
			
		||||
            );
 | 
			
		||||
        if let Some(deps) = &package.dependencies {
 | 
			
		||||
            for dep in deps.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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +171,11 @@ impl Modrinth {
 | 
			
		|||
                })
 | 
			
		||||
                .collect(),
 | 
			
		||||
            version: package.version_number.clone(),
 | 
			
		||||
            deps: if package.dependencies.len() > 0 {
 | 
			
		||||
            deps: if package
 | 
			
		||||
                .dependencies
 | 
			
		||||
                .as_ref()
 | 
			
		||||
                .is_some_and(|deps| deps.len() > 0)
 | 
			
		||||
            {
 | 
			
		||||
                Some(deps_meta)
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
| 
						 | 
				
			
			@ -182,19 +187,26 @@ impl Modrinth {
 | 
			
		|||
        &self,
 | 
			
		||||
        mod_id: &str,
 | 
			
		||||
        pack_meta: &ModpackMeta,
 | 
			
		||||
        ignore_game_version_and_loader: bool, // For deps we might as well let them use anything
 | 
			
		||||
    ) -> Result<Vec<ModrinthProjectVersion>, Box<dyn Error>> {
 | 
			
		||||
        let mut project_versions: Vec<ModrinthProjectVersion> = self
 | 
			
		||||
            .client
 | 
			
		||||
            .get(format!(
 | 
			
		||||
                "https://api.modrinth.com/v2/project/{mod_id}/version"
 | 
			
		||||
            ))
 | 
			
		||||
            .query(&[
 | 
			
		||||
        let query_vec = if ignore_game_version_and_loader {
 | 
			
		||||
            &vec![]
 | 
			
		||||
        } else {
 | 
			
		||||
            &vec![
 | 
			
		||||
                (
 | 
			
		||||
                    "loaders",
 | 
			
		||||
                    format!("[\"{}\"]", pack_meta.modloader.to_string().to_lowercase()),
 | 
			
		||||
                ),
 | 
			
		||||
                ("game_versions", format!("[\"{}\"]", pack_meta.mc_version)),
 | 
			
		||||
            ])
 | 
			
		||||
            ]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut project_versions: Vec<ModrinthProjectVersion> = self
 | 
			
		||||
            .client
 | 
			
		||||
            .get(format!(
 | 
			
		||||
                "https://api.modrinth.com/v2/project/{mod_id}/version"
 | 
			
		||||
            ))
 | 
			
		||||
            .query(query_vec)
 | 
			
		||||
            .send()
 | 
			
		||||
            .await?
 | 
			
		||||
            .json()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,11 +32,10 @@ impl PinnedPackMeta {
 | 
			
		|||
        &mut self,
 | 
			
		||||
        mod_metadata: &ModMeta,
 | 
			
		||||
        pack_metadata: &ModpackMeta,
 | 
			
		||||
        ignore_transitive_versions: bool,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
        if let Some(mod_meta) = self.mods.get(&mod_metadata.name) {
 | 
			
		||||
            if mod_metadata.version != "*"
 | 
			
		||||
                && semver::Version::parse(&mod_metadata.version)? == mod_meta.version
 | 
			
		||||
            {
 | 
			
		||||
            if mod_metadata.version != "*" && mod_metadata.version == mod_meta.version {
 | 
			
		||||
                // Skip already pinned mods
 | 
			
		||||
                // TODO: Replace * with the current mod version in the modpack meta so this doesn't get called twice for the first mod created
 | 
			
		||||
                return Ok(());
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +44,11 @@ impl PinnedPackMeta {
 | 
			
		|||
        let mut deps =
 | 
			
		||||
            HashSet::from_iter(self.pin_mod(mod_metadata, pack_metadata).await?.into_iter());
 | 
			
		||||
 | 
			
		||||
        if ignore_transitive_versions {
 | 
			
		||||
            // Ignore transitive dep versions
 | 
			
		||||
            deps = deps.iter().map(|d| d.clone().version("*")).collect();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let pinned_version = self
 | 
			
		||||
            .mods
 | 
			
		||||
            .get(&mod_metadata.name)
 | 
			
		||||
| 
						 | 
				
			
			@ -183,9 +187,14 @@ impl PinnedPackMeta {
 | 
			
		|||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn init(&mut self, modpack_meta: &ModpackMeta) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    pub async fn init(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        modpack_meta: &ModpackMeta,
 | 
			
		||||
        ignore_transitive_versions: bool,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
        for mod_meta in modpack_meta.iter_mods() {
 | 
			
		||||
            self.pin_mod_and_deps(mod_meta, modpack_meta).await?;
 | 
			
		||||
            self.pin_mod_and_deps(mod_meta, modpack_meta, ignore_transitive_versions)
 | 
			
		||||
                .await?;
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -210,12 +219,18 @@ impl PinnedPackMeta {
 | 
			
		|||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn load_from_directory(directory: &PathBuf) -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
    pub async fn load_from_directory(
 | 
			
		||||
        directory: &PathBuf,
 | 
			
		||||
        ignore_transitive_versions: bool,
 | 
			
		||||
    ) -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
        let modpack_lock_file_path = directory.clone().join(PathBuf::from(MODPACK_LOCK_FILENAME));
 | 
			
		||||
        if !modpack_lock_file_path.exists() {
 | 
			
		||||
            let mut new_modpack_lock = Self::new();
 | 
			
		||||
            new_modpack_lock
 | 
			
		||||
                .init(&ModpackMeta::load_from_directory(directory)?)
 | 
			
		||||
                .init(
 | 
			
		||||
                    &ModpackMeta::load_from_directory(directory)?,
 | 
			
		||||
                    ignore_transitive_versions,
 | 
			
		||||
                )
 | 
			
		||||
                .await?;
 | 
			
		||||
            return Ok(new_modpack_lock);
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +238,9 @@ impl PinnedPackMeta {
 | 
			
		|||
        Ok(toml::from_str(&modpack_lock_contents)?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn load_from_current_directory() -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
        Self::load_from_directory(&std::env::current_dir()?).await
 | 
			
		||||
    pub async fn load_from_current_directory(
 | 
			
		||||
        ignore_transitive_versions: bool,
 | 
			
		||||
    ) -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
        Self::load_from_directory(&std::env::current_dir()?, ignore_transitive_versions).await
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue