Compare commits

...

2 Commits

Author SHA1 Message Date
85bb5ec3f2 Merge branch 'feature/init-name-resolution' 2026-02-25 17:30:27 +01:00
14bbdaf560 fix: handle dotted names and .lua extension in meta path + name check
Two bugs:

1. Meta stem fallback used raw instance name (unslugged), so names with
   forbidden chars like '/' would create bogus directory components in
   the meta path. Fix: fallback now slugifies + init-prefixes, matching
   name_for_inst.

2. AdjacentMetadata name check used split('.').next() to extract the
   filesystem stem, breaking dotted names like "Name.new" (stem became
   "Name", mismatched the instance name, wrote an unnecessary name
   property). Fix: check the conditions that cause name_for_inst to
   diverge (invalid chars or init-prefix) directly instead of comparing
   path stems.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:30:21 +01:00
4 changed files with 45 additions and 18 deletions

View File

@@ -117,7 +117,19 @@ pub fn syncback_csv<'sync>(
.and_then(|s| s.strip_suffix(ext.as_str()))
.map(str::to_owned)
})
.unwrap_or_else(|| new_inst.name.clone());
.unwrap_or_else(|| {
let name = &new_inst.name;
let base = if crate::syncback::validate_file_name(name).is_err() {
crate::syncback::slugify_name(name)
} else {
name.clone()
};
if base.to_lowercase() == "init" {
format!("_{base}")
} else {
base
}
});
fs_snapshot.add_file(
parent.join(format!("{meta_stem}.meta.json")),
serde_json::to_vec_pretty(&meta).context("cannot serialize metadata")?,

View File

@@ -166,7 +166,19 @@ pub fn syncback_lua<'sync>(
.and_then(|s| s.strip_suffix(ext.as_str()))
.map(str::to_owned)
})
.unwrap_or_else(|| snapshot.new_inst().name.clone());
.unwrap_or_else(|| {
let name = &snapshot.new_inst().name;
let base = if crate::syncback::validate_file_name(name).is_err() {
crate::syncback::slugify_name(name)
} else {
name.clone()
};
if base.to_lowercase() == "init" {
format!("_{base}")
} else {
base
}
});
fs_snapshot.add_file(
parent_location.join(format!("{meta_stem}.meta.json")),
serde_json::to_vec_pretty(&meta).context("cannot serialize metadata")?,

View File

@@ -154,17 +154,12 @@ impl AdjacentMetadata {
.old_inst()
.and_then(|inst| inst.metadata().specified_name.clone())
.or_else(|| {
// Write name when the filesystem path doesn't match the
// instance name (invalid chars or init-prefix).
// Write name when name_for_inst would produce a different
// filesystem stem (slugification or init-prefix).
if snapshot.old_inst().is_none() {
let instance_name = &snapshot.new_inst().name;
let fs_stem = path
.file_name()
.and_then(|n| n.to_str())
.map(|s| s.split('.').next().unwrap_or(s))
.unwrap_or("");
if validate_file_name(instance_name).is_err()
|| fs_stem != instance_name.as_str()
|| instance_name.to_lowercase() == "init"
{
Some(instance_name.clone())
} else {
@@ -428,16 +423,12 @@ impl DirectoryMetadata {
.old_inst()
.and_then(|inst| inst.metadata().specified_name.clone())
.or_else(|| {
// Write name when the directory name doesn't match the
// instance name (invalid chars or init-prefix).
// Write name when name_for_inst would produce a different
// directory name (slugification or init-prefix).
if snapshot.old_inst().is_none() {
let instance_name = &snapshot.new_inst().name;
let fs_name = path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("");
if validate_file_name(instance_name).is_err()
|| fs_name != instance_name.as_str()
|| instance_name.to_lowercase() == "init"
{
Some(instance_name.clone())
} else {

View File

@@ -66,7 +66,19 @@ pub fn syncback_txt<'sync>(
.and_then(|s| s.strip_suffix(ext.as_str()))
.map(str::to_owned)
})
.unwrap_or_else(|| new_inst.name.clone());
.unwrap_or_else(|| {
let name = &new_inst.name;
let base = if crate::syncback::validate_file_name(name).is_err() {
crate::syncback::slugify_name(name)
} else {
name.clone()
};
if base.to_lowercase() == "init" {
format!("_{base}")
} else {
base
}
});
fs_snapshot.add_file(
parent.join(format!("{meta_stem}.meta.json")),
serde_json::to_vec_pretty(&meta).context("could not serialize metadata")?,