diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts index e02fd6d4f47..7c77530b81f 100644 --- a/editors/code/src/net.ts +++ b/editors/code/src/net.ts @@ -2,8 +2,6 @@ import fetch from "node-fetch"; import * as vscode from "vscode"; import * as stream from "stream"; import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; import * as util from "util"; import { log, assert } from "./util"; @@ -68,32 +66,31 @@ interface DownloadOpts { } export async function download(opts: DownloadOpts) { - // Put the artifact into a temporary folder to prevent partially downloaded files when user kills vscode - await withTempDir(async tempDir => { - const tempFile = path.join(tempDir, path.basename(opts.dest)); + // Put artifact into a temporary file (in the same dir for simplicity) + // to prevent partially downloaded files when user kills vscode + const tempFile = `${opts.dest}.tmp`; - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - cancellable: false, - title: opts.progressTitle - }, - async (progress, _cancellationToken) => { - let lastPercentage = 0; - await downloadFile(opts.url, tempFile, opts.mode, (readBytes, totalBytes) => { - const newPercentage = (readBytes / totalBytes) * 100; - progress.report({ - message: newPercentage.toFixed(0) + "%", - increment: newPercentage - lastPercentage - }); - - lastPercentage = newPercentage; + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: opts.progressTitle + }, + async (progress, _cancellationToken) => { + let lastPercentage = 0; + await downloadFile(opts.url, tempFile, opts.mode, (readBytes, totalBytes) => { + const newPercentage = (readBytes / totalBytes) * 100; + progress.report({ + message: newPercentage.toFixed(0) + "%", + increment: newPercentage - lastPercentage }); - } - ); - await moveFile(tempFile, opts.dest); - }); + lastPercentage = newPercentage; + }); + } + ); + + await fs.promises.rename(tempFile, opts.dest); } /** @@ -137,34 +134,3 @@ async function downloadFile( // https://github.com/rust-analyzer/rust-analyzer/issues/3167 }); } - -async function withTempDir(scope: (tempDirPath: string) => Promise) { - // Based on the great article: https://advancedweb.hu/secure-tempfiles-in-nodejs-without-dependencies/ - - // `.realpath()` should handle the cases where os.tmpdir() contains symlinks - const osTempDir = await fs.promises.realpath(os.tmpdir()); - - const tempDir = await fs.promises.mkdtemp(path.join(osTempDir, "rust-analyzer")); - - try { - return await scope(tempDir); - } finally { - // We are good citizens :D - void fs.promises.rmdir(tempDir, { recursive: true }).catch(log.error); - } -}; - -async function moveFile(src: fs.PathLike, dest: fs.PathLike) { - try { - await fs.promises.rename(src, dest); - } catch (err) { - if (err.code === 'EXDEV') { - // We are probably moving the file across partitions/devices - await fs.promises.copyFile(src, dest); - await fs.promises.unlink(src); - } else { - log.error(`Failed to rename the file ${src} -> ${dest}`, err); - throw err; - } - } -}