.. _omnigraph_versioning_usd:

OmniGraph USD Versioning
########################

This type of versioning involves changes to the structure or content of the USD backing for OmniGraph. It should
happen rarely. Two examples of changes of this type are the withdrawal of support for the global implicit graph, and
the move from using plain prims to back the OmniGraph elements to using schema-based prims.

In both cases the ABI remains unchanged, only the contents of the USD backing changed.

This deprecation follows a three-step process to give users ample opportunity to modify any code they need to in order
to support the new version that follows the standard :ref:`omnigraph_deprecation_approach`.

.. hint::

    Using the deprecation process ensures that each step only involves a minor version bump to the extension as
    existing code will continue to work. In the final phase of removal of the original behavior a major version
    bump may be required as existing scripts may not function without modification.


Step 1 - Introduce A Deprecation Setting
****************************************
For anything but the most trivial change there is always the possibility of existing code relying on the old way of
doing things so the first step is to introduce a deprecation setting using the instructions in
:ref:`omnigraph_versioning_settings`.

Step 2 - Add In Automatic File Migration
****************************************
Changes to the file format require a bump of the file format version, which can be found in the C++ file
`omni.graph.core/plugins/Graph.cpp` in a line that looks like this:

.. code-block:: cpp

    FileFormatVersion s_currentFileFormatVersion = { 1, 4 };

The first number is the major version, the second is the minor version, following the
:ref:`omnigraph_semantic_versioning` guidelines. A major version bump is reserved for any changes that are incapable
of having an automatic upgrade performed - e.g. adding mandatory metadata that identifies the time the file was created.

Next step is to introduce some code that will take the USD structure in the previous file formats, going as far back as
is reasonable, and modify it to conform to the desired new structure. Any USD-based modifications can be made at this
point so it is quite flexible.

One good way of doing this is to register a callback on a file format version update in the extension startup code,
remembering to unregister it when the extension shuts down.

.. literalinclude:: ../../../../../source/extensions/omni.graph/python/_impl/extension.py
   :language: python
   :start-after: begin-file-format-update
   :end-before: end-file-format-update

The callback should be placed somewhere that indicates it is on a deprecation path. For the **useSchemaPrims**
deprecation, for example, the deprecation code was added to a special directory `omni.graph/python/_impl/v1_5_0/` that
contains code deprecated after version 1.5.0 of that extension. The callback code should check the version of the
file being read and check it against the version that requires deprecation.

Once you've found that the file format is one that would require conversion then issue a deprecation warning, and if
the setting is configured to the new path then perform the conversion.

.. code-block:: python
    :emphasize-lines: 15,21

    def cb_for_my_deprecation(
        old_version: Optional[og.FileFormatVersion],
        new_version: Optional[og.FileFormatVersion],
        graph: Optional[og.Graph]
    ):

        if old_version is not None and\
            (old_version.majorVersion > VERSION_BEFORE_MY_CHANGE.majorVersion or\
                (old_version.majorVersion == VERSION_BEFORE_MY_CHANGE.majorVersion and\
                    old_version.minorVersion > VERSION_BEFORE_MY_CHANGE.minorVersion)):
            # No conversion needed, the file format is updated
            return

        # If the setting to automatically migrate is not on then there is nothing to do here
        carb.log_warn(f"Old format {old_version} automatically migrating to {new_version}")

        # If the setting to automatically migrate is not on then there is nothing to do here
        if not og.Settings().(og.Settings.MY_SETTING_NAME):
            return

        update_the_scene()


Step 3 - Enable The New Code Path By Default
********************************************
Once the deprecation time has been reached then modify the default value of the setting in
`omni.graph.core/plugins/OmniGraphSettings.cpp` and announce that the deprecation is happening.

Step 4 - Remove The Old Code Path
*********************************
In the rare case where full removal is required then you can remove the support code for the old code path.
- Delete the deprecation setting
- Delete all code paths that only execute when the setting is configured to use the deprecated code path
- Change the file format conversion callback to issue and error and fail
- Bump the major version of the file format to indicate older ones are no longer compatible


USD Version Effects On Python Scripting
***************************************

The automatic file migration provides a flexible upgrade path to making old files use the new way of doing things,
however there may still be incompatibilities lurking in the Python files. Simple examples include scripts that
assume the existence of deprecated prim types or attributes, or files containing script nodes that do the same.

The only way to handle these is to ensure that you have good test coverage so that when the default value of the
setting is reversed the test will fail and can be fixed.
