123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- use std::{
- collections::HashMap,
- fs::File,
- io::{self, BufWriter, Write},
- path::PathBuf,
- };
- use failure::Fail;
- use rbx_dom_weak::RbxInstanceProperties;
- use crate::{
- imfs::new::{FsError, Imfs, RealFetcher, WatchMode},
- snapshot::{apply_patch_set, compute_patch_set, InstancePropertiesWithMeta, RojoTree},
- snapshot_middleware::snapshot_from_imfs,
- };
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
- pub enum OutputKind {
- Rbxmx,
- Rbxlx,
- Rbxm,
- Rbxl,
- }
- fn detect_output_kind(options: &BuildOptions) -> Option<OutputKind> {
- let extension = options.output_file.extension()?.to_str()?;
- match extension {
- "rbxlx" => Some(OutputKind::Rbxlx),
- "rbxmx" => Some(OutputKind::Rbxmx),
- "rbxl" => Some(OutputKind::Rbxl),
- "rbxm" => Some(OutputKind::Rbxm),
- _ => None,
- }
- }
- #[derive(Debug)]
- pub struct BuildOptions {
- pub fuzzy_project_path: PathBuf,
- pub output_file: PathBuf,
- pub output_kind: Option<OutputKind>,
- }
- #[derive(Debug, Fail)]
- pub enum BuildError {
- #[fail(display = "Could not detect what kind of file to create")]
- UnknownOutputKind,
- #[fail(display = "IO error: {}", _0)]
- IoError(#[fail(cause)] io::Error),
- #[fail(display = "XML model file error")]
- XmlModelEncodeError(rbx_xml::EncodeError),
- #[fail(display = "Binary model file error")]
- BinaryModelEncodeError(rbx_binary::EncodeError),
- #[fail(display = "{}", _0)]
- FsError(#[fail(cause)] FsError),
- }
- impl_from!(BuildError {
- io::Error => IoError,
- rbx_xml::EncodeError => XmlModelEncodeError,
- rbx_binary::EncodeError => BinaryModelEncodeError,
- FsError => FsError,
- });
- fn xml_encode_config() -> rbx_xml::EncodeOptions {
- rbx_xml::EncodeOptions::new().property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown)
- }
- pub fn build(options: &BuildOptions) -> Result<(), BuildError> {
- let output_kind = options
- .output_kind
- .or_else(|| detect_output_kind(options))
- .ok_or(BuildError::UnknownOutputKind)?;
- log::info!("Hoping to generate file of type {:?}", output_kind);
- let mut tree = RojoTree::new(InstancePropertiesWithMeta {
- properties: RbxInstanceProperties {
- name: "ROOT".to_owned(),
- class_name: "Folder".to_owned(),
- properties: HashMap::new(),
- },
- metadata: Default::default(),
- });
- let root_id = tree.get_root_id();
- log::trace!("Constructing in-memory filesystem");
- let mut imfs = Imfs::new(RealFetcher::new(WatchMode::Disabled));
- log::trace!("Reading project root");
- let entry = imfs
- .get(&options.fuzzy_project_path)
- .expect("could not get project path");
- log::trace!("Generating snapshot of instances from IMFS");
- let snapshot = snapshot_from_imfs(&mut imfs, &entry)
- .expect("snapshot failed")
- .expect("snapshot did not return an instance");
- log::trace!("Computing patch set");
- let patch_set = compute_patch_set(&snapshot, &tree, root_id);
- log::trace!("Applying patch set");
- apply_patch_set(&mut tree, &patch_set);
- log::trace!("Opening output file for write");
- let mut file = BufWriter::new(File::create(&options.output_file)?);
- match output_kind {
- OutputKind::Rbxmx => {
- // Model files include the root instance of the tree and all its
- // descendants.
- rbx_xml::to_writer(&mut file, tree.inner(), &[root_id], xml_encode_config())?;
- }
- OutputKind::Rbxlx => {
- // Place files don't contain an entry for the DataModel, but our
- // RbxTree representation does.
- let root_instance = tree.get_instance(root_id).unwrap();
- let top_level_ids = root_instance.children();
- rbx_xml::to_writer(&mut file, tree.inner(), top_level_ids, xml_encode_config())?;
- }
- OutputKind::Rbxm => {
- rbx_binary::encode(tree.inner(), &[root_id], &mut file)?;
- }
- OutputKind::Rbxl => {
- log::warn!("Support for building binary places (rbxl) is still experimental.");
- log::warn!("Using the XML place format (rbxlx) is recommended instead.");
- log::warn!("For more info, see https://github.com/LPGhatguy/rojo/issues/180");
- let root_instance = tree.get_instance(root_id).unwrap();
- let top_level_ids = root_instance.children();
- rbx_binary::encode(tree.inner(), top_level_ids, &mut file)?;
- }
- }
- file.flush()?;
- log::trace!("Done!");
- Ok(())
- }
|