openscad icon indicating copy to clipboard operation
openscad copied to clipboard

Saving writes to a new file, not the one opened

Open Alex-Kent opened this issue 1 month ago • 6 comments

Describe the bug

When opening a script using the GUI and then saving it the text is saved to a new file [with the original file's name]. The save should be made to the original file.

To Reproduce

(Steps 1–3 and 7 performed from the command line.)

  1. Create a script: echo 'a=1;' > test_1.scad
  2. Create a hard-linked copy of it: ln test_1.scad test_2.scad
  3. Verify that both point to the same file: ls -1i test_1.scad test_2.scad The same number [inode] should be shown for both, e.g.:
6467257 test_1.scad
6467257 test_2.scad
  1. Open test_1.scad with OpenSCAD.
  2. Make changes to the script.
  3. Save the script.
  4. Check whether the script file was modified in-place: ls -1i test_1.scad test_2.scad
6467275 test_1.scad
6467257 test_2.scad

Observe that the script has been saved to a new file [the inode number has changed].

Expected behaviour

When saving to an existing file the text should be updated in-place, not written to a new file.

Additional notes

The same in-place write behaviour should occur whenever a file is written to by OpenSCAD (e.g. PNG export); I have not checked the current behaviour in these cases.

Unexpected behaviour [by OpenSCAD] could occur if a script is saved by the user whilst in the process of being evaluated by another OpenSCAD instance. The likelihood of this occurring is extremely low and the ramifications of such are probably minor; this is thus probably not a concern.

Environment and Version info:

  • OS: Ubuntu 22.04 LTS
  • System: Intel PC 64-bit
  • OpenSCAD Version 2025.11.30 (built from source)

Alex-Kent avatar Dec 01 '25 00:12 Alex-Kent

Write and rename-into-place is a standard mechanism; it means that a crash during write doesn't trash your file. (It also avoids writing a file that OpenSCAD is reading.)

It does mean that hard links get broken. IMO, c'est la vie, better that than any chance of losing the file.

jordanbrown0 avatar Dec 01 '25 01:12 jordanbrown0

Not a bug, save uses the Qt mechanism doing what @jordanbrown0 described:

https://github.com/openscad/openscad/blob/dc495e2f12255d9f4474441a232053cbb3a0e47d/src/gui/TabManager.cc#L604-L616

What's the argument for changing this behavior? Not trashing the existing file on save (e.g. on disk full) seems a strong argument for having this behavior for the manually edited text files.

t-paul avatar Dec 01 '25 11:12 t-paul

@bitbasher I found your note 😁. What's other way you have seen?

t-paul avatar Dec 01 '25 11:12 t-paul

What's the argument for changing this behavior?

One use case is for a library file that is used (via use or include) in multiple projects. Each project has a local copy of the library but a change (e.g. a bug fix) in one copy should be applied to all copies. With hard links and in-place saves this is the case.

With a soft link the linked-to file is the one that OpenSCAD modifies on save.¹ However, using soft links to a single library file has multiple downsides; a few examples:

  • Soft links are brittle, e.g.:
    • Moving the canonical (linked-to) copy to a new location breaks all the links.
    • With a relative link moving the link (the one in the project, not the linked-to file) to a new location will break the link unless the relative location is equivalent.
  • Projects are no longer self-contained; e.g. copying or archiving them² only copies the link, not the contents of the file it points to.

¹ e.g.:

  • echo 'a=1;' > 1.scad; ln -s 1.scad 2.scad
  • Edit 2.scad in OpenSCAD and save it
  • 1.scad has been modified (it's a new file, i.e. new inode) and the link is untouched.

² e.g. with cp -a or rsync -a --link-dest=…

Alex-Kent avatar Dec 01 '25 20:12 Alex-Kent

@bitbasher I found your note 😁. What's other way you have seen?

Saw that note as well and was similarly curious.

Alex-Kent avatar Dec 01 '25 20:12 Alex-Kent

FWIW, one common way to handle this is to copy the file to a backup (e.g. filename.scad.bck) and then, if the backup was successful, perform an in-place write to the original file. Optionally the backup file could be removed if the save is successful (to prevent inadvertently overwriting the backup in this case, attempts to save could be blocked [with user notification] if the backup file is present).

Alex-Kent avatar Dec 01 '25 20:12 Alex-Kent

* Soft links are brittle, e.g.:
  
  * Moving the canonical (linked-to) copy to a new location breaks all the links.

Leave a forwarding link.

Also hard links cannot be used across mount points, so if you need to you can't with hard links.

  * With a relative link moving the link (the one in the project, not the linked-to file) to a new location will break the link unless the relative location is equivalent.

Don't use relative links.

* Projects are no longer self-contained; e.g. copying or archiving them² only copies the link, not the contents of the file it points to.

Use --copy-links with rsync.

Hard links have just as many downsides as symbolic links. IMO this proposal is worse than the existing behaviour for the benefit of an approach which is worse than one which works now.

coryrc avatar Dec 14 '25 19:12 coryrc

Don't use relative links.

There are times to use relative links, and times to use absolute links. Getting either wrong will hurt you.

jordanbrown0 avatar Dec 14 '25 20:12 jordanbrown0