-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement property migration #268
Conversation
I'd like to give this more time and attention, but I have a lot going on right now. I feel like this code can be improved, but any PR is a good start for now, right? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beyond needing a quick update to not update our workflows because of PR #270, looks good to me. My request to log is the only serious one; in-lining format arguments or not isn't really important but we have the ability so we may as well.
Some(_) => { | ||
let (migration, property) = migrated_to.unwrap(); | ||
if !instance.builder.has_property(property.as_ref()) { | ||
match perform_migration(*migration, &value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
match perform_migration(*migration, &value) { | |
log::trace!("Attempting migrate property {canonical_name} to {property}"); | |
match perform_migration(*migration, &value) { |
If we're going to log when one fails, it makes sense for us to log when one starts as well.
log::warn!( | ||
"Failed to migrate property {} to {} because: {}", | ||
canonical_name, | ||
property, | ||
e.to_string() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log::warn!( | |
"Failed to migrate property {} to {} because: {}", | |
canonical_name, | |
property, | |
e.to_string() | |
); | |
log::warn!( | |
"Failed to migrate property {canonical_name} to {property} because: {}", | |
e.to_string() | |
); |
@@ -17,7 +17,7 @@ jobs: | |||
strategy: | |||
fail-fast: false | |||
matrix: | |||
rust_version: [stable, "1.63.0"] | |||
rust_version: [stable, "1.65.0"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rust_version: [stable, "1.65.0"] | |
rust_version: [stable] |
@@ -16,7 +16,7 @@ jobs: | |||
|
|||
strategy: | |||
matrix: | |||
rust_version: ["1.64.0"] | |||
rust_version: ["1.65.0"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rust_version: ["1.65.0"] | |
rust_version: [stable] |
...I should have thought about this beforehand but I just merged #249 which changes the format of patches a bit and swaps us over to using a polished version of Beyond having a better UX, we now no longer need to add properties to the database, only modify their serialization. That meshes well with migrations and should hopefully make it reasonable to have those migrations live as patches. |
## Roblox added a new property, but it's a migration from an existing property, and the existing property no longer loads | ||
Sometimes Roblox migrates an existing property whose type is too constrained to a new property with a more flexible type. | ||
|
||
Without special handling, this can cause problems for binary files because when old and new models are mixed together, the binary serializer must add the new property to the old models. Without special instruction, it'll just add the default value. This can result in weird behavior like old text UI all having the Arial font, because the default value of a new property took priority. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when old and new models are mixed together
What do you mean by "mixing" models?
## Roblox added a new property, but it's a migration from an existing property, and the existing property no longer loads | ||
Sometimes Roblox migrates an existing property whose type is too constrained to a new property with a more flexible type. | ||
|
||
Without special handling, this can cause problems for binary files because when old and new models are mixed together, the binary serializer must add the new property to the old models. Without special instruction, it'll just add the default value. This can result in weird behavior like old text UI all having the Arial font, because the default value of a new property took priority. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the binary serializer must add
Is this talking about rbx_binary
or saving from Studio?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, migrations swap out the old property for the new one in deserialization. It doesn't actual migrate the model file, it will still have the old property. I think this would be useful information to include.
Based on PR #268 Co-authored-by: Shae A <shae@uplift.games>
Work on this has been superseded by PR #283! Sorry that we ended up bungling this, I'll try to be more mindful of how the order things get merged in the future. |
Based on PR rojo-rbx#268 Co-authored-by: Shae A <shae@uplift.games>
This is a fixed version of #253 because its git history was cursed and I didn't want to force push or anything else weird to fix it.
Preview
This PR allows us to specify migrations using the patches files and a Variant to Variant converter in the actual Rust code. This is better than having the Rust code do hard-coded checks against property names and such without being super complex to implement or think about. Writing new migrations this way is easy!
The patch files look like this:
I've chosen to have migrations not be performed if the target property already exists. This matches Roblox's behavior where new properties always take priority. I figure making priority work both ways would be complex, and since backwards priority isn't known behavior of any present-day properties, it's unnecessary complexity. There's room to expand this in the future if we need to.
Why do we need this?
Two new properties --
FontFace
andScreenInsets
-- are migrated from old properties. When both the old and new properties are present, Roblox always prefers the new properties.The Roblox binary format requires that all objects of the same class have the same properties present. When mixing old models and new models into the same file using Rojo or Remodel, old models get assigned defaults for the new properties, which then take priority over the old properties.
This has two clear affects that users are actively experiencing in "preview" builds of Rojo and Remodel:
rojo build
or Remodel scripts results in all old text UI having the Arial font.rojo build
or Remodel scripts results in all old ScreenGuis losing their IgnoreGuiInset value.The only work-around for users right now is to open their models in Roblox and re-save over them to get Roblox to do the migration. This is not a reasonable ask of a Rojo fully-managed project that may have hundreds of models.
As time goes on, more properties will get migrations like this and maintaining a fully-managed Rojo codebase will become an unreasonable task.
Implementing these migrations on the rbx-dom side is quite easy. If we don't do it, either someone else will add this feature themselves or people just won't do fully-managed Rojo due to the high risk of breakage.
Changes in this PR
Migrate
, where you specify the new property name to migrate to and the name of the migration.