From 6596e715b1c123269b9a9e7fe6867267df987e22 Mon Sep 17 00:00:00 2001 From: Adrien Burgun Date: Sun, 24 Jul 2022 20:30:41 +0200 Subject: [PATCH] :sparkles: Rust implementation of the automation script --- .gitignore | 2 + automate-rs/Cargo.lock | 309 +++++++++++++++++++ automate-rs/Cargo.toml | 12 + automate-rs/resources/assets/lgbtq_heart.svg | 222 +++++++++++++ automate-rs/resources/blobfox.yml | 15 + automate-rs/resources/neugeme.yml | 11 + automate-rs/src/decl.rs | 107 +++++++ automate-rs/src/main.rs | 41 +++ 8 files changed, 719 insertions(+) create mode 100644 automate-rs/Cargo.lock create mode 100644 automate-rs/Cargo.toml create mode 100644 automate-rs/resources/assets/lgbtq_heart.svg create mode 100644 automate-rs/resources/blobfox.yml create mode 100644 automate-rs/resources/neugeme.yml create mode 100644 automate-rs/src/decl.rs create mode 100644 automate-rs/src/main.rs diff --git a/.gitignore b/.gitignore index b9fb92a..454f55b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ original/ output/ +__pycache__ +target diff --git a/automate-rs/Cargo.lock b/automate-rs/Cargo.lock new file mode 100644 index 0000000..033c6a8 --- /dev/null +++ b/automate-rs/Cargo.lock @@ -0,0 +1,309 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blobfox" +version = "0.1.0" +dependencies = [ + "clap", + "serde", + "serde_yaml", + "xmltree", +] + +[[package]] +name = "clap" +version = "3.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "os_str_bytes" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "serde" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/automate-rs/Cargo.toml b/automate-rs/Cargo.toml new file mode 100644 index 0000000..ecbc31a --- /dev/null +++ b/automate-rs/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "blobfox" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +xmltree = "0.10" +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8" +clap = { version = "3.2.14", features = ["derive"] } diff --git a/automate-rs/resources/assets/lgbtq_heart.svg b/automate-rs/resources/assets/lgbtq_heart.svg new file mode 100644 index 0000000..e8f245f --- /dev/null +++ b/automate-rs/resources/assets/lgbtq_heart.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automate-rs/resources/blobfox.yml b/automate-rs/resources/blobfox.yml new file mode 100644 index 0000000..c920640 --- /dev/null +++ b/automate-rs/resources/blobfox.yml @@ -0,0 +1,15 @@ +name: 'blobfox' +base_off: null +variants: + 'base': + src: '../vector/blobfox.svg' + + 'boop': + assets: + - type: svg + src: 'assets/lgbtq_heart.svg' + + overwrites: + - id: 'eye-left' + fill: 0xffffffff + remove: true diff --git a/automate-rs/resources/neugeme.yml b/automate-rs/resources/neugeme.yml new file mode 100644 index 0000000..a5a7016 --- /dev/null +++ b/automate-rs/resources/neugeme.yml @@ -0,0 +1,11 @@ +name: 'neugeme' +base: 'blobfox.yml' # all variants from 'blobfox' will be imported in this unit, unless they are already present +variants: + 'base': + overwrites: + - id: 'body' + fill: 0x02FFFD + - id: 'hair' + fill: 0x02FFFD + - id: 'blobfox' + remove: true diff --git a/automate-rs/src/decl.rs b/automate-rs/src/decl.rs new file mode 100644 index 0000000..a56d84c --- /dev/null +++ b/automate-rs/src/decl.rs @@ -0,0 +1,107 @@ +use std::path::{PathBuf, Path}; +use std::collections::HashMap; +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Declaration { + pub name: String, + pub base: Option, + pub variants: HashMap, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Variant { + pub base: Option, + + pub src: Option, // Loads every asset from an SVG file + #[serde(default)] + pub assets: Vec, // Loads individual assets + + #[serde(default)] + pub overwrites: Vec, // Operations on assets +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Asset { + pub src: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Overwrite { + pub id: String, // ID of the element to modify + + pub fill: Option, + pub stroke: Option, + + #[serde(default)] + pub remove: bool, +} + +impl Declaration { + pub fn join(self, parent: Self) -> Self { + let mut variants = self.variants; + + for (name, parent_variant) in parent.variants { + if let Some(variant) = variants.get_mut(&name) { + variant.join(parent_variant); + } else { + variants.insert(name, parent_variant); + } + } + + Self { + name: self.name, + base: parent.base, + variants + } + } + + /// Replaces every path relative to the yaml file to paths relative to the cwd + pub fn canonicalize(&mut self, path: impl AsRef) { + let path = path.as_ref().parent().unwrap_or(&PathBuf::from(".")).to_path_buf(); + for variant in self.variants.values_mut() { + variant.canonicalize(path.as_ref()); + } + } +} + +impl Variant { + pub fn join(&mut self, mut parent: Self) { + self.assets.append(&mut parent.assets); + self.overwrites.append(&mut parent.overwrites); + + if self.base.is_none() { + self.base = parent.base; + } + + if self.src.is_none() { + self.src = parent.src; // TODO: handle relative paths + } + } + + /// Replaces every path relative to the yaml file to paths relative to the cwd + pub fn canonicalize(&mut self, path: &Path) { + match &mut self.src { + Some(src_path) => *src_path = path.join(&*src_path), + None => {} + } + + for asset in &mut self.assets { + asset.canonicalize(path); + } + + // for overwrite in &mut self.overwrites { + // overwrite.canonicalize(path); + // } + } +} + +impl Asset { + /// Replaces every path relative to the yaml file to paths relative to the cwd + pub fn canonicalize(&mut self, path: &Path) { + match &mut self.src { + Some(src_path) => *src_path = path.join(&*src_path), + None => {} + } + } +} diff --git a/automate-rs/src/main.rs b/automate-rs/src/main.rs new file mode 100644 index 0000000..36bb8d8 --- /dev/null +++ b/automate-rs/src/main.rs @@ -0,0 +1,41 @@ +use clap::Parser; +use std::path::PathBuf; + +pub mod decl; +use decl::*; + +fn main() { + let args = Args::parse(); + + let mut path = args.decl_file; + let raw = std::fs::read_to_string(&path).unwrap(); + let mut declaration: Declaration = serde_yaml::from_str(&raw).unwrap(); + declaration.canonicalize(&path); + + while let Some(parent) = std::mem::take(&mut declaration.base) { + path = path.parent().unwrap_or(&PathBuf::from(".")).join(parent); + let raw = std::fs::read_to_string(&path).unwrap_or_else(|err| { + // TODO: print the include stack + panic!("Couldn't read {}: {}", path.display(), err); + }); + + let mut parent_decl: Declaration = serde_yaml::from_str(&raw).unwrap(); + parent_decl.canonicalize(&path); + + declaration = declaration.join(parent_decl); + } + + println!("{:#?}", declaration); +} + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + /// A YAML file containing the declaration from which the emotes should be generated + #[clap(short, long, value_parser)] + decl_file: PathBuf, + + /// List of the emote names to export + #[clap(value_parser)] + names: Vec, +}