Implement incremental syncback mode to preserve existing file structure

- Added an `incremental` flag to the `SyncbackCommand` to allow for preserving existing file structure and middleware formats during syncback operations.
- Enhanced the `syncback_loop` function to differentiate between clean mode and incremental mode, ensuring orphaned files are removed only in clean mode.
- Updated logging to reflect the mode of operation during syncback.
- Introduced new tests to validate the behavior of clean mode versus incremental mode, ensuring proper handling of orphaned files and preservation of existing structures.
This commit is contained in:
Joe 2026-02-01 08:14:20 -06:00
parent 0e5e809894
commit 58399bb863
39 changed files with 652 additions and 119 deletions

View file

@ -2,4 +2,4 @@
source: tests/rojo_test/syncback_util.rs
expression: "String::from_utf8_lossy(&output.stdout)"
---
Removing C:/Users/Joe/AppData/Local/Temp/.tmpGY4Eb8/ignore_trees_removing/src

View file

@ -4,3 +4,5 @@ expression: "String::from_utf8_lossy(&output.stdout)"
---
Writing src/modules/ClientModule.luau
Writing src/modules/ServerModule.luau
Removing C:/Users/Joe/AppData/Local/Temp/.tmpLKd1Ar/nested_projects_weird/client-only.project.json5
Removing C:/Users/Joe/AppData/Local/Temp/.tmpLKd1Ar/nested_projects_weird/server-only.project.json5

View file

@ -3,5 +3,6 @@ source: tests/rojo_test/syncback_util.rs
expression: "String::from_utf8_lossy(&output.stdout)"
---
Writing src/ChildWithoutDuplicates/Child/.gitkeep
Writing src/ChildWithDuplicates
Writing src/ChildWithoutDuplicates
Writing src/ChildWithoutDuplicates/Child

View file

@ -4,4 +4,6 @@ expression: "String::from_utf8_lossy(&output.stdout)"
---
Writing src/Pointer_1.model.json5
Writing src/Pointer_2.model.json5
Writing src/Target.model.json5
Writing src/Target/init.meta.json5
Writing src/Target
Removing C:/Users/Joe/AppData/Local/Temp/.tmpA4y8vf/ref_properties_duplicate/src/Target.model.json5

View file

@ -7,19 +7,19 @@ expression: container.model.json5
{
attributes: {
Rojo_Id: "value_1",
Rojo_Ref_Value: "ReplicatedStorage/container/value_1",
Rojo_Ref_Value: "ReplicatedStorage/container/value_1"
},
className: "ObjectValue",
name: "value_1",
name: "value_1"
},
{
attributes: {
Rojo_Id: "value_1",
Rojo_Ref_Value: "ReplicatedStorage/container/value_2",
Rojo_Ref_Value: "ReplicatedStorage/container/value_2"
},
className: "ObjectValue",
name: "value_2",
},
name: "value_2"
}
],
className: "Folder",
className: "Folder"
}

View file

@ -5,6 +5,6 @@ expression: src/int_value.model.json5
{
className: "IntValue",
properties: {
Value: 1337,
},
Value: 1337
}
}

View file

@ -5,6 +5,6 @@ expression: src/Message.model.json5
{
className: "Message",
properties: {
Text: "This message should be written to the disk.",
},
Text: "This message should be written to the disk."
}
}

View file

@ -6,7 +6,7 @@ expression: src/dir_with_meta/init.meta.json5
className: "Configuration",
properties: {
Tags: [
"This tag on dir_with_meta",
],
},
"This tag on dir_with_meta"
]
}
}

View file

@ -5,6 +5,6 @@ expression: src/model_json.model.json5
{
className: "StringValue",
properties: {
Value: "This text is model_json",
},
Value: "This text is model_json"
}
}

View file

@ -10,8 +10,8 @@ expression: src/project_json.project.json5
Value: [
1337,
-1337,
1337,
],
},
},
1337
]
}
}
}

View file

@ -9,11 +9,11 @@ expression: nested.project.json5
BoolValue: {
$className: "BoolValue",
$properties: {
Value: true,
},
Value: true
}
},
StringValue: {
$path: "string_value.txt",
},
},
$path: "string_value.txt"
}
}
}

