Consilidate template libraries #186
5 changed files with 59 additions and 36 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -937,6 +937,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"glob",
|
"glob",
|
||||||
"luajit2-sys",
|
"luajit2-sys",
|
||||||
|
"minijinja",
|
||||||
"nanorand",
|
"nanorand",
|
||||||
"notify",
|
"notify",
|
||||||
"oodle",
|
"oodle",
|
||||||
|
@ -948,7 +949,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_sjson",
|
"serde_sjson",
|
||||||
"shlex",
|
"shlex",
|
||||||
"string_template",
|
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
@ -3307,15 +3307,6 @@ dependencies = [
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "string_template"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc6f2c6b2c3fa950895c9aeb0c3cb9271d7eb580662af9af2b711b593f446320"
|
|
||||||
dependencies = [
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strip-ansi-escapes"
|
name = "strip-ansi-escapes"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
|
@ -14,6 +14,7 @@ exclude = ["lib/color-eyre"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
zip = { version = "2.1.3", default-features = false, features = ["deflate", "bzip2", "zstd", "time"] }
|
zip = { version = "2.1.3", default-features = false, features = ["deflate", "bzip2", "zstd", "time"] }
|
||||||
|
minijinja = { version = "2.0.1", default-features = false }
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
color-eyre = { path = "lib/color-eyre" }
|
color-eyre = { path = "lib/color-eyre" }
|
||||||
|
|
|
@ -27,7 +27,7 @@ futures = "0.3.25"
|
||||||
interprocess = "2.1.0"
|
interprocess = "2.1.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
luajit2-sys = { path = "../../lib/luajit2-sys", version = "*" }
|
luajit2-sys = { path = "../../lib/luajit2-sys", version = "*" }
|
||||||
minijinja = { version = "2.0.1", default-features = false }
|
minijinja = { workspace = true }
|
||||||
nexusmods = { path = "../../lib/nexusmods", version = "*" }
|
nexusmods = { path = "../../lib/nexusmods", version = "*" }
|
||||||
oodle = { path = "../../lib/oodle", version = "*" }
|
oodle = { path = "../../lib/oodle", version = "*" }
|
||||||
open = "5.0.1"
|
open = "5.0.1"
|
||||||
|
|
|
@ -20,7 +20,7 @@ promptly = "0.3.1"
|
||||||
sdk = { path = "../../lib/sdk", version = "*" }
|
sdk = { path = "../../lib/sdk", version = "*" }
|
||||||
serde_sjson = { path = "../../lib/serde_sjson", version = "*" }
|
serde_sjson = { path = "../../lib/serde_sjson", version = "*" }
|
||||||
serde = { version = "1.0.147", features = ["derive"] }
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
string_template = "0.2.1"
|
minijinja = { workspace = true }
|
||||||
tokio-stream = { version = "0.1.11", features = ["fs", "io-util"] }
|
tokio-stream = { version = "0.1.11", features = ["fs", "io-util"] }
|
||||||
tokio = { version = "1.21.2", features = ["rt-multi-thread", "fs", "process", "macros", "tracing", "io-util", "io-std"] }
|
tokio = { version = "1.21.2", features = ["rt-multi-thread", "fs", "process", "macros", "tracing", "io-util", "io-std"] }
|
||||||
tracing-error = "0.2.0"
|
tracing-error = "0.2.0"
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{Arg, ArgMatches, Command};
|
use clap::{Arg, ArgMatches, Command};
|
||||||
use color_eyre::eyre::{self, Context, Result};
|
use color_eyre::eyre::{self, Context, Result};
|
||||||
use color_eyre::Help;
|
use color_eyre::Help;
|
||||||
use futures::{StreamExt, TryStreamExt};
|
use futures::{StreamExt, TryStreamExt};
|
||||||
use string_template::Template;
|
use minijinja::Environment;
|
||||||
use tokio::fs::{self, DirBuilder};
|
use tokio::fs::{self, DirBuilder};
|
||||||
|
|
||||||
const TEMPLATES: [(&str, &str); 5] = [
|
const TEMPLATES: [(&str, &str); 5] = [
|
||||||
(
|
(
|
||||||
"dtmt.cfg",
|
"dtmt.cfg",
|
||||||
r#"id = "{{id}}"
|
r#"//
|
||||||
|
// This is your mod's main configuration file. It tells DTMT how to build the mod,
|
||||||
|
// and DTMM what to display to your users.
|
||||||
|
// Certain files have been pre-filled by the template, the ones commented out (`//`)
|
||||||
|
// are optional.
|
||||||
|
//
|
||||||
|
// A unique identifier (preferably lower case, alphanumeric)
|
||||||
|
id = "{{id}}"
|
||||||
|
// The display name that your users will see.
|
||||||
|
// This doesn't have to be unique, but you still want to avoid being confused with other
|
||||||
|
// mods.
|
||||||
name = "{{name}}"
|
name = "{{name}}"
|
||||||
|
// It's good practice to increase this number whenever you publish changes.
|
||||||
|
// It's up to you if you use SemVer or something simpler like `1970-12-24`. It should sort and
|
||||||
|
// compare well, though.
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
// author = ""
|
// author = ""
|
||||||
|
|
||||||
|
@ -32,16 +44,25 @@ categories = [
|
||||||
|
|
||||||
// A list of mod IDs that this mod depends on. You can find
|
// A list of mod IDs that this mod depends on. You can find
|
||||||
// those IDs by downloading the mod and extracting their `dtmt.cfg`.
|
// those IDs by downloading the mod and extracting their `dtmt.cfg`.
|
||||||
|
// To make your fellow modders' lives easier, publish your own mods' IDs
|
||||||
|
// somewhere visible, such as the Nexusmods page.
|
||||||
depends = [
|
depends = [
|
||||||
DMF
|
DMF
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// The primary resources that serve as the entry point to your
|
||||||
|
// mod's code. Unless for very specific use cases, the generated
|
||||||
|
// values shouldn't be changed.
|
||||||
resources = {
|
resources = {
|
||||||
init = "scripts/mods/{{id}}/init"
|
init = "scripts/mods/{{id}}/init"
|
||||||
data = "scripts/mods/{{id}}/data"
|
data = "scripts/mods/{{id}}/data"
|
||||||
localization = "scripts/mods/{{id}}/localization"
|
localization = "scripts/mods/{{id}}/localization"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The list of packages, or bundles, to build.
|
||||||
|
// Each one corresponds to a package definition in the named folder.
|
||||||
|
// For mods that contain only code and/or a few small assets, a single
|
||||||
|
// package will suffice.
|
||||||
packages = [
|
packages = [
|
||||||
"packages/mods/{{id}}"
|
"packages/mods/{{id}}"
|
||||||
]
|
]
|
||||||
|
@ -59,7 +80,6 @@ packages = [
|
||||||
r#"local mod = get_mod("{{id}}")
|
r#"local mod = get_mod("{{id}}")
|
||||||
|
|
||||||
-- Your mod code goes here.
|
-- Your mod code goes here.
|
||||||
-- https://vmf-docs.verminti.de
|
|
||||||
"#,
|
"#,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -137,34 +157,45 @@ pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()>
|
||||||
|
|
||||||
tracing::debug!(root = %root.display(), name, id);
|
tracing::debug!(root = %root.display(), name, id);
|
||||||
|
|
||||||
let mut data = HashMap::new();
|
let render_ctx = minijinja::context!(name => name.as_str(), id => id.as_str());
|
||||||
data.insert("name", name.as_str());
|
let env = Environment::new();
|
||||||
data.insert("id", id.as_str());
|
|
||||||
|
|
||||||
let templates = TEMPLATES
|
let templates = TEMPLATES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(path_tmpl, content_tmpl)| {
|
.map(|(path_tmpl, content_tmpl)| {
|
||||||
let path = Template::new(path_tmpl).render(&data);
|
env.render_str(path_tmpl, &render_ctx)
|
||||||
let content = Template::new(content_tmpl).render(&data);
|
.wrap_err_with(|| format!("Failed to render template: {}", path_tmpl))
|
||||||
|
.and_then(|path| {
|
||||||
(root.join(path), content)
|
env.render_named_str(&path, content_tmpl, &render_ctx)
|
||||||
|
.wrap_err_with(|| format!("Failed to render template '{}'", &path))
|
||||||
|
.map(|content| (root.join(path), content))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.map(|(path, content)| async move {
|
.map(|res| async move {
|
||||||
let dir = path
|
match res {
|
||||||
.parent()
|
Ok((path, content)) => {
|
||||||
.ok_or_else(|| eyre::eyre!("invalid root path"))?;
|
let dir = path
|
||||||
|
.parent()
|
||||||
|
.ok_or_else(|| eyre::eyre!("invalid root path"))?;
|
||||||
|
|
||||||
DirBuilder::new()
|
DirBuilder::new()
|
||||||
.recursive(true)
|
.recursive(true)
|
||||||
.create(&dir)
|
.create(&dir)
|
||||||
.await
|
.await
|
||||||
.wrap_err_with(|| format!("Failed to create directory {}", dir.display()))?;
|
.wrap_err_with(|| {
|
||||||
|
format!("Failed to create directory {}", dir.display())
|
||||||
|
})?;
|
||||||
|
|
||||||
tracing::trace!("Writing file {}", path.display());
|
tracing::trace!("Writing file {}", path.display());
|
||||||
|
|
||||||
fs::write(&path, content.as_bytes())
|
fs::write(&path, content.as_bytes())
|
||||||
.await
|
.await
|
||||||
.wrap_err_with(|| format!("Failed to write content to path {}", path.display()))
|
.wrap_err_with(|| {
|
||||||
|
format!("Failed to write content to path {}", path.display())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
futures::stream::iter(templates)
|
futures::stream::iter(templates)
|
||||||
|
|
Loading…
Add table
Reference in a new issue