Install plugin from CLI (#304)

* add install command

* cargo fmt

* filter spec files

* Update src/cli/plugin.rs

Co-Authored-By: Lucien Greathouse <me@lpghatguy.com>

* Update src/cli/plugin.rs

Co-Authored-By: Lucien Greathouse <me@lpghatguy.com>

* fix comments

* encode plugin with rbx_binary

* update build script

* refactor pathbuf error into io error

* fix rojo typo

* remove snafu

* Update `snapshot_from_fs_path`

* Print `rerun-if-changed` even for directories, in order to run the
  build.rs script when files are added.

* Switch `filter_map` loop to a regular for loop. I like the FP-style
  iterator stuff in Rust, but I think Result handling is easier in a
  normal loop. Also, I don't believe the result of read_dir implements
  `ExactSizedIterator`, so some of the wins of map+collect aren't there.

* Replace Result::unwrap with ? in build.rs

* Simplify error handling code in runtime

* Checkout with submodules

Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
This commit is contained in:
jeparlefrancais
2020-03-29 16:41:54 -04:00
committed by GitHub
parent 9b459c20d6
commit 3cf82e112f
10 changed files with 373 additions and 105 deletions

View File

@@ -12,6 +12,7 @@ fn run(global: GlobalOptions, subcommand: Subcommand) -> Result<(), Box<dyn Erro
Subcommand::Build(build_options) => cli::build(build_options)?,
Subcommand::Upload(upload_options) => cli::upload(upload_options)?,
Subcommand::Doc => cli::doc()?,
Subcommand::Plugin(plugin_options) => cli::plugin(plugin_options)?,
}
Ok(())

View File

@@ -3,6 +3,7 @@
mod build;
mod doc;
mod init;
mod plugin;
mod serve;
mod upload;
@@ -21,6 +22,7 @@ use thiserror::Error;
pub use self::build::*;
pub use self::doc::*;
pub use self::init::*;
pub use self::plugin::*;
pub use self::serve::*;
pub use self::upload::*;
@@ -111,6 +113,9 @@ pub enum Subcommand {
/// Open Rojo's documentation in your browser.
Doc,
/// Manages Rojo's Roblox Studio plugin.
Plugin(PluginCommand),
}
/// Initializes a new Rojo project.
@@ -287,3 +292,21 @@ fn resolve_path(path: &Path) -> Cow<'_, Path> {
Cow::Owned(env::current_dir().unwrap().join(path))
}
}
#[derive(Debug, StructOpt)]
pub enum PluginSubcommand {
/// Install the plugin in Roblox Studio's plugins folder. If the plugin is
/// already installed, installing it again will overwrite the current plugin
/// file.
Install,
/// Removes the plugin if it is installed.
Uninstall,
}
/// Install Rojo's plugin.
#[derive(Debug, StructOpt)]
pub struct PluginCommand {
#[structopt(subcommand)]
subcommand: PluginSubcommand,
}

70
src/cli/plugin.rs Normal file
View File

@@ -0,0 +1,70 @@
use std::{
fs::{self, File},
io::BufWriter,
};
use anyhow::Result;
use memofs::{InMemoryFs, Vfs, VfsSnapshot};
use roblox_install::RobloxStudio;
use crate::{
cli::{PluginCommand, PluginSubcommand},
serve_session::ServeSession,
};
static PLUGIN_BINCODE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/plugin.bincode"));
static PLUGIN_FILE_NAME: &str = "RojoManagedPlugin.rbxm";
pub fn plugin(options: PluginCommand) -> Result<()> {
match options.subcommand {
PluginSubcommand::Install => install_plugin(),
PluginSubcommand::Uninstall => uninstall_plugin(),
}
}
pub fn install_plugin() -> Result<()> {
let plugin_snapshot: VfsSnapshot = bincode::deserialize(PLUGIN_BINCODE)
.expect("Rojo's plugin was not properly packed into Rojo's binary");
let studio = RobloxStudio::locate()?;
let plugins_folder_path = studio.plugins_path();
if !plugins_folder_path.exists() {
log::debug!("Creating Roblox Studio plugins folder");
fs::create_dir(plugins_folder_path)?;
}
let mut in_memory_fs = InMemoryFs::new();
in_memory_fs.load_snapshot("plugin", plugin_snapshot)?;
let vfs = Vfs::new(in_memory_fs);
let session = ServeSession::new(vfs, "plugin")?;
let plugin_path = plugins_folder_path.join(PLUGIN_FILE_NAME);
log::debug!("Writing plugin to {}", plugin_path.display());
let mut file = BufWriter::new(File::create(plugin_path)?);
let tree = session.tree();
let root_id = tree.get_root_id();
rbx_binary::encode(tree.inner(), &[root_id], &mut file)?;
Ok(())
}
fn uninstall_plugin() -> Result<()> {
let studio = RobloxStudio::locate()?;
let plugin_path = studio.plugins_path().join(PLUGIN_FILE_NAME);
if plugin_path.exists() {
log::debug!("Removing existing plugin from {}", plugin_path.display());
fs::remove_file(plugin_path)?;
} else {
log::debug!("Plugin not installed at {}", plugin_path.display());
}
Ok(())
}