View file

@ -8,8 +8,8 @@ expression: property_mismatch.project.json5
$className: "BrickColorValue",
$properties: {
Value: {
BrickColor: 345,
},
},
},
BrickColor: 345
}
}
}
}

View file

@ -4,7 +4,7 @@ expression: src/pointer.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/target",
Rojo_Ref_Value: "ReplicatedStorage/target"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -4,7 +4,7 @@ expression: src/target.model.json5
---
{
attributes: {
Rojo_Id: "test referent id",
Rojo_Id: "test referent id"
},
className: "Folder",
className: "Folder"
}

View file

@ -4,7 +4,7 @@ expression: src/pointer.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/target",
Rojo_Ref_Value: "ReplicatedStorage/target"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -4,7 +4,7 @@ expression: src/Pointer_2.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/Target_2",
Rojo_Ref_Value: "ReplicatedStorage/Target_2"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -4,7 +4,7 @@ expression: src/Target_2.model.json5
---
{
attributes: {
Rojo_Id: "identical ID",
Rojo_Id: "identical ID"
},
className: "Folder",
className: "Folder"
}

View file

@ -4,7 +4,7 @@ expression: src/Pointer1.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/Target1",
Rojo_Ref_Value: "ReplicatedStorage/Target1"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -4,7 +4,7 @@ expression: src/Pointer2.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/Target2",
Rojo_Ref_Value: "ReplicatedStorage/Target2"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -4,7 +4,7 @@ expression: src/Pointer3.model.json5
---
{
attributes: {
Rojo_Ref_Value: "ReplicatedStorage/Target3",
Rojo_Ref_Value: "ReplicatedStorage/Target3"
},
className: "ObjectValue",
className: "ObjectValue"
}

View file

@ -9,8 +9,8 @@ expression: default.project.json5
project_node: {
$className: "BoolValue",
$properties: {
Value: true,
},
},
},
Value: true
}
}
}
}

View file

@ -5,6 +5,6 @@ expression: src/model_json.model.json5
{
className: "StringValue",
properties: {
Value: "This should be a .model.json file",
},
Value: "This should be a .model.json file"
}
}

View file

@ -8,13 +8,13 @@ expression: default.project.json5
tree: {
$className: "Folder",
src: {
$path: "src",
$path: "src"
},
trigger_reserialization: {
$className: "BoolValue",
$properties: {
Value: true,
},
},
},
Value: true
}
}
}
}

View file

@ -3,8 +3,7 @@ source: tests/tests/syncback.rs
expression: src/adjacent.meta.json5
---
{
$schema: "rojo/adjacent-meta",
attributes: {
trigger_reserialization: true,
},
trigger_reserialization: true
}
}

View file

@ -3,8 +3,7 @@ source: tests/tests/syncback.rs
expression: src/init/init.meta.json5
---
{
$schema: "rojo/init-meta",
attributes: {
trigger_reserialization: true,
},
trigger_reserialization: true
}
}

View file

@ -3,6 +3,5 @@ source: tests/tests/syncback.rs
expression: src/model.model.json5
---
{
$schema: "rojo/model.json",
className: "BoolValue",
className: "BoolValue"
}

View file

@ -9,14 +9,14 @@ expression: default.project.json5
inside_project_file: {
$className: "StringValue",
$properties: {
Value: "imgettingverytiredofwritingthesetests2",
},
Value: "imgettingverytiredofwritingthesetests2"
}
},
on_file_system: {
$attributes: {
imgettingverytiredofwritingthesetests: "person299 was ahead of his time",
imgettingverytiredofwritingthesetests: "person299 was ahead of his time"
},
$path: "string_value.txt",
},
},
$path: "string_value.txt"
}
}
}

View file

@ -5,14 +5,14 @@ expression: default.project.json5
{
name: "unscriptable_properties",
syncbackRules: {
syncUnscriptable: true,
syncUnscriptable: true
},
tree: {
$className: "BinaryStringValue",
$properties: {
Value: {
BinaryString: "Rojo/is/cool",
},
},
},
BinaryString: "Rojo/is/cool"
}
}
}
}