diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index 8d26c24e..69485209 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -449,7 +449,7 @@ export default class Controller { continue; } - if (entry.name.toLowerCase().endsWith("tmp.zip")) { + if (entry.name.toLowerCase().endsWith(".tmp.zip")) { continue; } diff --git a/packages/create/create.js b/packages/create/create.js index 8fbc5eb7..33911308 100755 --- a/packages/create/create.js +++ b/packages/create/create.js @@ -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); } diff --git a/packages/host/src/patch.ts b/packages/host/src/patch.ts index c1f9c085..05497637 100644 --- a/packages/host/src/patch.ts +++ b/packages/host/src/patch.ts @@ -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 { diff --git a/packages/lib/src/file_ops.ts b/packages/lib/src/file_ops.ts index b6709da1..5cd44961 100644 --- a/packages/lib/src/file_ops.ts +++ b/packages/lib/src/file_ops.ts @@ -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); diff --git a/test/host/patch.js b/test/host/patch.js index 6cfbb40c..9998bccc 100644 --- a/test/host/patch.js +++ b/test/host/patch.js @@ -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"], ]; diff --git a/test/lib/file_ops.js b/test/lib/file_ops.js index ff203138..8d4dcc2f 100644 --- a/test/lib/file_ops.js +++ b/test/lib/file_ops.js @@ -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() {