diff --git a/src/main.rs b/src/main.rs index e63b73c..ce63233 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,6 +49,7 @@ enum Commands{ Upload, Compile, Decompile, + DecompileHistoryIntoGit, } #[derive(Args)] @@ -112,6 +113,14 @@ async fn main()->AResult<()>{ write_models:!cli.no_models.unwrap_or(false), write_scripts:!cli.no_scripts.unwrap_or(false), }), + Commands::DecompileHistoryIntoGit=>decompile_history_into_git(DecompileHistoryConfig{ + cookie:cookie.unwrap(), + asset_id:cli.asset_id.unwrap(), + output_folder:cli.output.unwrap(), + write_template:!cli.no_template.unwrap_or(false), + write_models:!cli.no_models.unwrap_or(false), + write_scripts:!cli.no_scripts.unwrap_or(false), + }).await, } } @@ -659,6 +668,122 @@ fn decompile(config:DecompileConfig)->AResult<()>{ Ok(()) } +struct WriteCommitConfig{ + output_folder:std::path::PathBuf, + write_template:bool, + write_models:bool, + write_scripts:bool, +} + +fn write_commit(config:WriteCommitConfig,b:AResult<(AssetVersion,DecompiledContext)>,repo:&git2::Repository)->AResult<()>{ + let (asset_version,context)=b?; + + //clean output dir + { + let mut src=config.output_folder.clone(); + src.push("src"); + match std::fs::remove_dir_all(src){ + Ok(())=>(), + Err(e)=>println!("remove_dir_all src failed {}",e), + } + let mut template=config.output_folder.clone(); + template.push("template.rbxlx"); + match std::fs::remove_file(template){ + Ok(())=>(), + Err(e)=>println!("remove_file template.rbxlx failed {}",e), + } + } + + //write files + write_files(WriteConfig{ + output_folder:config.output_folder.clone(), + write_template:config.write_template, + write_models:config.write_models, + write_scripts:config.write_scripts, + },context)?; + + + let date=asset_version.created; + let sig=git2::Signature::new("roblox-git-history","git_history@strafes.net",&git2::Time::new(date.timestamp(),0)).unwrap(); + let tree_id={ + let mut tree_index = repo.index()?; + tree_index.add_all([config.output_folder].iter(),git2::IndexAddOption::DEFAULT,None)?; + tree_index.write_tree()? + }; + let tree=repo.find_tree(tree_id)?; + + match repo.head(){ + Ok(reference)=>repo.commit( + Some("HEAD"),//update_ref + &sig,//author + &sig,//commiter + &format!("v{}", asset_version.assetVersionNumber),//message + &tree,//tree (basically files) + &[&reference.peel_to_commit()?],//parents + )?, + Err(_)=>repo.commit( + Some("HEAD"),//update_ref + &sig,//author + &sig,//commiter + &format!("v{}", asset_version.assetVersionNumber),//message + &tree,//tree (basically files) + &[],//parents + )?, + }; + + //commit + Ok(()) +} + +struct DecompileHistoryConfig{ + cookie:String, + asset_id:AssetID, + output_folder:std::path::PathBuf, + write_template:bool, + write_models:bool, + write_scripts:bool, +} + +async fn decompile_history_into_git(config:DecompileHistoryConfig)->AResult<()>{ + let client=reqwest::Client::new(); + + //poll paged list of all asset versions + let asset_list=get_version_history(&client,&config.cookie.as_str(),config.asset_id).await?; + + let repo=git2::Repository::init(config.output_folder.clone())?; + + //download all versions + let asset_id_string=config.asset_id.to_string(); + futures::stream::iter(asset_list) + .map(|asset_version|{ + let client=&client; + let cookie=config.cookie.as_str(); + let asset_id_str=asset_id_string.as_str(); + async move{ + let resp=download_asset_version(client,cookie,asset_id_str,asset_version.assetVersionNumber.to_string().as_str()).await?; + let contents=match maybe_gzip_decode(std::io::Cursor::new(resp.bytes().await?))?{ + ReaderType::GZip(readable)=>generate_decompiled_context(readable)?, + ReaderType::Raw(readable)=>generate_decompiled_context(readable)?, + }; + + Ok((asset_version,contents)) + } + }) + .buffered(CONCURRENT_REQUESTS) + .for_each(|b:AResult<_>|async{ + match write_commit(WriteCommitConfig{ + output_folder:config.output_folder.clone(), + write_template:config.write_template, + write_models:config.write_models, + write_scripts:config.write_scripts, + },b,&repo){ + Ok(())=>(), + Err(e)=>println!("download/unzip/decompile/write/commit error: {}",e), + } + }).await; + Ok(()) +} + fn compile(_folder:std::path::PathBuf,_file:std::path::PathBuf)->AResult<()>{ Ok(()) }