diff --git a/news/changelog-1.6.md b/news/changelog-1.6.md index cf8faec07f3..2f06dfc868e 100644 --- a/news/changelog-1.6.md +++ b/news/changelog-1.6.md @@ -91,6 +91,7 @@ All changes included in 1.6: ## Projects +- ([#7988](https://github.com/quarto-dev/quarto-cli/issues/7988)): Do not allow `lib-dir` to cause an accidental cleanup of the project directory when its value points to a parent of the project directory. - ([#10125](https://github.com/quarto-dev/quarto-cli/issues/10125)): Show path to the project when project YAML validation fails. - ([#10268](https://github.com/quarto-dev/quarto-cli/issues/10268)): `quarto create` supports opening project in Positron, in addition to VS Code and RStudio IDE. - ([#10285](https://github.com/quarto-dev/quarto-cli/issues/10285)): Include text from before the first chapter sections in search indices. In addition, include text of every element with `.quarto-include-in-search-index` class in search indices. diff --git a/src/command/render/cleanup.ts b/src/command/render/cleanup.ts index f7667345a0c..d2fdc1c8547 100644 --- a/src/command/render/cleanup.ts +++ b/src/command/render/cleanup.ts @@ -4,7 +4,7 @@ * Copyright (C) 2020-2022 Posit Software, PBC */ -import { existsSync } from "../../deno_ral/fs.ts"; +import { existsSync, safeRemoveDirSync } from "../../deno_ral/fs.ts"; import { dirname, extname, isAbsolute, join } from "../../deno_ral/path.ts"; import * as ld from "../../core/lodash.ts"; @@ -22,11 +22,13 @@ import { isHtmlFileOutput, isLatexOutput } from "../../config/format.ts"; import { kKeepMd, kKeepTex, kKeepTyp } from "../../config/constants.ts"; import { filesDirLibDir, filesDirMediabagDir } from "./render-paths.ts"; +import { ProjectContext } from "../../project/types.ts"; export function renderCleanup( input: string, output: string, format: Format, + project: ProjectContext, supporting?: string[], keepMd?: string, ) { @@ -90,7 +92,7 @@ export function renderCleanup( // clean supporting ld.uniq(supporting).forEach((path) => { if (existsSync(path)) { - safeRemoveSync(path, { recursive: true }); + safeRemoveDirSync(path, project.dir); } }); } diff --git a/src/command/render/latexmk/latex.ts b/src/command/render/latexmk/latex.ts index 77cb9ffdd33..13a248961d9 100644 --- a/src/command/render/latexmk/latex.ts +++ b/src/command/render/latexmk/latex.ts @@ -5,7 +5,7 @@ */ import { basename, join } from "../../../deno_ral/path.ts"; -import { existsSync } from "../../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../../deno_ral/fs.ts"; import { error, info } from "../../../deno_ral/log.ts"; import { PdfEngine } from "../../../config/types.ts"; @@ -67,7 +67,7 @@ export async function runPdfEngine( // Clean any log file or output from previous runs [log, output].forEach((file) => { if (existsSync(file)) { - Deno.removeSync(file); + safeRemoveSync(file); } }); @@ -141,7 +141,7 @@ export async function runIndexEngine( // Clean any log file from previous runs if (existsSync(log)) { - Deno.removeSync(log); + safeRemoveSync(log); } const result = await runLatexCommand( @@ -176,7 +176,7 @@ export async function runBibEngine( // Clean any log file from previous runs if (existsSync(log)) { - Deno.removeSync(log); + safeRemoveSync(log); } const result = await runLatexCommand( diff --git a/src/command/render/latexmk/pdf.ts b/src/command/render/latexmk/pdf.ts index 81fdd746972..bf501aa8215 100644 --- a/src/command/render/latexmk/pdf.ts +++ b/src/command/render/latexmk/pdf.ts @@ -5,7 +5,7 @@ */ import { dirname, join } from "../../../deno_ral/path.ts"; -import { existsSync } from "../../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../../deno_ral/fs.ts"; import { PdfEngine } from "../../../config/types.ts"; import { LatexmkOptions } from "./types.ts"; @@ -594,7 +594,7 @@ function cleanup(workingDir: string, stem: string) { auxFiles.forEach((auxFile) => { if (existsSync(auxFile)) { - Deno.removeSync(auxFile); + safeRemoveSync(auxFile); } }); } diff --git a/src/command/render/output-tex.ts b/src/command/render/output-tex.ts index ac09b70eb99..768e8051f9e 100644 --- a/src/command/render/output-tex.ts +++ b/src/command/render/output-tex.ts @@ -5,7 +5,7 @@ */ import { dirname, join, normalize, relative } from "../../deno_ral/path.ts"; -import { ensureDirSync } from "../../deno_ral/fs.ts"; +import { ensureDirSync, safeRemoveSync } from "../../deno_ral/fs.ts"; import { writeFileToStdout } from "../../core/console.ts"; import { dirAndStem, expandPath } from "../../core/path.ts"; @@ -78,14 +78,14 @@ export function texToPdfOutputRecipe( // keep tex if requested const compileTex = join(inputDir, output); if (!format.render[kKeepTex]) { - Deno.removeSync(compileTex); + safeRemoveSync(compileTex); } // copy (or write for stdout) compiled pdf to final output location if (finalOutput) { if (finalOutput === kStdOut) { writeFileToStdout(pdfOutput); - Deno.removeSync(pdfOutput); + safeRemoveSync(pdfOutput); } else { const outputPdf = expandPath(finalOutput); @@ -99,9 +99,10 @@ export function texToPdfOutputRecipe( // Clean the output directory if it is empty if (pdfOutputDir) { + console.log({ pdfOutputDir }); try { // Remove the outputDir if it is empty - Deno.removeSync(pdfOutputDir, { recursive: false }); + safeRemoveSync(pdfOutputDir, { recursive: false }); } catch { // This is ok, just means the directory wasn't empty } diff --git a/src/command/render/output-typst.ts b/src/command/render/output-typst.ts index f714e7b6fbf..83a5b3f9cac 100644 --- a/src/command/render/output-typst.ts +++ b/src/command/render/output-typst.ts @@ -5,7 +5,7 @@ */ import { dirname, join, normalize, relative } from "../../deno_ral/path.ts"; -import { ensureDirSync } from "../../deno_ral/fs.ts"; +import { ensureDirSync, safeRemoveSync } from "../../deno_ral/fs.ts"; import { kFontPaths, @@ -81,14 +81,14 @@ export function typstPdfOutputRecipe( // keep typ if requested if (!format.render[kKeepTyp]) { - Deno.removeSync(input); + safeRemoveSync(input); } // copy (or write for stdout) compiled pdf to final output location if (finalOutput) { if (finalOutput === kStdOut) { writeFileToStdout(pdfOutput); - Deno.removeSync(pdfOutput); + safeRemoveSync(pdfOutput); } else { const outputPdf = expandPath(finalOutput); diff --git a/src/command/render/output.ts b/src/command/render/output.ts index cf08086e6f1..9ae7e057e7a 100644 --- a/src/command/render/output.ts +++ b/src/command/render/output.ts @@ -15,7 +15,7 @@ import { } from "../../deno_ral/path.ts"; import { writeFileToStdout } from "../../core/console.ts"; -import { dirAndStem, expandPath } from "../../core/path.ts"; +import { dirAndStem, expandPath, safeRemoveSync } from "../../core/path.ts"; import { parse as parseYaml, partitionYamlFrontMatter, @@ -209,7 +209,7 @@ export function outputRecipe( recipe.isOutputTransient = true; completeActions.push(() => { writeFileToStdout(join(inputDir, recipe.output)); - Deno.removeSync(join(inputDir, recipe.output)); + safeRemoveSync(join(inputDir, recipe.output)); }); } else if (!isAbsolute(recipe.output)) { // relatve output file on the command line: make it relative to the input dir diff --git a/src/command/render/project.ts b/src/command/render/project.ts index 76fbbeb175d..6e50bcdd0d0 100644 --- a/src/command/render/project.ts +++ b/src/command/render/project.ts @@ -4,7 +4,14 @@ * Copyright (C) 2020-2022 Posit Software, PBC */ -import { ensureDirSync, existsSync, safeMoveSync } from "../../deno_ral/fs.ts"; +import { + ensureDirSync, + existsSync, + safeMoveSync, + safeRemoveDirSync, + safeRemoveSync, + UnsafeRemovalError, +} from "../../deno_ral/fs.ts"; import { dirname, isAbsolute, join, relative } from "../../deno_ral/path.ts"; import { info, warning } from "../../deno_ral/log.ts"; import { mergeProjectMetadata } from "../../config/metadata.ts"; @@ -481,7 +488,18 @@ export async function renderProject( return; } if (existsSync(targetDir)) { - Deno.removeSync(targetDir, { recursive: true }); + try { + safeRemoveDirSync(targetDir, context.dir); + } catch (e) { + if (e instanceof UnsafeRemovalError) { + warning( + `Refusing to remove directory ${targetDir} since it is not a subdirectory of the main project directory.`, + ); + warning( + `Quarto did not expect the path configuration being used in this project, and strange behavior may result.`, + ); + } + } } ensureDirSync(dirname(targetDir)); if (copy) { @@ -494,7 +512,7 @@ export async function renderProject( // because src and target are in different file systems. // In that case, try to recursively copy from src copyTo(srcDir, targetDir); - Deno.removeSync(srcDir, { recursive: true }); + safeRemoveDirSync(targetDir, context.dir); } } }; @@ -906,7 +924,7 @@ export async function renderProject( if (projectRenderConfig.options.forceClean) { const scratchDir = join(projDir, kQuartoScratch); if (existsSync(scratchDir)) { - Deno.removeSync(scratchDir, { recursive: true }); + safeRemoveSync(scratchDir, { recursive: true }); } } diff --git a/src/command/render/render.ts b/src/command/render/render.ts index 80986a16016..e8e0d70dcb3 100644 --- a/src/command/render/render.ts +++ b/src/command/render/render.ts @@ -377,6 +377,7 @@ export async function renderPandoc( context.target.input, finalOutput!, format, + file.context.project, cleanupSelfContained, executionEngineKeepMd(context), )); diff --git a/src/core/copy.ts b/src/core/copy.ts index a05636cddce..c2d5712910f 100644 --- a/src/core/copy.ts +++ b/src/core/copy.ts @@ -18,6 +18,7 @@ import { existsSync, getFileInfoType, isSubdir, + safeRemoveSync, walkSync, } from "../deno_ral/fs.ts"; @@ -146,7 +147,7 @@ function copyFileSync( // multiple users/owners in play). see this code for where this occurs: // https://github.com/denoland/deno/blob/1c05e41f37da022971f0090b2a92e6340d230055/runtime/ops/fs.rs#L914-L916 if (existsSync(dest)) { - Deno.removeSync(dest); + safeRemoveSync(dest); } Deno.copyFileSync(src, dest); @@ -196,7 +197,7 @@ function copySymlinkSync( ensureValidCopySync(src, dest, options); // remove dest if it exists if (existsSync(dest)) { - Deno.removeSync(dest); + safeRemoveSync(dest); } const originSrcFilePath = Deno.readLinkSync(src); const type = getFileInfoType(Deno.lstatSync(src)); diff --git a/src/core/deno/debug.ts b/src/core/deno/debug.ts index d5c68326cb4..01a94641175 100644 --- a/src/core/deno/debug.ts +++ b/src/core/deno/debug.ts @@ -122,6 +122,19 @@ export const getStackAsArray = ( col: m4[5] + (m4[1] ? 6 : 0), }; } + + // at Array.map () + const m5 = s.match( + /^.*at (.*)\(\)$/, + ); + if (m5) { + return { + pos: "", + name: `${m5[1]}`, + line: "", + col: "", + }; + } throw new Error(`Unexpected stack entry: ${s}`); }); diff --git a/src/core/deno/monkey-patch.ts b/src/core/deno/monkey-patch.ts index 5119e882c06..7f6fb6a8840 100644 --- a/src/core/deno/monkey-patch.ts +++ b/src/core/deno/monkey-patch.ts @@ -6,8 +6,9 @@ import { debug } from "../../deno_ral/log.ts"; import { normalizePath } from "../path.ts"; +import { getStack } from "./debug.ts"; -// Window UNC paths can be mishandled by realPathSync +// Windows UNC paths can be mishandled by realPathSync // (see https://github.com/quarto-dev/quarto-vscode/issues/67) // so we monkey-patch to implement the absolute path and normalize // parts of realPathSync (we aren't interested in the symlink diff --git a/src/core/run/lua.ts b/src/core/run/lua.ts index d9e797ed274..dfb9c801d04 100644 --- a/src/core/run/lua.ts +++ b/src/core/run/lua.ts @@ -7,7 +7,7 @@ import { info } from "../../deno_ral/log.ts"; import { dirname, extname } from "../../deno_ral/path.ts"; -import { normalizePath } from "../path.ts"; +import { normalizePath, safeRemoveSync } from "../path.ts"; import { isWindows } from "../platform.ts"; import { execProcess } from "../process.ts"; import { pandocBinaryPath, resourcePath } from "../resources.ts"; @@ -109,7 +109,7 @@ setmetatable(_G, meta) } finally { // remove temp script if (tempScript) { - Deno.removeSync(tempScript); + safeRemoveSync(tempScript); } } } diff --git a/src/core/windows.ts b/src/core/windows.ts index 8ed9c990c7f..38dde5acec3 100644 --- a/src/core/windows.ts +++ b/src/core/windows.ts @@ -3,7 +3,7 @@ * * Copyright (C) 2020-2022 Posit Software, PBC */ -import { existsSync } from "../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../deno_ral/fs.ts"; import { join } from "../deno_ral/path.ts"; import { quartoCacheDir } from "./appdirs.ts"; import { removeIfExists } from "./path.ts"; @@ -79,7 +79,7 @@ export async function cacheCodePage() { export function clearCodePageCache() { if (existsSync(tokenPath)) { - Deno.removeSync(tokenPath); + safeRemoveSync(tokenPath); } } diff --git a/src/deno_ral/fs.ts b/src/deno_ral/fs.ts index cf229454518..d408f1ad261 100644 --- a/src/deno_ral/fs.ts +++ b/src/deno_ral/fs.ts @@ -36,6 +36,7 @@ export function getFileInfoType(fileInfo: Deno.FileInfo): PathType | undefined { } // from https://jsr.io/@std/fs/1.0.3/_is_subdir.ts +// 2024-15-11: isSubDir("foo", "foo/bar") returns true, which gets src and dest exactly backwards?! /** * Checks whether `src` is a sub-directory of `dest`. * @@ -104,3 +105,22 @@ export function safeRemoveSync( } } } + +export class UnsafeRemovalError extends Error { + constructor(msg: string) { + super(msg); + } +} + +export function safeRemoveDirSync( + path: string, + boundary: string, +) { + // note the comment above about isSubdir getting src and dest backwards + if (path === boundary || isSubdir(path, boundary)) { + throw new UnsafeRemovalError( + `Refusing to remove directory ${path} that isn't a subdirectory of ${boundary}`, + ); + } + return safeRemoveSync(path, { recursive: true }); +} diff --git a/src/execute/julia.ts b/src/execute/julia.ts index f95ab3d2a6b..622fed63114 100644 --- a/src/execute/julia.ts +++ b/src/execute/julia.ts @@ -39,7 +39,7 @@ import { isInteractiveSession } from "../core/platform.ts"; import { runningInCI } from "../core/ci-info.ts"; import { sleep } from "../core/async.ts"; import { JupyterNotebook } from "../core/jupyter/types.ts"; -import { existsSync } from "../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../deno_ral/fs.ts"; import { encodeBase64 } from "encoding/base64"; import { executeResultEngineDependencies, @@ -468,7 +468,7 @@ async function getJuliaServerConnection( options, "Connecting to server failed, a transport file was reused so it might be stale. Delete transport file and retry.", ); - Deno.removeSync(juliaTransportFile()); + safeRemoveSync(juliaTransportFile()); return await getJuliaServerConnection(options); } else { error( diff --git a/src/execute/jupyter/jupyter-kernel.ts b/src/execute/jupyter/jupyter-kernel.ts index 71c89d4ef6f..d94c2c65794 100644 --- a/src/execute/jupyter/jupyter-kernel.ts +++ b/src/execute/jupyter/jupyter-kernel.ts @@ -4,7 +4,7 @@ * Copyright (C) 2020-2022 Posit Software, PBC */ -import { existsSync } from "../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../deno_ral/fs.ts"; import { join } from "../../deno_ral/path.ts"; import { error, info, warning } from "../../deno_ral/log.ts"; @@ -148,7 +148,7 @@ export async function executeKernelKeepalive( // in that case remove the connection file and re-throw the exception const transportFile = kernelTransportFile(options.target.input); if (existsSync(transportFile)) { - Deno.removeSync(transportFile); + safeRemoveSync(transportFile); } throw e; } finally { @@ -174,7 +174,7 @@ async function abortKernel(options: JupyterExecuteOptions) { } finally { const transportFile = kernelTransportFile(options.target.input); if (existsSync(transportFile)) { - Deno.removeSync(transportFile); + safeRemoveSync(transportFile); } conn.close(); } @@ -360,7 +360,7 @@ function readKernelTransportFile( "Error reading kernel transport file: " + e.toString() + "(removing file)", ); - Deno.removeSync(transportFile); + safeRemoveSync(transportFile); return null; } } else { @@ -408,7 +408,7 @@ async function connectToKernel( } catch { // remove the transport file if (existsSync(transportFile)) { - Deno.removeSync(transportFile); + safeRemoveSync(transportFile); } } } @@ -453,7 +453,7 @@ async function connectToKernel( return await denoConnectToKernel(kernelTransport); } catch (e) { // remove the transport file - Deno.removeSync(transportFile); + safeRemoveSync(transportFile); error("Error connecting to Jupyter kernel: " + e.toString()); return Promise.reject(); } diff --git a/src/execute/ojs/extract-resources.ts b/src/execute/ojs/extract-resources.ts index f56c674477e..95eb5a3de66 100644 --- a/src/execute/ojs/extract-resources.ts +++ b/src/execute/ojs/extract-resources.ts @@ -34,6 +34,7 @@ import { stripColor } from "../../core/lib/external/colors.ts"; import { lines } from "../../core/lib/text.ts"; import { InternalError } from "../../core/lib/error.ts"; import { kRenderServicesLifetime } from "../../config/constants.ts"; +import { safeRemoveSync } from "../../deno_ral/fs.ts"; // ResourceDescription filenames are always project-relative export interface ResourceDescription { @@ -571,7 +572,7 @@ export async function extractResourceDescriptionsFromOJSChunk( // more than once, so we could end up with more than one request // to delete it. Fail gracefully if so. try { - Deno.removeSync(res.filename); + safeRemoveSync(res.filename); } catch (e) { if (e.name !== "NotFound") { throw e; diff --git a/src/extension/install.ts b/src/extension/install.ts index 51784c96b42..fef12c6764c 100644 --- a/src/extension/install.ts +++ b/src/extension/install.ts @@ -4,7 +4,7 @@ * Copyright (C) 2020-2022 Posit Software, PBC */ -import { ensureDirSync, existsSync } from "../deno_ral/fs.ts"; +import { ensureDirSync, existsSync, safeRemoveSync } from "../deno_ral/fs.ts"; import { Confirm } from "cliffy/prompt/mod.ts"; import { Table } from "cliffy/table/mod.ts"; import { basename, dirname, join, relative } from "../deno_ral/path.ts"; @@ -587,7 +587,7 @@ export async function completeInstallation( // Move from the staging path to the install dir const installPath = join(installExtDir, extensionRelativeDir); if (existsSync(installPath)) { - Deno.removeSync(installPath, { recursive: true }); + safeRemoveSync(installPath, { recursive: true }); } // Ensure the parent directory exists @@ -596,7 +596,7 @@ export async function completeInstallation( }); } finally { // Clean up the staging directory - Deno.removeSync(stagingDir, { recursive: true }); + safeRemoveSync(stagingDir, { recursive: true }); } return Promise.resolve(); }); diff --git a/src/preview/preview-text.ts b/src/preview/preview-text.ts index 24bb0eeafc3..a0820e58f8f 100644 --- a/src/preview/preview-text.ts +++ b/src/preview/preview-text.ts @@ -19,6 +19,7 @@ import { pandocBinaryPath, textHighlightThemePath, } from "../core/resources.ts"; +import { safeRemoveSync } from "../deno_ral/fs.ts"; import { basename, extname, join } from "../deno_ral/path.ts"; @@ -254,6 +255,6 @@ async function gfmPreview(file: string, request: Request) { ); } } finally { - Deno.removeSync(workingDir, { recursive: true }); + safeRemoveSync(workingDir, { recursive: true }); } } diff --git a/src/project/project-shared.ts b/src/project/project-shared.ts index 13b28744a93..ec9bcfb619f 100644 --- a/src/project/project-shared.ts +++ b/src/project/project-shared.ts @@ -350,7 +350,7 @@ export async function directoryMetadataForInputFile( } const mdForFile = async ( - project: ProjectContext, + _project: ProjectContext, engine: ExecutionEngine | undefined, file: string, ): Promise => { diff --git a/src/project/serve/serve.ts b/src/project/serve/serve.ts index b2822e6f8b1..cca9218cf51 100644 --- a/src/project/serve/serve.ts +++ b/src/project/serve/serve.ts @@ -5,7 +5,7 @@ */ import { info, warning } from "../../deno_ral/log.ts"; -import { existsSync } from "../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../deno_ral/fs.ts"; import { basename, dirname, @@ -918,7 +918,7 @@ function acquirePreviewLock(project: ProjectContext) { function releasePreviewLock(project: ProjectContext) { try { - Deno.removeSync(previewLockFile(project)); + safeRemoveSync(previewLockFile(project)); } catch { // } diff --git a/src/project/types/book/book-render.ts b/src/project/types/book/book-render.ts index 87f3f593b21..b83c881dfc7 100644 --- a/src/project/types/book/book-render.ts +++ b/src/project/types/book/book-render.ts @@ -681,6 +681,7 @@ function cleanupExecutedFile( file.context.target.input, finalOutput, file.recipe.format, + file.context.project, file.executeResult.supporting, executionEngineKeepMd(file.context), ); diff --git a/src/project/types/manuscript/manuscript.ts b/src/project/types/manuscript/manuscript.ts index abf093bfcab..bab820b2f4c 100644 --- a/src/project/types/manuscript/manuscript.ts +++ b/src/project/types/manuscript/manuscript.ts @@ -107,7 +107,12 @@ import { isQmdFile } from "../../../execute/qmd.ts"; import * as ld from "../../../core/lodash.ts"; import { safeExistsSync } from "../../../core/path.ts"; -import { copySync, ensureDirSync, existsSync } from "../../../deno_ral/fs.ts"; +import { + copySync, + ensureDirSync, + existsSync, + safeRemoveSync, +} from "../../../deno_ral/fs.ts"; import { kTitleBlockStyle } from "../../../format/html/format-html-title.ts"; import { resolveProjectInputLinks } from "../website/website-utils.ts"; @@ -751,7 +756,7 @@ const createTexOutputBundle = ( texInputFile, texOutputFile, ); - Deno.removeSync(texInputFile); + safeRemoveSync(texInputFile); // Create the resulting bundle descriptor const texBundle: { manuscript: string; supporting: string[] } = { @@ -767,7 +772,7 @@ const createTexOutputBundle = ( const outPath = join(texDirAbs, relative(context.dir, supportingAbs)); ensureDirSync(dirname(outPath)); copySync(supportingAbs, outPath, { overwrite: true }); - Deno.removeSync(supportingAbs, { recursive: true }); + safeRemoveSync(supportingAbs, { recursive: true }); texBundle.supporting.push(outPath); } } diff --git a/src/project/types/website/listing/website-listing-feed.ts b/src/project/types/website/listing/website-listing-feed.ts index b23f144dd73..a22a945d6b5 100644 --- a/src/project/types/website/listing/website-listing-feed.ts +++ b/src/project/types/website/listing/website-listing-feed.ts @@ -40,7 +40,11 @@ import { renderedContentReader, RenderedContents, } from "./website-listing-shared.ts"; -import { dirAndStem, resolvePathGlobs } from "../../../../core/path.ts"; +import { + dirAndStem, + resolvePathGlobs, + safeRemoveSync, +} from "../../../../core/path.ts"; import { ProjectOutputFile } from "../../types.ts"; import { resolveInputTarget } from "../../../project-index.ts"; import { projectOutputDir } from "../../../project-shared.ts"; @@ -372,7 +376,7 @@ export function completeStagedFeeds( ); } finally { try { - Deno.removeSync(feedFile); + safeRemoveSync(feedFile); } catch { // Just ignore this and move on } diff --git a/src/project/types/website/listing/website-listing-index.ts b/src/project/types/website/listing/website-listing-index.ts index 0cb928f861c..0a6bb0cbcf8 100644 --- a/src/project/types/website/listing/website-listing-index.ts +++ b/src/project/types/website/listing/website-listing-index.ts @@ -5,7 +5,7 @@ */ import { join, relative } from "../../../../deno_ral/path.ts"; -import { existsSync } from "../../../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../../../deno_ral/fs.ts"; import { ProjectContext } from "../../../types.ts"; import { ListingDescriptor, ListingItem } from "./website-listing-shared.ts"; @@ -124,7 +124,7 @@ export function updateGlobalListingIndex( listingPaths.push(indexJson); } - Deno.removeSync(indexPath); + safeRemoveSync(indexPath); } } } diff --git a/src/project/types/website/listing/website-listing-project.ts b/src/project/types/website/listing/website-listing-project.ts index ae6b27b5485..b9dfa596e3d 100644 --- a/src/project/types/website/listing/website-listing-project.ts +++ b/src/project/types/website/listing/website-listing-project.ts @@ -4,7 +4,7 @@ * Copyright (C) 2020-2022 Posit Software, PBC */ -import { ensureDirSync } from "../../../../deno_ral/fs.ts"; +import { ensureDirSync, safeRemoveSync } from "../../../../deno_ral/fs.ts"; import { dirname, join } from "../../../../deno_ral/path.ts"; import { projectScratchPath } from "../../../project-scratch.ts"; @@ -66,7 +66,7 @@ export function clearListingProjectData(project: ProjectContext) { function clearListingMap(project: ProjectContext) { const file = projectListingMapFile(project.dir); try { - Deno.removeSync(file); + safeRemoveSync(file); } catch { // No op } diff --git a/src/tools/impl/tinytex.ts b/src/tools/impl/tinytex.ts index 464e04bd91f..926fce63bf1 100644 --- a/src/tools/impl/tinytex.ts +++ b/src/tools/impl/tinytex.ts @@ -5,7 +5,7 @@ */ import { debug, warning } from "../../deno_ral/log.ts"; -import { existsSync } from "../../deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../../deno_ral/fs.ts"; import { basename, join, relative } from "../../deno_ral/path.ts"; import { expandPath, which } from "../../core/path.ts"; @@ -226,7 +226,7 @@ async function install( } } - Deno.removeSync(from, { recursive: true }); + safeRemoveSync(from, { recursive: true }); // Note the version that we have installed noteInstalledVersion(pkgInfo.version); diff --git a/src/tools/tools.ts b/src/tools/tools.ts index fedc442b26e..94053a08a29 100644 --- a/src/tools/tools.ts +++ b/src/tools/tools.ts @@ -20,6 +20,7 @@ import { chromiumInstallable } from "./impl/chromium.ts"; import { downloadWithProgress } from "../core/download.ts"; import { Confirm } from "cliffy/prompt/mod.ts"; import { isWSL } from "../core/platform.ts"; +import { safeRemoveSync } from "../deno_ral/fs.ts"; // The tools that are available to install const kInstallableTools: { [key: string]: InstallableTool } = { @@ -152,7 +153,7 @@ export async function installTool(name: string, updatePath?: boolean) { } } finally { // Cleanup the working directory - Deno.removeSync(workingDir, { recursive: true }); + safeRemoveSync(workingDir, { recursive: true }); } } } else { @@ -184,7 +185,7 @@ export async function uninstallTool(name: string, updatePath?: boolean) { } catch (e) { logError(e); } finally { - Deno.removeSync(workingDir, { recursive: true }); + safeRemoveSync(workingDir, { recursive: true }); } } else { info( @@ -232,7 +233,7 @@ export async function updateTool(name: string) { } catch (e) { logError(e); } finally { - Deno.removeSync(workingDir, { recursive: true }); + safeRemoveSync(workingDir, { recursive: true }); } } else { info( diff --git a/tests/test.ts b/tests/test.ts index c346a0f2b60..f808d4fe14e 100644 --- a/tests/test.ts +++ b/tests/test.ts @@ -4,7 +4,7 @@ * Copyright (C) 2020-2022 Posit Software, PBC * */ -import { existsSync } from "../src/deno_ral/fs.ts"; +import { existsSync, safeRemoveSync } from "../src/deno_ral/fs.ts"; import { AssertionError, fail } from "testing/asserts"; import { warning } from "../src/deno_ral/log.ts"; import { initDenoDom } from "../src/core/deno-dom.ts"; @@ -301,7 +301,7 @@ export function test(test: TestDescriptor) { } fail(output.join("\n")); } finally { - Deno.removeSync(log); + safeRemoveSync(log); await cleanupLogOnce(); if (test.context.teardown) { await test.context.teardown();