From afd41e743505844cee83d50b7b718e3b42523653 Mon Sep 17 00:00:00 2001 From: Jacek Rzeniewicz Date: Fri, 30 Jun 2023 16:32:16 +0100 Subject: [PATCH] fix: make directory removal work on node 12.9 For alpine releases we are stuck with node 12.9 where recursive directory removal does not work. We are reluctant to make major changes to release tooling as we work towards deprecating this tool, so this commit is adding a rimraf workaround which will catch cases when `fs.rmdirSync` throws. --- package.json | 2 ++ src/lib/delete-directory.ts | 12 ++++++++++++ src/lib/git-clone.ts | 3 ++- src/scripts/sync/clone-and-analyze.ts | 4 ++-- test/lib/delete-directory.test.ts | 15 +++++++++++++++ 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/lib/delete-directory.ts create mode 100644 test/lib/delete-directory.test.ts diff --git a/package.json b/package.json index 24569856..41a6c4a0 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "needle": "2.9.1", "p-map": "4.0.0", "parse-link-header": "2.0.0", + "rimraf": "3.0.2", "simple-git": "3.16.0", "sleep-promise": "8.0.1", "snyk-request-manager": "1.8.0", @@ -70,6 +71,7 @@ "@types/needle": "2.0.4", "@types/node": "14.14.45", "@types/parse-link-header": "1.0.0", + "@types/rimraf": "3.0.2", "@types/split": "1.0.0", "@typescript-eslint/eslint-plugin": "4.28.1", "@typescript-eslint/parser": "4.28.1", diff --git a/src/lib/delete-directory.ts b/src/lib/delete-directory.ts new file mode 100644 index 00000000..18d2def6 --- /dev/null +++ b/src/lib/delete-directory.ts @@ -0,0 +1,12 @@ +import * as rmrf from 'rimraf'; +import * as fs from 'fs'; + +export async function deleteDirectory(dir: string): Promise { + try { + fs.rmdirSync(dir, { recursive: true, maxRetries: 3 }); + } catch (e) { + await new Promise((resolve, reject) => + rmrf(dir, (err) => (err ? reject(err) : resolve())), + ); + } +} diff --git a/src/lib/git-clone.ts b/src/lib/git-clone.ts index b690ad11..2f2bef7d 100644 --- a/src/lib/git-clone.ts +++ b/src/lib/git-clone.ts @@ -8,6 +8,7 @@ import { simpleGit } from 'simple-git'; import * as github from '../lib/source-handlers/github'; import type { RepoMetaData } from './types'; import { SupportedIntegrationTypesUpdateProject } from './types'; +import { deleteDirectory } from './delete-directory'; const debug = debugLib('snyk:git-clone'); @@ -53,7 +54,7 @@ export async function gitClone( } catch (err: any) { debug(`Could not shallow clone the repo:\n ${err}`); if (fs.existsSync(repoClonePath)) { - fs.rmdirSync(repoClonePath, { recursive: true, maxRetries: 3 }); + await deleteDirectory(repoClonePath); } return { success: false, diff --git a/src/scripts/sync/clone-and-analyze.ts b/src/scripts/sync/clone-and-analyze.ts index 9cb0ffd2..264838d3 100644 --- a/src/scripts/sync/clone-and-analyze.ts +++ b/src/scripts/sync/clone-and-analyze.ts @@ -1,5 +1,4 @@ import * as debugLib from 'debug'; -import * as fs from 'fs'; import * as path from 'path'; import { defaultExclusionGlobs } from '../../common'; @@ -12,6 +11,7 @@ import type { SyncTargetsConfig, } from '../../lib/types'; import { generateProjectDiffActions } from './generate-projects-diff-actions'; +import { deleteDirectory } from '../../lib/delete-directory'; const debug = debugLib('snyk:clone-and-analyze'); @@ -63,7 +63,7 @@ export async function cloneAndAnalyze( ); try { - fs.rmdirSync(repoPath, { recursive: true, maxRetries: 3 }); + await deleteDirectory(repoPath); } catch (error) { debug(`Failed to delete ${repoPath}. Error was ${error}.`); } diff --git a/test/lib/delete-directory.test.ts b/test/lib/delete-directory.test.ts new file mode 100644 index 00000000..bfb4e3fe --- /dev/null +++ b/test/lib/delete-directory.test.ts @@ -0,0 +1,15 @@ +import { promises as fs } from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { deleteDirectory } from '../../src/lib/delete-directory'; + +test('directory is deleted with contents', async () => { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'deletion-test-')); + await fs.writeFile(path.join(dir, 'root.txt'), ''); + + await deleteDirectory(dir); + + console.log(dir); + + await expect(fs.stat(dir)).rejects.toThrowError('no such file or directory'); +});