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 install_plugin() -> anyhow::Result<()> {
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 studio = RobloxStudio::locate()?;
54
55 let plugins_folder_path = studio.plugins_path();
56
57 if !plugins_folder_path.exists() {
58 log::debug!("Creating Roblox Studio plugins folder");
59 fs::create_dir(plugins_folder_path)?;
60 }
61
62 let mut in_memory_fs = InMemoryFs::new();
63 in_memory_fs.load_snapshot("/plugin", plugin_snapshot)?;
64
65 let vfs = Vfs::new(in_memory_fs);
66 let session = ServeSession::new(vfs, "/plugin")?;
67
68 let plugin_path = plugins_folder_path.join(PLUGIN_FILE_NAME);
69 log::debug!("Writing plugin to {}", plugin_path.display());
70
71 let mut file = BufWriter::new(File::create(plugin_path)?);
72
73 let tree = session.tree();
74 let root_id = tree.get_root_id();
75
76 rbx_binary::to_writer(&mut file, tree.inner(), &[root_id])?;
77
78 Ok(())
79}
80
81fn uninstall_plugin() -> anyhow::Result<()> {
82 let studio = RobloxStudio::locate()?;
83
84 let plugin_path = studio.plugins_path().join(PLUGIN_FILE_NAME);
85
86 if plugin_path.exists() {
87 log::debug!("Removing existing plugin from {}", plugin_path.display());
88 fs::remove_file(plugin_path)?;
89 } else {
90 log::debug!("Plugin not installed at {}", plugin_path.display());
91 }
92
93 Ok(())
94}