legacympt-rs/mpt/src/commands/createmodlist.rs
LordMZTE 1fe7ef0f2d
All checks were successful
continuous-integration/drone/push Build is passing
add debug logging
2021-09-08 17:31:27 +02:00

192 lines
5.4 KiB
Rust

use crate::{config::Config, util, util::CliStyle};
use addonscript::manifest::{
Contributor,
File,
Manifest,
Meta,
Relation,
Repository,
RepositoryType,
};
use anyhow::Context;
use log::{debug, info};
use reqwest::Client;
use serde::Serialize;
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use tera::Tera;
use twitch::api::AddonInfoResponse;
const TEMPLATE: &str = include_str!("../../assets/modlist.html.tera");
pub async fn run(
(_config, mut manifest): (Config, Manifest),
outfile: PathBuf,
) -> anyhow::Result<()> {
let version = manifest
.versions
.pop()
.context("Manifest has no versions!")?;
let repos = util::repo_map(manifest.repositories);
info!("instatiating tera engine");
let mut tera = Tera::default();
tera.add_raw_template("modlist", TEMPLATE)?;
let http = Arc::new(Client::new());
println!("{}", "Resolving metas.".info());
let mut metas = vec![];
let mut cf_rels = vec![];
for rel in version.relations {
let mi = get_meta(rel, &repos)?;
match mi {
MetaInfo::Meta(meta) => metas.push(meta),
MetaInfo::CfId(id) => cf_rels.push(id),
}
}
if !cf_rels.is_empty() {
println!("{}", "Querying CF metas.".info());
info!(
"Requesting addon info for {} curseforge mods",
cf_rels.len()
);
let res = http
.post("https://addons-ecs.forgesvc.net/api/v2/addon")
.body(
serde_json::to_string(&cf_rels)
.context("Failed to serialize curseforge relation IDs")?,
)
.header("Content-Type", "application/json")
.send()
.await
.context("Failed sending CF relation request")?
.bytes()
.await
.context("Failed getting CF relation response body")?;
let cf_metas = serde_json::from_slice::<Vec<AddonInfoResponse>>(&res)
.context("Failed deserializing CF relation response")?;
info!("Converting CF metas to AS metas");
let cf_metas = cf_metas.into_iter().map(|m| Meta {
name: m.name,
contributors: m
.authors
.into_iter()
.map(|a| Contributor {
name: a.name,
roles: vec!["author".into()],
})
.collect(),
description: Some(m.summary),
icon_url: m
.attachments
.into_iter()
.find(|a| a.is_default)
.map(|a| a.url.to_string()),
website_url: Some(m.website_url),
});
metas.extend(cf_metas);
}
metas.sort_by_key(|m| m.name.to_ascii_lowercase());
println!("{}", "Rendering modlist.".info());
let rendered = tera.render(
"modlist",
&tera::Context::from_serialize(&ModListContent {
metas,
pack_meta: manifest.meta,
})?,
)?;
println!("{}", "Writing file.".info());
if let Some(parent) = outfile.parent() {
tokio::fs::create_dir_all(parent).await?;
}
tokio::fs::write(outfile, rendered).await?;
Ok(())
}
fn get_meta(rel: Relation, repos: &HashMap<String, Repository>) -> anyhow::Result<MetaInfo> {
debug!("getting meta for {:?}", &rel);
if let Some(meta) = rel.meta {
return Ok(MetaInfo::Meta(meta));
}
if rel.file.is_none() {
return Ok(MetaInfo::Meta(Meta {
name: rel.id.clone(),
contributors: vec![],
description: rel.versions.map(|v| format!("version {}", v)),
icon_url: None,
website_url: None,
}));
}
let file = rel.file.unwrap();
match file {
File::Link { link, id, .. } => {
Ok(MetaInfo::Meta(Meta {
name: if let Some(id) = id {
id
} else {
util::link_file_name(&link)?
},
contributors: vec![],
// this is fine, since if a link relation is used you should probably add a local
// meta object anyways, in which case this code won't be reached.
description: Some(format!("{:?}", &link)),
icon_url: None,
website_url: None,
}))
},
File::Maven {
repository,
artifact,
..
} => {
let repo = repos
.get(&repository)
.context("File references unknown repository!")?;
match repo.repo_type {
RepositoryType::Maven => Ok(MetaInfo::Meta(Meta {
name: artifact,
contributors: vec![],
description: None,
icon_url: None,
website_url: None,
})),
RepositoryType::Curseforge => {
let (p_id, _) = util::parse_curseforge_artifact(&artifact)?;
let p_id = p_id
.parse::<u32>()
.context("Failed to parse curseforge ID")?;
Ok(MetaInfo::CfId(p_id))
},
}
},
}
}
#[derive(Serialize)]
struct ModListContent {
metas: Vec<Meta>,
pack_meta: Meta,
}
enum MetaInfo {
Meta(Meta),
CfId(u32),
}