213 lines
5.5 KiB
Python
213 lines
5.5 KiB
Python
"thanks chatgpt"
|
|
|
|
import os
|
|
import textwrap
|
|
from abc import ABC, abstractmethod
|
|
from collections.abc import Iterable
|
|
from pathlib import Path
|
|
from typing import Callable
|
|
|
|
root = Path(__file__).parent.parent
|
|
static = root / "static"
|
|
src = root / "src"
|
|
out_rs = src / "assets.rs"
|
|
|
|
assert 'name = "wakey"' in (root / "Cargo.toml").read_text(encoding="utf-8"), (
|
|
"uhh how do i explain this"
|
|
)
|
|
|
|
|
|
def sanitize(name: str) -> str:
|
|
# Valid Rust identifiers: letters, digits, underscores; no starting digit
|
|
s = "".join(c if c.isalnum() else "_" for c in name)
|
|
if s and s[0].isdigit():
|
|
s = "_" + s
|
|
return s
|
|
|
|
|
|
def indent(text: str, n: int) -> str:
|
|
pad = " " * n
|
|
return textwrap.indent(text, pad)
|
|
|
|
|
|
class RsAsset(ABC):
|
|
path: Path
|
|
|
|
|
|
class RsAssetWithName(ABC):
|
|
name: str
|
|
|
|
@staticmethod
|
|
@abstractmethod
|
|
def name_gen(path: Path) -> str:
|
|
"helper"
|
|
|
|
|
|
class RsAssetFile(RsAsset, RsAssetWithName):
|
|
__match_args__ = ("path", "name")
|
|
|
|
def __init__(self, path: Path, name: str | None = None):
|
|
self.path = path
|
|
if name is None:
|
|
self.name: str = RsAssetFile.name_gen(path)
|
|
else:
|
|
self.name = name
|
|
|
|
def path_relative_to(self, path: Path):
|
|
"helper"
|
|
return self.path.relative_to(path, walk_up=True).as_posix()
|
|
|
|
@staticmethod
|
|
def plain_template(const_name: str, relative_path: str):
|
|
return f'pub const {const_name}: &str = include_str!("{relative_path}");'
|
|
|
|
@staticmethod
|
|
def macroed_template(const_name: str, relative_path: str):
|
|
return f'file {const_name} "{relative_path}"'
|
|
|
|
@staticmethod
|
|
def name_gen(path: Path) -> str:
|
|
return sanitize(path.name).upper()
|
|
|
|
|
|
class RsAssetModule(RsAsset, RsAssetWithName):
|
|
__match_args__ = ("path", "name")
|
|
|
|
def __init__(self, path: Path, name: str | None = None):
|
|
self.path = path
|
|
if name is None:
|
|
self.name: str = RsAssetModule.name_gen(path)
|
|
else:
|
|
self.name = name
|
|
|
|
@staticmethod
|
|
def plain_template(sanitized_name: str, body: str):
|
|
"braindead"
|
|
indented_body = indent(body, 4)
|
|
return f"pub mod {sanitized_name} {{\n{indented_body}\n}}"
|
|
|
|
@staticmethod
|
|
def macroed_template(sanitized_name: str, body: str):
|
|
indented_body = indent(body, 4)
|
|
return f"folder {sanitized_name} {{\n{indented_body}\n}}"
|
|
|
|
@staticmethod
|
|
def process_body(path: Path, renderer: Callable[[RsAsset], str]):
|
|
"here just cuz. Path has to be a folder... so idk"
|
|
body = RsAssetModule.iterate_assets(path)
|
|
return "\n".join(map(renderer, body))
|
|
|
|
@staticmethod
|
|
def iterate_assets(path: Path) -> "Iterable[RsAssetFile | RsAssetModule]":
|
|
subs = []
|
|
for f in path.iterdir():
|
|
if f.is_file():
|
|
yield RsAssetFile(f)
|
|
elif f.is_dir():
|
|
subs.append(RsAssetModule(f))
|
|
yield from subs
|
|
|
|
@staticmethod
|
|
def name_gen(path: Path) -> str:
|
|
return sanitize(path.name).lower()
|
|
|
|
|
|
# i meant plain
|
|
def render_pain(ass: RsAsset) -> str:
|
|
"""
|
|
fym i have to deal with all RsAsset subclasses.
|
|
|
|
ts like a matrix of ahh.
|
|
"""
|
|
match ass:
|
|
case RsAssetRoot(path):
|
|
body = RsAssetModule.process_body(path, render_pain)
|
|
return RsAssetRoot.plain_template(body)
|
|
case RsAssetModule(path, name):
|
|
body = RsAssetModule.process_body(path, render_pain)
|
|
return RsAssetModule.plain_template(name, body)
|
|
case RsAssetFile(path, name) as file:
|
|
return RsAssetFile.plain_template(name, file.path_relative_to(src))
|
|
case _:
|
|
raise TypeError("who are you?")
|
|
|
|
|
|
def render_macro(ass: RsAsset) -> str:
|
|
"""
|
|
ts is ridiculous
|
|
"""
|
|
match ass:
|
|
case RsAssetRoot(path):
|
|
body = RsAssetModule.process_body(path, render_macro)
|
|
return RsAssetRoot.macroed_template(body)
|
|
case RsAssetModule(path, name):
|
|
body = RsAssetModule.process_body(path, render_macro)
|
|
return RsAssetModule.macroed_template(name, body)
|
|
case RsAssetFile(path, name) as file:
|
|
return RsAssetFile.macroed_template(name, file.path_relative_to(src))
|
|
case _:
|
|
raise TypeError("who are you?")
|
|
|
|
|
|
# region shit ass
|
|
# im deleting this code because its so ass
|
|
# endregion
|
|
|
|
lda_macro = """
|
|
macro_rules! hehe {
|
|
// Folder
|
|
(folder $name:ident { $($children:tt)* } $($rest:tt)*) => {
|
|
pub mod $name {
|
|
hehe!{$($children)*}
|
|
}
|
|
hehe!{$($rest)*}
|
|
};
|
|
// File
|
|
(file $name:ident $file:literal $($rest:tt)*) => {
|
|
pub const $name: &str = include_str!($file);
|
|
hehe!{$($rest)*}
|
|
};
|
|
// Base case
|
|
() => {};
|
|
}
|
|
"""
|
|
header = "// generated with ./scripts/map_static.py"
|
|
|
|
|
|
class RsAssetRoot(RsAsset):
|
|
__match_args__ = ("path",)
|
|
|
|
@staticmethod
|
|
def plain_template(body: str):
|
|
return f"""{header}
|
|
|
|
{body}
|
|
"""
|
|
|
|
@staticmethod
|
|
def macroed_template(body: str):
|
|
indented_body = indent(body, 4)
|
|
return f"""{header}
|
|
{lda_macro}
|
|
hehe! {{
|
|
{indented_body}
|
|
}}
|
|
"""
|
|
|
|
def __init__(self, path: Path) -> None:
|
|
os.scandir(path) # is you a dir?
|
|
self.path = path
|
|
|
|
|
|
asset_root = RsAssetRoot(static)
|
|
|
|
# print(render_pain(asset_root))
|
|
# print(render_macro(asset_root))
|
|
|
|
# rs_code = render_pain(asset_root)
|
|
rs_code = render_macro(asset_root)
|
|
|
|
# generate
|
|
out_rs.write_text(rs_code, encoding="utf-8")
|
|
print(f"written to {out_rs.relative_to(Path.cwd(), walk_up=True)}")
|