summaryrefslogblamecommitdiff
path: root/src/commands/update.rs
blob: 92ea9d67e927b149d95dff2662083cf753cb08d6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                           
 
            



                                                                 
                                                                      

                                                                       


                         
                                                                           

                                                   

  
            
                    
                 




                          

                                  
                                                                         
                       
                                                    

                                            
 
                                   

                                                                    
                                                                      
                                                                         
                                          
 
                                                                   
 

                                                                                
                           
                                                        

                                                
 
                                                                 
                                                   
 
                        









                                      
         
 



                                             
 
                  
                                           

                                           
 
                                                       







                                     

                                  
                       

                                           
                                     
                                                           
                      

                              
                                                                

                                                        

                                             

                                                                             
                                                               
                                               

                                                                              
                                                                              

                      







                                                 

             
                                                                           
                        
     
 

                                                      


          










                                                           
 




                                                                 
 















                                                                     



          





                           
                           
                             
                                                                               
 
                                           
 


                                            


                                                 
     
 

                                                                        
                       
                         
                                 
       
     
                                                                                
 





                                                        

                          



                                                                                                        
 


                                                                        






                                     
                     




                               

      





                              
 
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};

use crate::{
    apis::modrinth::{extract_current_version, versions, Version},
    config::Cfg,
    data::list::List,
    db::{
        mods_get_info, userlist_change_versions, userlist_get_all_ids,
        userlist_get_applicable_versions, userlist_get_current_version,
        userlist_get_set_version,
    },
    errors::{Error, MLE},
    files::{
        clean_list_dir, delete_version, disable_version, download_versions,
    },
    PROGRESS_CHARS, STYLE_BAR_POS, STYLE_OPERATION,
};

/// # Errors
pub async fn update(
    config: &Cfg,
    liststack: Vec<List>,
    clean: bool,
    direct_download: bool,
    delete_old: bool,
) -> MLE<()> {
    let mp = MultiProgress::new();

    let update_p = mp.add(ProgressBar::new(liststack.len().try_into()?));
    update_p.set_style(
        ProgressStyle::with_template(STYLE_BAR_POS)?
            .progress_chars(PROGRESS_CHARS),
    );

    for current_list in liststack {
        update_p.set_message(format!("Update {}", current_list.id));

        let list_p = mp.insert_before(&update_p, ProgressBar::new(2));
        list_p.set_style(ProgressStyle::with_template(STYLE_OPERATION)?);
        list_p.set_message("Update mods");

        let mods = userlist_get_all_ids(config, &current_list.id)?;

        let list_u_p =
            mp.insert_before(&list_p, ProgressBar::new(mods.len().try_into()?));
        list_u_p.set_style(
            ProgressStyle::with_template(STYLE_BAR_POS)?
                .progress_chars(PROGRESS_CHARS),
        );

        let mut current_versions: Vec<(String, String)> = vec![];
        let mut updatestack: Vec<Version> = vec![];

        for id in mods {
            update_mod(
                config,
                id,
                list_u_p.clone(),
                &current_list,
                &mut updatestack,
                &mut current_versions,
                clean,
            )
            .await?;
        }

        list_u_p.finish_with_message(format!(
            "Updated mods in {}",
            current_list.id
        ));

        if clean {
            list_p.set_message("Cleaning");
            clean_list_dir(&current_list)?;
        };

        if direct_download && !updatestack.is_empty() {
            download_versions(
                current_list.clone(),
                config.clone(),
                updatestack,
                &mp,
                &list_p,
            )
            .await?;

            //Disable old versions
            if !clean {
                let d_p = mp.insert_before(
                    &list_p,
                    ProgressBar::new(
                        current_versions.len().try_into()?,
                    ),
                );
                d_p.set_style(
                    ProgressStyle::with_template(STYLE_BAR_POS)?
                        .progress_chars(PROGRESS_CHARS),
                );
                for ver in current_versions {
                    if delete_old {
                        d_p.set_message(format!("Delete version {}", ver.0));
                        d_p.inc(1);
                        delete_version(&current_list, &ver.0)?;
                    } else if ver.0 != "NONE" {
                        d_p.set_message(format!("Disable version {}", ver.0));
                        d_p.inc(1);
                        disable_version(config, &current_list, ver.0, ver.1)?;
                    };
                }

                let del_msg = if delete_old {
                    "Deleted all old versions"
                } else {
                    "Disabled all old versions"
                };

                d_p.finish_with_message(del_msg);
            }
        };
        list_p.finish_with_message(format!("Updated {}", current_list.id));
        update_p.inc(1);
    }

    update_p.finish_with_message("Updated all lists");

    Ok(())
}

async fn update_mod(
    config: &Cfg,
    id: String,
    list_u_p: ProgressBar,
    current_list: &List,
    updatestack: &mut Vec<Version>,
    current_versions: &mut Vec<(String, String)>,
    clean: bool,
) -> MLE<()> {
    let info = mods_get_info(config, &id)?;
    list_u_p.set_message(format!("Update {}", info.title));

    //Skip check if version is set
    if userlist_get_set_version(config, &current_list.id, &id)? {
        list_u_p.inc(1);
        return Ok(());
    }

    //Getting current installed version for disable or delete
    let disable_version =
        userlist_get_current_version(config, &current_list.id, &id)?;

    let version = specific_update(
            config,
            clean,
            current_list.clone(),
            &id,
            &list_u_p,
        ).await?;
    if let Some(v) = version {
        updatestack.push(v);
        current_versions.push((disable_version, id.to_string()));
    }
    list_u_p.inc(1);

    Ok(())
}

async fn specific_update(
    config: &Cfg,
    clean: bool,
    list: List,
    id: &str,
    progress: &ProgressBar,
) -> MLE<Option<Version>> {
    let applicable_versions =
        versions(&config.apis.modrinth, String::from(id), list.clone()).await?;

    let mut versions: Vec<String> = vec![];

    if applicable_versions.is_empty() {
        versions.push(String::from("NONE"));
    } else {
        for ver in &applicable_versions {
            versions.push(String::from(&ver.id));
        }
    }

    let mut current: Option<Version> = None;
    if clean || (versions.join("|") != userlist_get_applicable_versions(
                config,
                &list.id,
                String::from(id),
    )?)
    {
        let current_str = extract_current_version(applicable_versions.clone())?;

        if !clean {
            progress.println(format!(
                "Found new version for {}",
                mods_get_info(config, id).unwrap().title
            ));
        }

        //get new versions
        let Some(current_ver) = applicable_versions.into_iter().find(|ver| ver.id == current_str) else {
            return Err(Error::NoCurrentVersion);
        };
        current = Some(current_ver.clone());

        let files = &current_ver.files;

        let link = match files.clone().into_iter().find(|f| f.primary) {
            Some(f) => f,
            None => files[0].clone(),
        }
        .url;

        userlist_change_versions(
            config,
            &list.id,
            current_str,
            versions.join("|"),
            link,
            id.to_string(),
        )?;
    };

    if current.is_none() {
        // No Update Available
        Ok(None)
    } else {
        Ok(current)
    }
}