-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for packed animation plugins (wasm only)
- Loading branch information
Showing
18 changed files
with
520 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/target | ||
**/captures | ||
*.crab | ||
|
||
*.csv | ||
*.log | ||
|
@@ -14,4 +15,4 @@ webui/dist | |
*-wal | ||
|
||
.DS_Store | ||
.idea | ||
.idea |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ members = [ | |
"visualizer", | ||
"events", | ||
"test-wasm-animation", | ||
"animation-packer", | ||
] | ||
|
||
resolver = "2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "animation-packer" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
serde = { version = "1.0.215", features = ["derive"] } | ||
serde_json = "1.0.133" | ||
tar = "0.4.43" | ||
thiserror = "2.0.3" | ||
|
||
[features] | ||
default = ["pack", "unpack"] | ||
pack = [] | ||
unpack = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Rustmas Animation Packer | ||
======================== | ||
|
||
This crate contains utilities for wrapping animations into Compiled Rustmas | ||
Animation Bundles (yes, we worked very hard on this acronym, glad you noticed). | ||
|
||
Additionally, an executable `crabwrap` is provided to help create animation | ||
plugin files from animation code. In order to create an animation plugin file, | ||
run `crabwrap` from the root directory of your animation. Before that, | ||
you might need to install the `wasm32-wasip2` target for your Rust toolchain: | ||
|
||
``` | ||
rustup target add wasm32-wasip2 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use std::{ | ||
fs::read_dir, | ||
path::PathBuf, | ||
process::{Command, ExitStatus}, | ||
}; | ||
|
||
fn build_plugin() -> std::io::Result<ExitStatus> { | ||
let mut cmd = Command::new("cargo") | ||
.args(["build", "--target", "wasm32-wasip2", "--release"]) | ||
.spawn()?; | ||
cmd.wait() | ||
} | ||
|
||
fn find_animation_id() -> std::io::Result<String> { | ||
std::env::current_dir()? | ||
.components() | ||
.last() | ||
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, "Invalid project path")) | ||
.map(|c| c.as_os_str().to_string_lossy().to_string()) | ||
.map(|s| s.replace('-', "_")) | ||
} | ||
|
||
fn find_manifest() -> std::io::Result<PathBuf> { | ||
let manifest_path = std::env::current_dir()?.join("manifest.json"); | ||
|
||
if !manifest_path.exists() { | ||
Err(std::io::Error::new( | ||
std::io::ErrorKind::NotFound, | ||
"Could not find manifest.json", | ||
)) | ||
} else { | ||
Ok(manifest_path) | ||
} | ||
} | ||
|
||
fn find_animation_executable() -> std::io::Result<PathBuf> { | ||
let project_root = find_project_root()?; | ||
let animation_id = find_animation_id()?; | ||
|
||
let executable_path = project_root | ||
.join("target/wasm32-wasip2/release") | ||
.join(format!("{animation_id}.wasm")); | ||
|
||
if !executable_path.exists() { | ||
Err(std::io::Error::new( | ||
std::io::ErrorKind::NotFound, | ||
"Could not find animation executable", | ||
)) | ||
} else { | ||
Ok(executable_path) | ||
} | ||
} | ||
|
||
fn get_output_path() -> std::io::Result<PathBuf> { | ||
let animation_id = find_animation_id()?; | ||
Ok(std::env::current_dir()? | ||
.as_path() | ||
.join(format!("{animation_id}.crab"))) | ||
} | ||
|
||
fn find_project_root() -> std::io::Result<PathBuf> { | ||
std::env::current_dir()? | ||
.as_path() | ||
.ancestors() | ||
.find(|p| { | ||
let Ok(dir) = read_dir(p) else { | ||
return false; | ||
}; | ||
dir.into_iter() | ||
.filter_map(|p| p.ok()) | ||
.map(|p| p.file_name().to_string_lossy().to_string()) | ||
.any(|p| p == "Cargo.lock") | ||
}) | ||
.map(PathBuf::from) | ||
.ok_or_else(|| { | ||
std::io::Error::new( | ||
std::io::ErrorKind::NotFound, | ||
"Could not find Cargo.lock until filesystem root", | ||
) | ||
}) | ||
} | ||
|
||
fn main() { | ||
let manifest_path = find_manifest().expect("Could not find manifest.json file"); | ||
|
||
build_plugin().expect("Failed to build the plugin"); | ||
|
||
let executable_path = find_animation_executable().expect("Could not find animation executable"); | ||
let output_path = get_output_path().expect("Could not generate output path"); | ||
|
||
animation_packer::pack::pack_plugin(&output_path, &executable_path, &manifest_path) | ||
.expect("Failed to pack the plugin"); | ||
|
||
println!("Plugin ready at {}", output_path.to_string_lossy()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use std::{ | ||
path::{Path, PathBuf}, | ||
process::{Command, Stdio}, | ||
}; | ||
|
||
use serde::Deserialize; | ||
|
||
use crate::unpack::PluginUnpackError; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum PluginConfigError { | ||
#[error("Failed to parse manifest: {reason}")] | ||
InvalidManifest { reason: String }, | ||
|
||
#[error("Failed to unpack plugin")] | ||
InvalidPluginPack(#[from] PluginUnpackError), | ||
|
||
#[error("Directory containing plugin has non UTF-8 name")] | ||
NonUtf8DirectoryName, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, Default, PartialEq, Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum PluginType { | ||
#[default] | ||
Native, | ||
Wasm, | ||
} | ||
|
||
#[derive(Debug, Clone, Deserialize)] | ||
pub struct PluginManifest { | ||
display_name: String, | ||
#[serde(default)] | ||
plugin_type: PluginType, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct PluginConfig { | ||
pub(crate) animation_id: String, | ||
pub(crate) manifest: PluginManifest, | ||
pub(crate) path: PathBuf, | ||
} | ||
|
||
impl PluginConfig { | ||
pub fn new(path: PathBuf) -> Result<Self, PluginConfigError> { | ||
let manifest: PluginManifest = | ||
serde_json::from_slice(&std::fs::read(path.join("manifest.json")).map_err(|e| { | ||
PluginConfigError::InvalidManifest { | ||
reason: format!("IO error: {}", e), | ||
} | ||
})?) | ||
.map_err(|e| PluginConfigError::InvalidManifest { | ||
reason: e.to_string(), | ||
})?; | ||
|
||
let animation_id = path | ||
.file_name() | ||
.unwrap() | ||
.to_str() | ||
.ok_or(PluginConfigError::NonUtf8DirectoryName)? | ||
.to_owned(); | ||
|
||
Ok(Self { | ||
animation_id, | ||
manifest, | ||
path, | ||
}) | ||
} | ||
|
||
pub fn animation_id(&self) -> &str { | ||
&self.animation_id | ||
} | ||
|
||
pub fn animation_name(&self) -> &str { | ||
&self.manifest.display_name | ||
} | ||
|
||
pub fn plugin_type(&self) -> PluginType { | ||
self.manifest.plugin_type | ||
} | ||
|
||
pub fn path(&self) -> &Path { | ||
self.path.as_path() | ||
} | ||
|
||
pub fn executable_path(&self) -> PathBuf { | ||
let executable_name = if self.manifest.plugin_type == PluginType::Wasm { | ||
"plugin.wasm" | ||
} else if cfg!(windows) { | ||
"plugin.exe" | ||
} else { | ||
"plugin" | ||
}; | ||
|
||
self.path.join(executable_name) | ||
} | ||
|
||
pub fn is_executable(&self) -> bool { | ||
match self.manifest.plugin_type { | ||
PluginType::Native => Command::new(self.executable_path()) | ||
.stdout(Stdio::null()) | ||
.stdin(Stdio::null()) | ||
.spawn() | ||
.is_ok(), | ||
PluginType::Wasm => self.executable_path().exists(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
pub mod config; | ||
|
||
#[cfg(feature = "pack")] | ||
pub mod pack; | ||
|
||
#[cfg(feature = "unpack")] | ||
pub mod unpack; |
Oops, something went wrong.