Skip to content

Add temporary directory helpers and a createDirectories write option - #3045

Open
ld-kerley wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
ld-kerley:format/temp-directory-and-write-create-directories
Open

Add temporary directory helpers and a createDirectories write option#3045
ld-kerley wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
ld-kerley:format/temp-directory-and-write-create-directories

Conversation

@ld-kerley

Copy link
Copy Markdown
Contributor

(This work is extracted and refined from #2739)

This adds a small set of file system utilities for creating and removing temporary directories, along with an option for writeToXmlFile() to create the directory hierarchy of its target file. Together these let tools and tests stage
generated documents in scratch locations without pre-creating the directory structure themselves, which currently requires each caller to reimplement platform-specific temporary directory logic.

The following specific changes are included:

  • Add FilePath::getSystemTemporaryDirectory(), returning the platform temporary directory. This is queried with GetTempPath on Windows, and with the TMPDIR, TMP, TEMP and TEMPDIR environment variables on POSIX,
    falling back to /tmp. The directory is not created, and its existence is not guaranteed.
  • Add FilePath::createTemporaryDirectory(), creating a uniquely named directory under a given parent and defaulting to the system temporary directory, and throwing an Exception if the directory cannot be created. POSIX platforms use mkdtemp(), which generates the name, creates the directory atomically, and restricts access to the owner. Windows has no equivalent, so candidate names are passed to CreateDirectory, which fails rather than succeeding when the path already exists; only a name collision is retried, and any other error is reported.
  • Add FilePath::removeDirectory(), removing a directory and optionally its contents, and returning whether the removal succeeded. A recursive removal classifies entries with lstat or the reparse point attribute, so that symbolic links within the directory are removed without deleting the contents of their targets.
  • Add an XmlWriteOptions::createDirectories flag, causing writeToXmlFile() to create the parent directory hierarchy of the target file if it does not already exist. The flag defaults to false, so the behavior of existing code is unchanged.

New cases in MaterialXTest cover the default and explicit parent directories, the uniqueness and owner-only permissions of each created directory, the reporting of a creation failure under a read-only parent, directory removal with and without recursion, the preservation of a symbolic link's target during a recursive removal, and the round-tripping of a document written into a newly created hierarchy. The permission, read-only parent and symbolic link cases are guarded to POSIX. I have run the full test suite on macOS; the Windows code paths are exercised only by CI.

Add three file system methods to FilePath:

- getSystemTemporaryDirectory() returns the platform temporary
  directory, queried with GetTempPath on Windows and the TMPDIR, TMP,
  TEMP and TEMPDIR environment variables on POSIX, falling back to /tmp.
- createTemporaryDirectory() creates a uniquely-named directory under a
  given parent, defaulting to the system temporary directory, and throws
  if it cannot be created.  POSIX platforms use mkdtemp(), which names
  and creates the directory atomically and restricts access to the
  owner.  Windows has no equivalent, so candidate names are passed to
  CreateDirectory, which fails rather than succeeding on an existing
  path, and only a collision is retried.
- removeDirectory() removes a directory, optionally recursively,
  classifying entries with lstat or the reparse point attribute so that
  symbolic links are removed without deleting their targets' contents.

Add an XmlWriteOptions::createDirectories flag, which causes
writeToXmlFile() to create the parent directory hierarchy of the target
file if it does not already exist.

Tests cover the default and explicit parent directories, the uniqueness
and owner-only permissions of each created directory, the reporting of a
creation failure, directory removal with and without recursion, and the
round-tripping of a document written to a newly created hierarchy.
@lgritz

lgritz commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Is there a reason why these aren't just implemented in terms of std::filesystem wherever possible? Are those inadequate in a way I have not previously appreciated?

@ld-kerley

Copy link
Copy Markdown
Contributor Author

@lgritz I was considering exactly that while putting this together - but MaterialX is used in a whole bunch of different places javascript bindings via emscripten, and I wasn't 100% sure that std::filesystem is supported in all the places.

Also hoping to land this fairly easily, as a precursor to some other more important work - so didn't want to rock the boat too much.

Given you also flagged what I was thinking I'll file an issue and we can come back to std::filesystem conversion as a separate piece of work. In my very cursory investigation with Claude, it did notice that std::filesystem calls throw exceptions that are more specific that std::exception, but the MaterialX pattern for exceptions is to inherit from that. So I wonder if moving to std::filesystem might invalidate some client code where its catching the MaterialXException class.

@lgritz

lgritz commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Don't let me derail you. In all honestly, I was thinking "gosh, I just minimally wrap std::filesystem for some of these... are there shortcomings I'm unaware of?"

I assume these are holdovers from the pre-C++17 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants