diff --git a/Cargo.toml b/Cargo.toml index de8add6..fd76fc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ colored = "2.1.0" serde = { version = "1.0.197", features = ["derive"] } thiserror = "1.0.58" toml = "0.8.12" -shulkerscript-lang = { git = "https://github.com/moritz-hoelting/shulkerscript-lang", features = ["shulkerbox"], default-features = false, rev = "09b389c2060e73f686d92df3c45290c2c1b34ecb"} -shulkerbox = { git = "https://github.com/moritz-hoelting/shulkerbox", default-features = false, rev = "296502dcc5dd29b3d930ffec91ceec3d161e0e47" } +shulkerscript-lang = { git = "https://github.com/moritz-hoelting/shulkerscript-lang", features = ["shulkerbox"], default-features = false, rev = "44d634355b4ab5b652de56b0becd61b05680c068"} +shulkerbox = { git = "https://github.com/moritz-hoelting/shulkerbox", default-features = false, rev = "b79c9ecd6d45f9319c9083a8103ef0186839b0c0" } git2 = { version = "0.18.3", default-features = false } path-absolutize = "3.1.1" color-eyre = "0.6.3" diff --git a/src/config.rs b/src/config.rs index cd5e49f..2e85675 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,15 @@ +use std::path::PathBuf; + use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ProjectConfig { pub pack: PackConfig, + pub compiler: Option, } impl ProjectConfig { - pub fn new(pack: PackConfig) -> Self { - Self { pack } + pub fn new(pack: PackConfig, compiler: Option) -> Self { + Self { pack, compiler } } } @@ -47,3 +50,15 @@ impl Default for PackConfig { fn default_pack_format() -> u8 { 26 } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CompilerConfig { + /// The path of a folder which files and subfolders will be copied to the root of the datapack. + pub assets: Option, +} + +impl CompilerConfig { + pub fn new(assets: Option) -> Self { + Self { assets } + } +} diff --git a/src/subcommands/build.rs b/src/subcommands/build.rs index bbaf634..3a4c22c 100644 --- a/src/subcommands/build.rs +++ b/src/subcommands/build.rs @@ -1,10 +1,11 @@ use color_eyre::eyre::Result; use path_absolutize::Absolutize; +use shulkerbox::virtual_fs::VFolder; use crate::{ config::ProjectConfig, error::Error, - terminal_output::{print_error, print_info}, + terminal_output::{print_error, print_info, print_warning}, }; use std::{ env, fs, @@ -17,8 +18,13 @@ pub struct BuildArgs { #[clap(default_value = ".")] pub path: PathBuf, /// The path of the directory to place the compiled datapack. + /// Overrides the `DATAPACK_DIR` environment variable. #[clap(short, long)] pub output: Option, + /// The path of a folder which files and subfolders will be copied to the root of the datapack. + /// Overrides the `assets` field in the pack.toml file. + #[clap(short, long)] + pub assets: Option, } pub fn build(_verbose: bool, args: &BuildArgs) -> Result<()> { @@ -29,7 +35,7 @@ pub fn build(_verbose: bool, args: &BuildArgs) -> Result<()> { .or_else(|| env::var("DATAPACK_DIR").ok().map(PathBuf::from)) .unwrap_or_else(|| path.join("dist")); - print_info(&format!( + print_info(format!( "Building project at {}", path.absolutize()?.display() )); @@ -51,11 +57,39 @@ pub fn build(_verbose: bool, args: &BuildArgs) -> Result<()> { let compiled = shulkerscript_lang::compile(&script_paths)?; + let assets_path = args.assets.clone().or(project_config + .compiler + .as_ref() + .and_then(|c| c.assets.as_ref().map(|p| path.join(p)))); + + let output = if let Some(assets_path) = assets_path { + let assets = VFolder::try_from(assets_path.as_path()); + if assets.is_err() { + print_error(format!( + "The specified assets path does not exist: {}", + assets_path.display() + )); + } + let mut assets = assets?; + let replaced = assets.merge(compiled); + + for replaced in replaced { + print_warning(format!( + "Template file {} was replaced by a file in the compiled datapack", + replaced + )); + } + + assets + } else { + compiled + }; + let dist_path = dist_path.join(project_config.pack.name); - compiled.place(&dist_path)?; + output.place(&dist_path)?; - print_info(&format!( + print_info(format!( "Finished building project to {}", dist_path.absolutize_from(path)?.display() )); diff --git a/src/subcommands/clean.rs b/src/subcommands/clean.rs index 2590ff5..6c963e7 100644 --- a/src/subcommands/clean.rs +++ b/src/subcommands/clean.rs @@ -44,7 +44,7 @@ pub fn clean(verbose: bool, args: &CleanArgs) -> Result<()> { delete_paths.push(dist_path.join(project_config.pack.name + ".zip")); } - print_info(&format!( + print_info(format!( "Cleaning project at {}", path.absolutize_from(path)?.display() )); @@ -67,7 +67,7 @@ pub fn clean(verbose: bool, args: &CleanArgs) -> Result<()> { && dist_path.read_dir()?.next().is_none() { if verbose { - print_info(&format!("Deleting {:?}, as it is empty", dist_path)); + print_info(format!("Deleting {:?}, as it is empty", dist_path)); } std::fs::remove_dir(&dist_path)?; } diff --git a/src/subcommands/init.rs b/src/subcommands/init.rs index 9a6e783..98b21e7 100644 --- a/src/subcommands/init.rs +++ b/src/subcommands/init.rs @@ -118,7 +118,7 @@ fn create_pack_config( fs::write(&path, toml::to_string_pretty(&content)?)?; if verbose { - print_info(&format!( + print_info(format!( "Created pack.toml file at {}.", path.absolutize()?.display() )); @@ -130,7 +130,7 @@ fn create_dir(path: &Path, verbose: bool) -> std::io::Result<()> { if !path.exists() { fs::create_dir(path)?; if verbose { - print_info(&format!( + print_info(format!( "Created directory at {}.", path.absolutize()?.display() )); @@ -143,7 +143,7 @@ fn create_gitignore(path: &Path, verbose: bool) -> std::io::Result<()> { let gitignore = path.join(".gitignore"); fs::write(&gitignore, "/dist\n")?; if verbose { - print_info(&format!( + print_info(format!( "Created .gitignore file at {}.", gitignore.absolutize()?.display() )); @@ -155,7 +155,7 @@ fn create_pack_png(path: &Path, verbose: bool) -> std::io::Result<()> { let pack_png = path.join("pack.png"); fs::write(&pack_png, include_bytes!("../../assets/default-icon.png"))?; if verbose { - print_info(&format!( + print_info(format!( "Created pack.png file at {}.", pack_png.absolutize()?.display() )); @@ -173,7 +173,7 @@ fn create_main_file(path: &Path, namespace: &str, verbose: bool) -> std::io::Res ), )?; if verbose { - print_info(&format!( + print_info(format!( "Created main.shu file at {}.", main_file.absolutize()?.display() )); diff --git a/src/subcommands/package.rs b/src/subcommands/package.rs index 4f8a8d2..ed03a66 100644 --- a/src/subcommands/package.rs +++ b/src/subcommands/package.rs @@ -2,8 +2,12 @@ use std::{env, path::PathBuf}; use color_eyre::eyre::Result; use path_absolutize::Absolutize; +use shulkerbox::virtual_fs::VFolder; -use crate::{error::Error, terminal_output::print_info}; +use crate::{ + error::Error, + terminal_output::{print_error, print_info, print_warning}, +}; use super::BuildArgs; @@ -22,7 +26,7 @@ pub fn package(_verbose: bool, args: &PackageArgs) -> Result<()> { .or_else(|| env::var("DATAPACK_DIR").ok().map(PathBuf::from)) .unwrap_or_else(|| path.join("dist")); - print_info(&format!( + print_info(format!( "Packaging project at {}", path.absolutize()?.display() )); @@ -38,11 +42,39 @@ pub fn package(_verbose: bool, args: &PackageArgs) -> Result<()> { let compiled = shulkerscript_lang::compile(&script_paths)?; + let assets_path = args.build_args.assets.clone().or(project_config + .compiler + .as_ref() + .and_then(|c| c.assets.as_ref().map(|p| path.join(p)))); + + let output = if let Some(assets_path) = assets_path { + let assets = VFolder::try_from(assets_path.as_path()); + if assets.is_err() { + print_error(format!( + "The specified assets path does not exist: {}", + assets_path.display() + )); + } + let mut assets = assets?; + let replaced = assets.merge(compiled); + + for replaced in replaced { + print_warning(format!( + "Template file {} was replaced by a file in the compiled datapack", + replaced + )); + } + + assets + } else { + compiled + }; + let dist_path = dist_path.join(project_config.pack.name + ".zip"); - compiled.zip(&dist_path)?; + output.zip(&dist_path)?; - print_info(&format!( + print_info(format!( "Finished packaging project to {}", dist_path.absolutize_from(path)?.display() )); diff --git a/src/terminal_output.rs b/src/terminal_output.rs index 039619a..62bb02f 100644 --- a/src/terminal_output.rs +++ b/src/terminal_output.rs @@ -1,12 +1,31 @@ +use std::fmt::Display; + use colored::Colorize; -pub fn print_info(msg: &str) { +pub fn print_info(msg: D) +where + D: Display, +{ println!("[{}] {msg}", "INFO".blue()) } -pub fn print_success(msg: &str) { +pub fn print_success(msg: D) +where + D: Display, +{ println!("[{}] {msg}", "SUCCESS".green()) } -pub fn print_error(msg: &str) { + +pub fn print_warning(msg: D) +where + D: Display, +{ + println!("[{}] {msg}", "WARNING".yellow()) +} + +pub fn print_error(msg: D) +where + D: Display, +{ println!("[{}] {msg}", "ERROR".red()) }