From 45e889b4b399bce6696e636276c5ffe1ddce5450 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 7 Aug 2023 15:08:26 +0100 Subject: [PATCH] Install check-disk-space Node package --- node_modules/.package-lock.json | 8 + node_modules/check-disk-space/LICENSE | 21 ++ node_modules/check-disk-space/README.md | 53 +++++ .../dist/check-disk-space.cjs | 210 ++++++++++++++++++ .../dist/check-disk-space.d.ts | 53 +++++ .../dist/check-disk-space.mjs | 203 +++++++++++++++++ node_modules/check-disk-space/package.json | 83 +++++++ package-lock.json | 9 + package.json | 1 + 9 files changed, 641 insertions(+) create mode 100644 node_modules/check-disk-space/LICENSE create mode 100644 node_modules/check-disk-space/README.md create mode 100644 node_modules/check-disk-space/dist/check-disk-space.cjs create mode 100644 node_modules/check-disk-space/dist/check-disk-space.d.ts create mode 100644 node_modules/check-disk-space/dist/check-disk-space.mjs create mode 100644 node_modules/check-disk-space/package.json diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index aa1e87b30..79af0ee6c 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1751,6 +1751,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-disk-space": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz", + "integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==", + "engines": { + "node": ">=16" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", diff --git a/node_modules/check-disk-space/LICENSE b/node_modules/check-disk-space/LICENSE new file mode 100644 index 000000000..80d73b158 --- /dev/null +++ b/node_modules/check-disk-space/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-2019 Alexandre Demode + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/check-disk-space/README.md b/node_modules/check-disk-space/README.md new file mode 100644 index 000000000..b4520d83d --- /dev/null +++ b/node_modules/check-disk-space/README.md @@ -0,0 +1,53 @@ +# Check disk space + +[![Continue Integration](https://img.shields.io/github/workflow/status/Alex-D/check-disk-space/Continuous%20Integration?style=for-the-badge)](https://github.com/Alex-D/check-disk-space/actions/workflows/ci.yml) +[![check-disk-space on npm](https://img.shields.io/npm/v/check-disk-space?style=for-the-badge)](https://www.npmjs.com/package/check-disk-space) +[![License MIT](https://img.shields.io/github/license/Alex-D/check-disk-space.svg?style=for-the-badge)](LICENSE) + + +## Introduction + +Light multi-platform disk space checker without third party for Node.js. + +- Works on Linux, macOS and Windows +- Take care of mounting points on unix-like systems +- No dependencies +- TypeScript support + + +## Install + +`npm install check-disk-space` + + +## Usage + +```js +// ES +import checkDiskSpace from 'check-disk-space' + +// CommonJS +const checkDiskSpace = require('check-disk-space').default + +// On Windows +checkDiskSpace('C:/blabla/bla').then((diskSpace) => { + console.log(diskSpace) + // { + // diskPath: 'C:', + // free: 12345678, + // size: 98756432 + // } + // Note: `free` and `size` are in bytes +}) + +// On Linux or macOS +checkDiskSpace('/mnt/mygames').then((diskSpace) => { + console.log(diskSpace) + // { + // diskPath: '/', + // free: 12345678, + // size: 98756432 + // } + // Note: `free` and `size` are in bytes +}) +``` diff --git a/node_modules/check-disk-space/dist/check-disk-space.cjs b/node_modules/check-disk-space/dist/check-disk-space.cjs new file mode 100644 index 000000000..52ce60daf --- /dev/null +++ b/node_modules/check-disk-space/dist/check-disk-space.cjs @@ -0,0 +1,210 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var node_child_process = require('node:child_process'); +var promises = require('node:fs/promises'); +var node_os = require('node:os'); +var node_path = require('node:path'); +var node_process = require('node:process'); +var node_util = require('node:util'); + +class InvalidPathError extends Error { + constructor(message) { + super(message); + this.name = 'InvalidPathError'; + // Set the prototype explicitly. + Object.setPrototypeOf(this, InvalidPathError.prototype); + } +} + +class NoMatchError extends Error { + constructor(message) { + super(message); + this.name = 'NoMatchError'; + // Set the prototype explicitly. + Object.setPrototypeOf(this, NoMatchError.prototype); + } +} + +/** + * Tells if directory exists + * + * @param directoryPath - The file/folder path + * @param dependencies - Dependencies container + */ +async function isDirectoryExisting(directoryPath, dependencies) { + try { + await dependencies.fsAccess(directoryPath); + return Promise.resolve(true); + } + catch (error) { + return Promise.resolve(false); + } +} + +/** + * Get the first existing parent path + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +async function getFirstExistingParentPath(directoryPath, dependencies) { + let parentDirectoryPath = directoryPath; + let parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies); + while (!parentDirectoryFound) { + parentDirectoryPath = dependencies.pathNormalize(parentDirectoryPath + '/..'); + parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies); + } + return parentDirectoryPath; +} + +/** + * Tell if PowerShell 3 is available based on Windows version + * + * Note: 6.* is Windows 7 + * Note: PowerShell 3 is natively available since Windows 8 + * + * @param dependencies - Dependencies Injection Container + */ +async function hasPowerShell3(dependencies) { + const major = parseInt(dependencies.release.split('.')[0], 10); + if (major <= 6) { + return false; + } + try { + await dependencies.cpExecFile('where', ['powershell'], { windowsHide: true }); + return true; + } + catch (error) { + return false; + } +} + +/** + * Check disk space + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +function checkDiskSpace(directoryPath, dependencies = { + platform: node_process.platform, + release: node_os.release(), + fsAccess: promises.access, + pathNormalize: node_path.normalize, + pathSep: node_path.sep, + cpExecFile: node_util.promisify(node_child_process.execFile), +}) { + // Note: This function contains other functions in order + // to wrap them in a common context and make unit tests easier + /** + * Maps command output to a normalized object {diskPath, free, size} + * + * @param stdout - The command output + * @param filter - To filter drives (only used for win32) + * @param mapping - Map between column index and normalized column name + * @param coefficient - The size coefficient to get bytes instead of kB + */ + function mapOutput(stdout, filter, mapping, coefficient) { + const parsed = stdout + .split('\n') // Split lines + .map(line => line.trim()) // Trim all lines + .filter(line => line.length !== 0) // Remove empty lines + .slice(1) // Remove header + .map(line => line.split(/\s+(?=[\d/])/)); // Split on spaces to get columns + const filtered = parsed.filter(filter); + if (filtered.length === 0) { + throw new NoMatchError(); + } + const diskData = filtered[0]; + return { + diskPath: diskData[mapping.diskPath], + free: parseInt(diskData[mapping.free], 10) * coefficient, + size: parseInt(diskData[mapping.size], 10) * coefficient, + }; + } + /** + * Run the command and do common things between win32 and unix + * + * @param cmd - The command to execute + * @param filter - To filter drives (only used for win32) + * @param mapping - Map between column index and normalized column name + * @param coefficient - The size coefficient to get bytes instead of kB + */ + async function check(cmd, filter, mapping, coefficient = 1) { + const [file, ...args] = cmd; + /* istanbul ignore if */ + if (file === undefined) { + return Promise.reject(new Error('cmd must contain at least one item')); + } + try { + const { stdout } = await dependencies.cpExecFile(file, args, { windowsHide: true }); + return mapOutput(stdout, filter, mapping, coefficient); + } + catch (error) { + return Promise.reject(error); + } + } + /** + * Build the check call for win32 + * + * @param directoryPath - The file/folder path from where we want to know disk space + */ + async function checkWin32(directoryPath) { + if (directoryPath.charAt(1) !== ':') { + return Promise.reject(new InvalidPathError(`The following path is invalid (should be X:\\...): ${directoryPath}`)); + } + const powershellCmd = [ + 'powershell', + 'Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object Caption, FreeSpace, Size', + ]; + const wmicCmd = [ + 'wmic', + 'logicaldisk', + 'get', + 'size,freespace,caption', + ]; + const cmd = await hasPowerShell3(dependencies) ? powershellCmd : wmicCmd; + return check(cmd, driveData => { + // Only get the drive which match the path + const driveLetter = driveData[0]; + return directoryPath.toUpperCase().startsWith(driveLetter.toUpperCase()); + }, { + diskPath: 0, + free: 1, + size: 2, + }); + } + /** + * Build the check call for unix + * + * @param directoryPath - The file/folder path from where we want to know disk space + */ + async function checkUnix(directoryPath) { + if (!dependencies.pathNormalize(directoryPath).startsWith(dependencies.pathSep)) { + return Promise.reject(new InvalidPathError(`The following path is invalid (should start by ${dependencies.pathSep}): ${directoryPath}`)); + } + const pathToCheck = await getFirstExistingParentPath(directoryPath, dependencies); + return check([ + 'df', + '-Pk', + '--', + pathToCheck, + ], () => true, // We should only get one line, so we did not need to filter + { + diskPath: 5, + free: 3, + size: 1, + }, 1024); + } + // Call the right check depending on the OS + if (dependencies.platform === 'win32') { + return checkWin32(directoryPath); + } + return checkUnix(directoryPath); +} + +exports.InvalidPathError = InvalidPathError; +exports.NoMatchError = NoMatchError; +exports.default = checkDiskSpace; +exports.getFirstExistingParentPath = getFirstExistingParentPath; diff --git a/node_modules/check-disk-space/dist/check-disk-space.d.ts b/node_modules/check-disk-space/dist/check-disk-space.d.ts new file mode 100644 index 000000000..b054c684d --- /dev/null +++ b/node_modules/check-disk-space/dist/check-disk-space.d.ts @@ -0,0 +1,53 @@ +import { access } from 'node:fs/promises'; +import { normalize, sep } from 'node:path'; + +declare class InvalidPathError extends Error { + name: string; + constructor(message?: string); +} + +declare class NoMatchError extends Error { + name: string; + constructor(message?: string); +} + +type Dependencies = { + platform: NodeJS.Platform; + release: string; + fsAccess: typeof access; + pathNormalize: typeof normalize; + pathSep: typeof sep; + cpExecFile: (file: string, args: ReadonlyArray | undefined | null, options: { + windowsHide: true; + }) => Promise<{ + stdout: string; + stderr: string; + }>; +}; + +/** + * Get the first existing parent path + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +declare function getFirstExistingParentPath(directoryPath: string, dependencies: Dependencies): Promise; + +/** + * `free` and `size` are in bytes + */ +type DiskSpace = { + diskPath: string; + free: number; + size: number; +}; + +/** + * Check disk space + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +declare function checkDiskSpace(directoryPath: string, dependencies?: Dependencies): Promise; + +export { Dependencies, DiskSpace, InvalidPathError, NoMatchError, checkDiskSpace as default, getFirstExistingParentPath }; diff --git a/node_modules/check-disk-space/dist/check-disk-space.mjs b/node_modules/check-disk-space/dist/check-disk-space.mjs new file mode 100644 index 000000000..4af273174 --- /dev/null +++ b/node_modules/check-disk-space/dist/check-disk-space.mjs @@ -0,0 +1,203 @@ +import { execFile } from 'node:child_process'; +import { access } from 'node:fs/promises'; +import { release } from 'node:os'; +import { normalize, sep } from 'node:path'; +import { platform } from 'node:process'; +import { promisify } from 'node:util'; + +class InvalidPathError extends Error { + constructor(message) { + super(message); + this.name = 'InvalidPathError'; + // Set the prototype explicitly. + Object.setPrototypeOf(this, InvalidPathError.prototype); + } +} + +class NoMatchError extends Error { + constructor(message) { + super(message); + this.name = 'NoMatchError'; + // Set the prototype explicitly. + Object.setPrototypeOf(this, NoMatchError.prototype); + } +} + +/** + * Tells if directory exists + * + * @param directoryPath - The file/folder path + * @param dependencies - Dependencies container + */ +async function isDirectoryExisting(directoryPath, dependencies) { + try { + await dependencies.fsAccess(directoryPath); + return Promise.resolve(true); + } + catch (error) { + return Promise.resolve(false); + } +} + +/** + * Get the first existing parent path + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +async function getFirstExistingParentPath(directoryPath, dependencies) { + let parentDirectoryPath = directoryPath; + let parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies); + while (!parentDirectoryFound) { + parentDirectoryPath = dependencies.pathNormalize(parentDirectoryPath + '/..'); + parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies); + } + return parentDirectoryPath; +} + +/** + * Tell if PowerShell 3 is available based on Windows version + * + * Note: 6.* is Windows 7 + * Note: PowerShell 3 is natively available since Windows 8 + * + * @param dependencies - Dependencies Injection Container + */ +async function hasPowerShell3(dependencies) { + const major = parseInt(dependencies.release.split('.')[0], 10); + if (major <= 6) { + return false; + } + try { + await dependencies.cpExecFile('where', ['powershell'], { windowsHide: true }); + return true; + } + catch (error) { + return false; + } +} + +/** + * Check disk space + * + * @param directoryPath - The file/folder path from where we want to know disk space + * @param dependencies - Dependencies container + */ +function checkDiskSpace(directoryPath, dependencies = { + platform, + release: release(), + fsAccess: access, + pathNormalize: normalize, + pathSep: sep, + cpExecFile: promisify(execFile), +}) { + // Note: This function contains other functions in order + // to wrap them in a common context and make unit tests easier + /** + * Maps command output to a normalized object {diskPath, free, size} + * + * @param stdout - The command output + * @param filter - To filter drives (only used for win32) + * @param mapping - Map between column index and normalized column name + * @param coefficient - The size coefficient to get bytes instead of kB + */ + function mapOutput(stdout, filter, mapping, coefficient) { + const parsed = stdout + .split('\n') // Split lines + .map(line => line.trim()) // Trim all lines + .filter(line => line.length !== 0) // Remove empty lines + .slice(1) // Remove header + .map(line => line.split(/\s+(?=[\d/])/)); // Split on spaces to get columns + const filtered = parsed.filter(filter); + if (filtered.length === 0) { + throw new NoMatchError(); + } + const diskData = filtered[0]; + return { + diskPath: diskData[mapping.diskPath], + free: parseInt(diskData[mapping.free], 10) * coefficient, + size: parseInt(diskData[mapping.size], 10) * coefficient, + }; + } + /** + * Run the command and do common things between win32 and unix + * + * @param cmd - The command to execute + * @param filter - To filter drives (only used for win32) + * @param mapping - Map between column index and normalized column name + * @param coefficient - The size coefficient to get bytes instead of kB + */ + async function check(cmd, filter, mapping, coefficient = 1) { + const [file, ...args] = cmd; + /* istanbul ignore if */ + if (file === undefined) { + return Promise.reject(new Error('cmd must contain at least one item')); + } + try { + const { stdout } = await dependencies.cpExecFile(file, args, { windowsHide: true }); + return mapOutput(stdout, filter, mapping, coefficient); + } + catch (error) { + return Promise.reject(error); + } + } + /** + * Build the check call for win32 + * + * @param directoryPath - The file/folder path from where we want to know disk space + */ + async function checkWin32(directoryPath) { + if (directoryPath.charAt(1) !== ':') { + return Promise.reject(new InvalidPathError(`The following path is invalid (should be X:\\...): ${directoryPath}`)); + } + const powershellCmd = [ + 'powershell', + 'Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object Caption, FreeSpace, Size', + ]; + const wmicCmd = [ + 'wmic', + 'logicaldisk', + 'get', + 'size,freespace,caption', + ]; + const cmd = await hasPowerShell3(dependencies) ? powershellCmd : wmicCmd; + return check(cmd, driveData => { + // Only get the drive which match the path + const driveLetter = driveData[0]; + return directoryPath.toUpperCase().startsWith(driveLetter.toUpperCase()); + }, { + diskPath: 0, + free: 1, + size: 2, + }); + } + /** + * Build the check call for unix + * + * @param directoryPath - The file/folder path from where we want to know disk space + */ + async function checkUnix(directoryPath) { + if (!dependencies.pathNormalize(directoryPath).startsWith(dependencies.pathSep)) { + return Promise.reject(new InvalidPathError(`The following path is invalid (should start by ${dependencies.pathSep}): ${directoryPath}`)); + } + const pathToCheck = await getFirstExistingParentPath(directoryPath, dependencies); + return check([ + 'df', + '-Pk', + '--', + pathToCheck, + ], () => true, // We should only get one line, so we did not need to filter + { + diskPath: 5, + free: 3, + size: 1, + }, 1024); + } + // Call the right check depending on the OS + if (dependencies.platform === 'win32') { + return checkWin32(directoryPath); + } + return checkUnix(directoryPath); +} + +export { InvalidPathError, NoMatchError, checkDiskSpace as default, getFirstExistingParentPath }; diff --git a/node_modules/check-disk-space/package.json b/node_modules/check-disk-space/package.json new file mode 100644 index 000000000..aa698d8e8 --- /dev/null +++ b/node_modules/check-disk-space/package.json @@ -0,0 +1,83 @@ +{ + "name": "check-disk-space", + "version": "3.4.0", + "description": "Light multi-platform disk space checker without third party for Node.js", + "files": [ + "dist", + "README.md" + ], + "main": "./dist/check-disk-space.cjs", + "module": "./dist/check-disk-space.mjs", + "types": "./dist/check-disk-space.d.ts", + "exports": { + "import": "./dist/check-disk-space.mjs", + "require": "./dist/check-disk-space.cjs", + "types": "./dist/check-disk-space.d.ts" + }, + "scripts": { + "build:lib": "rollup --config", + "build:dts": "rollup --config rollup.dts.config.mjs", + "build": "npm-run-all build:lib build:dts", + "lint": "eslint . --cache", + "lint:fix": "eslint --fix .", + "typecheck": "tsc --noEmit", + "test": "npm-run-all test:coverage lint typecheck", + "test:unit": "NODE_ENV=test TS_NODE_PROJECT='tsconfig.test.json' ava", + "test:coverage": "nyc --reporter=lcov --reporter=text npm run test:unit --silent" + }, + "ava": { + "files": [ + "test/**", + "!test/__helpers__/**" + ], + "extensions": [ + "ts" + ], + "require": [ + "tsconfig-paths/register", + "ts-node/register", + "source-map-support/register" + ] + }, + "engines": { + "node": ">=16" + }, + "devDependencies": { + "@alex-d/eslint-config": "2.2.0", + "@istanbuljs/nyc-config-typescript": "1.0.2", + "@rollup/plugin-typescript": "11.1.1", + "@types/node": "16.11.7", + "@typescript-eslint/eslint-plugin": "5.59.6", + "@typescript-eslint/parser": "5.59.6", + "ava": "5.2.0", + "eslint": "8.41.0", + "eslint-plugin-ava": "14.0.0", + "eslint-plugin-import": "2.27.5", + "eslint-plugin-simple-import-sort": "10.0.0", + "npm-run-all": "4.1.5", + "nyc": "15.1.0", + "rollup": "3.22.0", + "rollup-plugin-dts": "5.3.0", + "source-map-support": "0.5.21", + "ts-node": "10.9.1", + "tsconfig-paths": "4.2.0", + "tslib": "2.5.2", + "typescript": "5.0.4" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Alex-D/check-disk-space.git" + }, + "keywords": [ + "disk", + "space", + "hdd", + "free" + ], + "author": "Alex-D (https://alex-d.fr)", + "license": "MIT", + "bugs": { + "url": "https://github.com/Alex-D/check-disk-space/issues" + }, + "homepage": "https://github.com/Alex-D/check-disk-space#readme" +} diff --git a/package-lock.json b/package-lock.json index 51ead36db..f99cc3078 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@schemastore/package": "0.0.10", "@types/uuid": "^9.0.2", "adm-zip": "^0.5.10", + "check-disk-space": "^3.4.0", "console-log-level": "^1.4.1", "del": "^6.1.1", "fast-deep-equal": "^3.1.3", @@ -1807,6 +1808,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-disk-space": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz", + "integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==", + "engines": { + "node": ">=16" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", diff --git a/package.json b/package.json index 5ce76a67b..d0e5fdfc3 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@schemastore/package": "0.0.10", "@types/uuid": "^9.0.2", "adm-zip": "^0.5.10", + "check-disk-space": "^3.4.0", "console-log-level": "^1.4.1", "del": "^6.1.1", "fast-deep-equal": "^3.1.3",