Relative vs Absolute File Paths in SMTK

There are several places where file paths are stored in SMTK core:

  • File and Directory Items in Attribute Resources
  • Resource Information stored in Links
  • Location of native model files for Model Resources

With the ongoing development work on supporting the concept of Projects (and the requirement that Projects should be relocatable), the question of how to properly deal with file paths and when to store the information using absolute vs relative paths needs to be addressed.

Let the I/O Handle It

Its seems that when loaded in core, the simplest thing to do for Resources is to have the locations for Resources that are in-core to be in absolute format since I’m not sure what the benefits are in supporting relative paths for in-core resources and (In fact I can think of one major problem if the path was relative which is how to save the Resource with a relative path without having the directory path needed to write it.

We could simply let the I/O operations do the conversion since they could be given a directory path (for example the path of a Project), to use in determining if the Resource path should be relative or not. So the location of Resources could be saved in relative format but when read into the system the location information would be converted into absolute.

If FileSystem Items needed to be store using relative paths, this could be tricky. I can see how I can do this in the XML format since there is a single class doing the work. I’m not sure how the JSON code could do this since there doesn’t seem to be an easy way to do this.

Comments?

@tj.corona, @johnt, @dcthomp , @jacob.vaverka - would be interested in your take on this.

I like the idea of letting the I/O handle it. That way, we require the support of both relative and absolute paths at the lowest level of SMTK.

Projects could certainly establish their own convention, though. For example, we could differentiate between resources & files that are imported into a project and those that are merely referenced by the files by using relative and absolute paths, respectively.

I think we should continue using absolute paths for resources and, where practical, relative paths for native files linked to resources. (At least I think that’s how SMTK currently works.)

Because manually moving resources can introduce lots of unforeseen consequences, I don’t think we should support that (i.e., read operations should fail) except, perhaps as an advanced option (caveat emptor).

Instead, maybe we should first focus on providing 2 operations to bundle and unbundle projects, respectively, in a way that they can be ported to different machines and/or filesystem locations

This topic also brings to mind the future requirement to support a resource stored at multiple locations, but we might want to defer that discussion for now.

I also like the idea of letting the I/O operations handle things. However, I think the I/O operations should follow these simple rules to use relative paths wherever possible:

  • if a resource being written has a parent resource (i.e., a project):
    • if the resource’s location is a relative path or the parent resource’s containing directory also contains the resource being written, a relative path should be used and it should be relative to the parent resource;
    • otherwise, an absolute path should be used (the one in the resource’s location string).
  • else if a resource has no parent resource:
    • if the resource’s location is a relative path, it should be written relative to the current working directory (smtk::common::Paths::currentDirectory());
    • otherwise, the absolute location should be used.

Similar rules could (and should) be used for non-SMTK files referenced by SMTK resources. That doesn’t seem too onerous and will make sharing projects much simpler.

I was thinking of something simpler that doesn’t require resources having parent resources (at least for this particular issue :slight_smile:.

Lets focus on 5 things :

  1. the reading/writing of Resource Links
  2. the reading/writing of FileSystem Items information
  3. the reading/writing of Native Representations of Resources (naming Meshes and Geometric Models)
  4. Import Operations
  5. Project Package Operation

Resource Links I/O

I completely forgot that all external Resource related information in a Resource is stored in the Resource Links. How about we add a parameter to the Resource’s write operation to indicate the following options:

  • auto - if the path of to a linked Resource is a superset of the path to the Resource being written the write the path to the linked resource in relative form else use the absolute form.
  • absolute - force all paths to linked Resources to be written out in absolute form

Note that I did not include a force relative option - not sure which use cases would want it.

Example

Assume we have a Project with links to 2 Resources (/a/b/c/R1 and a/proj/R2). Lets assume that the project is going to be written out to a/proj/proj.smtk. If we use the auto option then inside project.smtk file we should see in the Links Section (of the project’s attribute resource section):
a/b/c/R1 and ./R2.

FileSystem Items and Paths to Native Representations I/O

We could provide the same options here as in the Resource Links if that makes sense.

Import Operations

Should provide an option to indicate if the Native Representation should be “linked” or “embedded”. If embedded then the file is copied, else it will be referenced using an absolute path.

Project Package Operation

This operation will convert all linked resources to be embedded resources.

Does this make sense?

Since resources that are not projects are not directories unto themselves, we need (a) somewhere to preserve the user’s decision (if you allow relative paths in Resource::location(), that is sufficient but if these paths are always absolute then embed/link must be stored somewhere) and (b) a counterpart in export operations that uses this decision (link vs embed) to write a relative or absolute path. Note that when a resource “save as…” operation calls an export operation, it also needs to reference this decision.

The other corner case is when we have an import operation but no matching export (say, because we don’t support modifying the data in the file). In that case, “save as…” operations must copy embedded non-SMTK files (but not linked ones).