mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 14:01:37 +00:00
Implement encoding and decoding for Windows-invalid characters in file names
- Added `encode_path_name` and `decode_path_name` functions to handle encoding and decoding of invalid characters. - Updated `SyncbackRules` to include an option for encoding Windows-invalid characters during syncback. - Modified `name_for_inst` to conditionally encode invalid characters based on the new option. - Adjusted `ServeSession` and `InstanceContext` to support the new encoding feature. - Updated tests and snapshots to reflect changes in encoding behavior.
This commit is contained in:
parent
db87fa010f
commit
6d8c85682d
59 changed files with 350 additions and 53 deletions
|
|
@ -6,12 +6,15 @@ use std::borrow::Cow;
|
|||
use anyhow::Context;
|
||||
use rbx_dom_weak::Instance;
|
||||
|
||||
use crate::{snapshot::InstanceWithMeta, snapshot_middleware::Middleware};
|
||||
use crate::{
|
||||
path_encoding::encode_path_name, snapshot::InstanceWithMeta, snapshot_middleware::Middleware,
|
||||
};
|
||||
|
||||
pub fn name_for_inst<'old>(
|
||||
middleware: Middleware,
|
||||
new_inst: &Instance,
|
||||
old_inst: Option<InstanceWithMeta<'old>>,
|
||||
encode_invalid_chars: bool,
|
||||
) -> anyhow::Result<Cow<'old, str>> {
|
||||
if let Some(old_inst) = old_inst {
|
||||
if let Some(source) = old_inst.metadata().relevant_paths.first() {
|
||||
|
|
@ -35,13 +38,37 @@ pub fn name_for_inst<'old>(
|
|||
| Middleware::CsvDir
|
||||
| Middleware::ServerScriptDir
|
||||
| Middleware::ClientScriptDir
|
||||
| Middleware::ModuleScriptDir => Cow::Owned(new_inst.name.clone()),
|
||||
| Middleware::ModuleScriptDir => {
|
||||
let name = if encode_invalid_chars {
|
||||
let encoded = encode_path_name(&new_inst.name);
|
||||
// Validate for issues not fixed by encoding (trailing space/dot, control chars, reserved names)
|
||||
validate_file_name(&encoded).with_context(|| {
|
||||
format!("name '{}' (encoded from '{}') is not legal to write to the file system", encoded, new_inst.name)
|
||||
})?;
|
||||
encoded
|
||||
} else {
|
||||
validate_file_name(&new_inst.name).with_context(|| {
|
||||
format!("name '{}' is not legal to write to the file system", new_inst.name)
|
||||
})?;
|
||||
new_inst.name.clone()
|
||||
};
|
||||
Cow::Owned(name)
|
||||
}
|
||||
_ => {
|
||||
let extension = extension_for_middleware(middleware);
|
||||
let name = &new_inst.name;
|
||||
validate_file_name(name).with_context(|| {
|
||||
format!("name '{name}' is not legal to write to the file system")
|
||||
})?;
|
||||
let name = if encode_invalid_chars {
|
||||
let encoded = encode_path_name(&new_inst.name);
|
||||
// Validate for issues not fixed by encoding (trailing space/dot, control chars, reserved names)
|
||||
validate_file_name(&encoded).with_context(|| {
|
||||
format!("name '{}' (encoded from '{}') is not legal to write to the file system", encoded, new_inst.name)
|
||||
})?;
|
||||
encoded
|
||||
} else {
|
||||
validate_file_name(&new_inst.name).with_context(|| {
|
||||
format!("name '{}' is not legal to write to the file system", new_inst.name)
|
||||
})?;
|
||||
new_inst.name.clone()
|
||||
};
|
||||
Cow::Owned(format!("{name}.{extension}"))
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -409,6 +409,12 @@ pub struct SyncbackRules {
|
|||
/// generally a better UX.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
create_ignore_dir_paths: Option<bool>,
|
||||
/// Whether to encode Windows-invalid characters in file names during
|
||||
/// syncback. Characters like `<`, `>`, `:`, `"`, `/`, `\`, `|`, `?`, `*`
|
||||
/// will be encoded as `%LT%`, `%GT%`, `%COLON%`, etc.
|
||||
/// Defaults to `false`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
encode_windows_invalid_chars: Option<bool>,
|
||||
}
|
||||
|
||||
impl SyncbackRules {
|
||||
|
|
@ -432,6 +438,13 @@ impl SyncbackRules {
|
|||
|
||||
Ok(globs)
|
||||
}
|
||||
|
||||
/// Returns whether Windows-invalid characters should be encoded in file
|
||||
/// names during syncback. Defaults to `false`.
|
||||
#[inline]
|
||||
pub fn encode_windows_invalid_chars(&self) -> bool {
|
||||
self.encode_windows_invalid_chars.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_path(globs: &Option<Vec<Glob>>, base_path: &Path, path: &Path) -> bool {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,13 @@ impl<'sync> SyncbackSnapshot<'sync> {
|
|||
middleware: None,
|
||||
};
|
||||
let middleware = get_best_middleware(&snapshot);
|
||||
let name = name_for_inst(middleware, snapshot.new_inst(), snapshot.old_inst())?;
|
||||
let encode_invalid_chars = self.encode_windows_invalid_chars();
|
||||
let name = name_for_inst(
|
||||
middleware,
|
||||
snapshot.new_inst(),
|
||||
snapshot.old_inst(),
|
||||
encode_invalid_chars,
|
||||
)?;
|
||||
snapshot.path = self.path.join(name.as_ref());
|
||||
|
||||
Ok(snapshot)
|
||||
|
|
@ -70,7 +76,13 @@ impl<'sync> SyncbackSnapshot<'sync> {
|
|||
middleware: None,
|
||||
};
|
||||
let middleware = get_best_middleware(&snapshot);
|
||||
let name = name_for_inst(middleware, snapshot.new_inst(), snapshot.old_inst())?;
|
||||
let encode_invalid_chars = self.encode_windows_invalid_chars();
|
||||
let name = name_for_inst(
|
||||
middleware,
|
||||
snapshot.new_inst(),
|
||||
snapshot.old_inst(),
|
||||
encode_invalid_chars,
|
||||
)?;
|
||||
snapshot.path = base_path.join(name.as_ref());
|
||||
|
||||
Ok(snapshot)
|
||||
|
|
@ -224,6 +236,34 @@ impl<'sync> SyncbackSnapshot<'sync> {
|
|||
.map(|classes| classes.iter().any(|c| c == class_name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Checks if an instance should be ignored based on ignoreTrees rules.
|
||||
/// Takes a Ref to check against the new tree's instance path.
|
||||
#[inline]
|
||||
pub fn should_ignore_tree(&self, referent: Ref) -> bool {
|
||||
if let Some(ignore_trees) = self.ignore_tree() {
|
||||
let path = inst_path(self.new_tree(), referent);
|
||||
for ignored in ignore_trees {
|
||||
if path.starts_with(ignored.as_str()) {
|
||||
log::debug!("Ignoring {path} because it matches ignoreTrees entry: {ignored}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns whether Windows-invalid characters should be encoded in file
|
||||
/// names during syncback.
|
||||
#[inline]
|
||||
pub fn encode_windows_invalid_chars(&self) -> bool {
|
||||
self.data
|
||||
.project
|
||||
.syncback_rules
|
||||
.as_ref()
|
||||
.map(|rules| rules.encode_windows_invalid_chars())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter_out_property(inst: &Instance, prop_name: &str) -> bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue