1use std::{
2 fs::{self, File},
3 io::BufWriter,
4};
5
6use clap::Parser;
7use memofs::{InMemoryFs, Vfs, VfsSnapshot};
8use roblox_install::RobloxStudio;
9
10use crate::serve_session::ServeSession;
11
12static PLUGIN_BINCODE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/plugin.bincode"));
13static PLUGIN_FILE_NAME: &str = "RojoManagedPlugin.rbxm";
14
15#[derive(Debug, Parser)]
17pub struct PluginCommand {
18 #[clap(subcommand)]
19 subcommand: PluginSubcommand,
20}
21
22#[derive(Debug, Parser)]
24pub enum PluginSubcommand {
25 Install,
29
30 Uninstall,
32}
33
34impl PluginCommand {
35 pub fn run(self) -> anyhow::Result<()> {
36 self.subcommand.run()
37 }
38}
39
40impl PluginSubcommand {
41 pub fn run(self) -> anyhow::Result<()> {
42 match self {
43 PluginSubcommand::Install => install_plugin(),
44 PluginSubcommand::Uninstall => uninstall_plugin(),
45 }
46 }
47}
48
49fn initialize_plugin() -> anyhow::Result<ServeSession> {
50 let plugin_snapshot: VfsSnapshot = bincode::deserialize(PLUGIN_BINCODE)
51 .expect("Rojo's plugin was not properly packed into Rojo's binary");
52
53 let mut in_memory_fs = InMemoryFs::new();
54 in_memory_fs.load_snapshot("/plugin", plugin_snapshot)?;
55
56 let vfs = Vfs::new(in_memory_fs);
57 Ok(ServeSession::new(vfs, "/plugin")?)
58}
59
60fn install_plugin() -> anyhow::Result<()> {
61 let studio = RobloxStudio::locate()?;
62
63 let plugins_folder_path = studio.plugins_path();
64
65 if !plugins_folder_path.exists() {
66 log::debug!("Creating Roblox Studio plugins folder");
67 fs::create_dir(plugins_folder_path)?;
68 }
69
70 let plugin_path = plugins_folder_path.join(PLUGIN_FILE_NAME);
71 log::debug!("Writing plugin to {}", plugin_path.display());
72
73 let mut file = BufWriter::new(File::create(plugin_path)?);
74
75 let session = initialize_plugin()?;
76 let tree = session.tree();
77 let root_id = tree.get_root_id();
78
79 rbx_binary::to_writer(&mut file, tree.inner(), &[root_id])?;
80
81 Ok(())
82}
83
84fn uninstall_plugin() -> anyhow::Result<()> {
85 let studio = RobloxStudio::locate()?;
86
87 let plugin_path = studio.plugins_path().join(PLUGIN_FILE_NAME);
88
89 if plugin_path.exists() {
90 log::debug!("Removing existing plugin from {}", plugin_path.display());
91 fs::remove_file(plugin_path)?;
92 } else {
93 log::debug!("Plugin not installed at {}", plugin_path.display());
94 }
95
96 Ok(())
97}
98
99#[test]
100fn plugin_initialize() {
101 let _ = initialize_plugin().unwrap();
102}