delete-old-files
Version:
Delete files that were last updated too long time ago.
262 lines (229 loc) • 9.36 kB
JavaScript
var fs = require("fs");
var path = require("path");
var deffy = require("deffy");
/**
* deleteOldFiles
* Deletes the old files in the specified directories.
*
* @name deleteOldFiles
* @function
* @param {Object} options The options object containing:
*
* - `directoryPaths` (Array): An array of directory paths to scan for old files. Default is `[]`.
* - `age` (Number): The age in seconds that a file must be older than to be deleted. Default is `604800` (7 days).
* - `checkInterval` (Number): The interval in seconds to check for old files. Default is `86400` (1 day). Set to `0` to disable periodic checks.
* - `recursive` (Boolean): Whether to scan directories recursively. Default is `false`.
* - `exclude` (Array): An array of file names or regex patterns to exclude from deletion. Default is `[]`.
* - `include` (Array): An array of file names or regex patterns to include for deletion. If empty, all files are included unless excluded. Default is `[]`.
* - `verbose` (Boolean): Whether to log detailed information about the process. Default is `false`.
* - `dryRun` (Boolean): If `true`, files will not be deleted, but actions will be logged. Default is `false`.
* - `onError` (Function): A callback function that is called when an error occurs. Receives the error as an argument.
* - `onDelete` (Function): A callback function that is called when a file is deleted. Receives the file path as an argument.
*/
function deleteOldFiles() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
options = deffy(options, {});
options.directoryPaths = deffy(options.directoryPaths, []);
options.age = deffy(options.age, 86400 * 7); // 7 days
options.checkInterval = deffy(options.checkInterval, 86400); // seconds (1 day)
options.recursive = deffy(options.recursive, false);
options.exclude = deffy(options.exclude, []);
options.include = deffy(options.include, []);
options.verbose = deffy(options.verbose, false);
options.dryRun = deffy(options.dryRun, false);
if (typeof options.onError !== "function") {
options.onError = function () {};
}
if (typeof options.onDelete !== "function") {
options.onDelete = function () {};
}
if (!options.directoryPaths.length) {
return;
}
if (options.age < 0) {
throw new Error("The age option must be a positive number.");
}
var run = function run() {
try {
deleteOldFiles.run(options);
} catch (err) {
options.onError(err);
}
};
if (options.checkInterval > 0) {
setInterval(run, options.checkInterval * 1000);
}
run();
}
deleteOldFiles.matches = function (filePath) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$include = _ref.include,
include = _ref$include === undefined ? [] : _ref$include,
_ref$exclude = _ref.exclude,
exclude = _ref$exclude === undefined ? [] : _ref$exclude;
if (!include.length && !exclude.length) {
return true;
}
var included = !include.length;
var baseName = path.basename(filePath);
var matches = function matches(pattern) {
return pattern instanceof RegExp ? pattern.test(filePath) : pattern === baseName;
};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = include[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var pattern = _step.value;
if (matches(pattern)) {
included = true;
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (!included) {
return false;
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = exclude[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _pattern = _step2.value;
if (matches(_pattern)) {
return false;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return true;
};
deleteOldFiles.run = async function (options) {
var processDirectory = async function processDirectory(directoryPath) {
if (options.verbose) {
console.log("[delete-old-files] Processing directory: " + directoryPath);
}
var files = await fs.promises.readdir(directoryPath);
var now = Date.now();
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = files[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var file = _step3.value;
var filePath = path.join(directoryPath, file);
var stats = void 0;
try {
stats = await fs.promises.stat(filePath);
} catch (err) {
options.onError(err);
continue;
}
if (stats.isDirectory()) {
if (options.recursive) {
await processDirectory(filePath);
}
continue;
}
var fileAge = Math.floor((now - stats.mtimeMs) / 1000); // in seconds
var deleteFilters = {
age: fileAge > options.age,
matches: deleteOldFiles.matches(filePath, options)
};
var shouldDelete = deleteFilters.age && deleteFilters.matches;
if (shouldDelete) {
if (options.dryRun) {
if (options.verbose) {
console.log("[delete-old-files] (dry run) Would delete file: " + filePath + " (" + fileAge + "s > " + options.age + "s)");
}
} else {
try {
await fs.promises.unlink(filePath);
if (options.verbose) {
console.log("[delete-old-files] Deleted file: " + filePath + " (" + fileAge + "s > " + options.age + "s)");
}
options.onDelete(filePath);
} catch (err) {
options.onError(err);
}
}
} else {
if (options.verbose) {
console.log("[delete-old-files] Keeping file: " + filePath + " - " + (!deleteFilters.matches ? "not matched" : "age (" + fileAge + "s <= " + options.age + "s)"));
}
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
if (options.verbose) {
var finishedAt = new Date();
var diff = finishedAt - now;
console.log("[delete-old-files] Finished processing directory: " + directoryPath + " in " + diff + "ms");
}
};
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = options.directoryPaths[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var directoryPath = _step4.value;
try {
await processDirectory(directoryPath);
} catch (err) {
options.onError(err);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
};
module.exports = deleteOldFiles;
;