Use .tmp before the file extension (#529)

When creating temporary files use the pattern `.tmp.ext` instead of
`.ext.tmp` to be consistent with Factorio which creates `.tmp.zip` files
during saving.

If patching fails this will leave a `.tmp.zip` file in the instance saves
directory which is ignored by the default save selector.

Resolves #486.
This commit is contained in:
Hornwitser authored and GitHub committed 2023-11-30 01:21:06 +01:00
1 parent faadf873fb
commit d5bcd34cdb
6 files changed
+28 -12

No files matched your search

+1 -1
View File
@@ -449,7 +449,7 @@ export default class Controller {
continue;
}
if (entry.name.toLowerCase().endsWith("tmp.zip")) {
if (entry.name.toLowerCase().endsWith(".tmp.zip")) {
continue;
}
+2 -1
View File
@@ -86,7 +86,8 @@ class InstallError extends Error { }
async function safeOutputFile(file, data, options={}) {
let temporary = `${file}.tmp`;
let { dir, name, ext } = path.parse(file);
let temporary = `${dir}${name}.tmp${ext}`;
await fs.outputFile(temporary, data, options);
await fs.rename(temporary, file);
}
+1 -1
View File
@@ -417,7 +417,7 @@ export async function patch(savePath: string, modules: SaveModule[]) {
root.file("clusterio.json", JSON.stringify(patchInfo, null, "\t"));
// Write back the save
let tempSavePath = `${savePath}.tmp`;
let tempSavePath = savePath.replace(/(\.zip)?$/, ".tmp.zip");
let stream = zip.generateNodeStream({ compression: "DEFLATE" });
let fd = await fs.open(tempSavePath, "w");
try {
+6 -5
View File
@@ -126,7 +126,8 @@ export async function getTempFile(prefix = "tmp.", suffix = "", tmpdir = "./") {
*
* Same as fs-extra.outputFile except the data is written to a temporary
* file that's renamed over the target file. The name of the temporary file
* is the same as the target file with the suffix `.tmp` added.
* is the same as the target file with the suffix `.tmp` added before the
* extension.
*
* If the operation fails it may leave behind the temporary file. This
* should not be too much of an issue as the next time the same file is
@@ -137,11 +138,11 @@ export async function getTempFile(prefix = "tmp.", suffix = "", tmpdir = "./") {
* @param options - see fs.writeFile, `flag` must not be set.
*/
export async function safeOutputFile(file: string, data: string | Buffer, options: fs.WriteFileOptions ={}) {
let directory = path.dirname(file);
if (!await fs.pathExists(directory)) {
await fs.mkdirs(directory);
let { dir, name, ext } = path.parse(file);
if (dir && !await fs.pathExists(dir)) {
await fs.mkdirs(dir);
}
let temporary = `${file}.tmp`;
let temporary = `${dir}${name}.tmp${ext}`;
let fd = await fs.open(temporary, "w");
try {
await fs.writeFile(fd, data, options);
+2 -2
View File
@@ -15,11 +15,11 @@ describe("host/patch", function() {
const mappings = [
["locale/en/foo.cfg", "locale/en/test-foo.cfg"],
["locale/en/foo.txt", "locale/en/test-foo.txt"],
["locale/en/foo.txt.tmp", "locale/en/test-foo.txt.tmp"],
["locale/en/foo.tmp.txt", "locale/en/test-foo.tmp.txt"],
["locale/en/foo", "locale/en/test-foo"],
["locale/en.cfg", "locale/en/test.cfg"],
["locale/en.txt", "locale/en/test.txt"],
["locale/en.txt.tmp", "locale/en/test.txt.tmp"],
["locale/en.tmp.txt", "locale/en/test.tmp.txt"],
["locale/en", "locale/en/test"],
["locale/en/bar/foo.cfg", "locale/en/test-bar/foo.cfg"],
];
+16 -2
View File
@@ -88,16 +88,30 @@ describe("lib/file_ops", function() {
it("should write new target file", async function() {
let target = path.join(baseDir, "safe", "simple.txt");
await lib.safeOutputFile(target, "a text file", "utf8");
assert(!await fs.pathExists(`${target}.tmp`), "temporary was left behind");
assert(!await fs.pathExists(target.replace(".txt", ".tmp.txt")), "temporary was left behind");
assert.equal(await fs.readFile(target, "utf8"), "a text file");
});
it("should overwrite existing target file", async function() {
let target = path.join(baseDir, "safe", "exists.txt");
await fs.outputFile(target, "previous", "utf8");
await lib.safeOutputFile(target, "current", "utf8");
assert(!await fs.pathExists(`${target}.tmp`), "temporary was left behind");
assert(!await fs.pathExists(target.replace(".txt", ".tmp.txt")), "temporary was left behind");
assert.equal(await fs.readFile(target, "utf8"), "current");
});
it("should handle creating file in current working directory", async function() {
let target = "temporary-file-made-to-test-cwd.txt";
try {
await lib.safeOutputFile(target, "a text file", "utf8");
} finally {
try {
await fs.unlink(target);
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
}
});
});
describe("checkFilename()", function() {