oputil fb rm|remove|del|delete functionality

This commit is contained in:
Bryan Ashby 2017-09-23 23:03:21 -06:00
parent b0260049ba
commit 1ad5b125f5
3 changed files with 178 additions and 62 deletions

View File

@ -11,6 +11,7 @@ const async = require('async');
const _ = require('lodash'); const _ = require('lodash');
const paths = require('path'); const paths = require('path');
const fse = require('fs-extra'); const fse = require('fs-extra');
const { unlink } = require('graceful-fs');
const FILE_TABLE_MEMBERS = [ const FILE_TABLE_MEMBERS = [
'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag', 'file_id', 'area_tag', 'file_sha256', 'file_name', 'storage_tag',
@ -541,6 +542,40 @@ module.exports = class FileEntry {
}); });
} }
static removeEntry(srcFileEntry, options, cb) {
if(!_.isFunction(cb) && _.isFunction(options)) {
cb = options;
options = {};
}
async.series(
[
function removeFromDatabase(callback) {
fileDb.run(
`DELETE FROM file
WHERE file_id = ?;`,
[ srcFileEntry.fileId ],
err => {
return callback(err);
}
);
},
function optionallyRemovePhysicalFile(callback) {
if(true !== options.removePhysFile) {
return callback(null);
}
unlink(srcFileEntry.filePath, err => {
return callback(err);
});
}
],
err => {
return cb(err);
}
);
}
static moveEntry(srcFileEntry, destAreaTag, destStorageTag, destFileName, cb) { static moveEntry(srcFileEntry, destAreaTag, destStorageTag, destFileName, cb) {
if(!cb && _.isFunction(destFileName)) { if(!cb && _.isFunction(destFileName)) {
cb = destFileName; cb = destFileName;
@ -550,7 +585,6 @@ module.exports = class FileEntry {
const srcPath = srcFileEntry.filePath; const srcPath = srcFileEntry.filePath;
const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag); const dstDir = FileEntry.getAreaStorageDirectoryByTag(destStorageTag);
if(!dstDir) { if(!dstDir) {
return cb(Errors.Invalid('Invalid storage tag')); return cb(Errors.Invalid('Invalid storage tag'));
} }

View File

@ -438,52 +438,17 @@ function scanFileAreas() {
); );
} }
function moveFiles() { function expandFileTargets(targets, cb) {
// let entries = [];
// oputil fb move SRC [SRC2 ...] DST
//
// SRC: FILENAME_WC|FILE_ID|SHA|AREA_TAG[@STORAGE_TAG]
// DST: AREA_TAG[@STORAGE_TAG]
//
if(argv._.length < 4) {
return printUsageAndSetExitCode(getHelpFor('FileBase'), ExitCodes.ERROR);
}
const moveArgs = argv._.slice(2); // Each entry may be PATH|FILE_ID|SHA|AREA_TAG[@STORAGE_TAG]
let src = getAreaAndStorage(moveArgs.slice(0, -1)); const FileEntry = require('../../core/file_entry.js');
let dst = getAreaAndStorage(moveArgs.slice(-1))[0];
let FileEntry;
async.waterfall( async.eachSeries(targets, (areaAndStorage, next) => {
[
function init(callback) {
return initConfigAndDatabases( err => {
if(!err) {
fileArea = require('../../core/file_base_area.js');
}
return callback(err);
});
},
function validateAndExpandSourceAndDest(callback) {
let srcEntries = [];
const areaInfo = fileArea.getFileAreaByTag(dst.areaTag);
if(areaInfo) {
dst.areaInfo = areaInfo;
} else {
return callback(Errors.DoesNotExist('Invalid or unknown destination area'));
}
// Each SRC may be PATH|FILE_ID|SHA|AREA_TAG[@STORAGE_TAG]
FileEntry = require('../../core/file_entry.js');
async.eachSeries(src, (areaAndStorage, next) => {
const areaInfo = fileArea.getFileAreaByTag(areaAndStorage.areaTag); const areaInfo = fileArea.getFileAreaByTag(areaAndStorage.areaTag);
if(areaInfo) { if(areaInfo) {
// AREA_TAG[@STORAGE_TAG] - all files in area@tag // AREA_TAG[@STORAGE_TAG] - all files in area@tag
src.areaInfo = areaInfo;
const findFilter = { const findFilter = {
areaTag : areaAndStorage.areaTag, areaTag : areaAndStorage.areaTag,
}; };
@ -501,7 +466,7 @@ function moveFiles() {
const fileEntry = new FileEntry(); const fileEntry = new FileEntry();
fileEntry.load(fileId, err => { fileEntry.load(fileId, err => {
if(!err) { if(!err) {
srcEntries.push(fileEntry); entries.push(fileEntry);
} }
return nextFileId(err); return nextFileId(err);
}); });
@ -514,17 +479,59 @@ function moveFiles() {
} else { } else {
// FILENAME_WC|FILE_ID|SHA|PARTIAL_SHA // FILENAME_WC|FILE_ID|SHA|PARTIAL_SHA
// :TODO: FULL_PATH -> entries // :TODO: FULL_PATH -> entries
getFileEntries(areaAndStorage.pattern, (err, entries) => { getFileEntries(areaAndStorage.pattern, (err, fileEntries) => {
if(err) { if(err) {
return next(err); return next(err);
} }
srcEntries = srcEntries.concat(entries); entries = entries.concat(fileEntries);
return next(null); return next(null);
}); });
} }
}, },
err => { err => {
return cb(err, entries);
});
}
function moveFiles() {
//
// oputil fb move SRC [SRC2 ...] DST
//
// SRC: FILENAME_WC|FILE_ID|SHA|AREA_TAG[@STORAGE_TAG]
// DST: AREA_TAG[@STORAGE_TAG]
//
if(argv._.length < 4) {
return printUsageAndSetExitCode(getHelpFor('FileBase'), ExitCodes.ERROR);
}
const moveArgs = argv._.slice(2);
const src = getAreaAndStorage(moveArgs.slice(0, -1));
const dst = getAreaAndStorage(moveArgs.slice(-1))[0];
let FileEntry;
async.waterfall(
[
function init(callback) {
return initConfigAndDatabases( err => {
if(!err) {
fileArea = require('../../core/file_base_area.js');
}
return callback(err);
});
},
function validateAndExpandSourceAndDest(callback) {
const areaInfo = fileArea.getFileAreaByTag(dst.areaTag);
if(areaInfo) {
dst.areaInfo = areaInfo;
} else {
return callback(Errors.DoesNotExist('Invalid or unknown destination area'));
}
FileEntry = require('../../core/file_entry.js');
expandFileTargets(src, (err, srcEntries) => {
return callback(err, srcEntries); return callback(err, srcEntries);
}); });
}, },
@ -555,13 +562,80 @@ function moveFiles() {
return callback(err); return callback(err);
}); });
} }
] ],
err => {
if(err) {
process.exitCode = ExitCodes.ERROR;
console.error(err.message);
}
}
); );
} }
function removeFiles() { function removeFiles() {
// //
// REMOVE FILENAME_WC|SHA|FILE_ID [SHA|FILE_ID ...] // oputil fb rm|remove|del|delete SRC [SRC2 ...]
//
// SRC: FILENAME_WC|FILE_ID|SHA|AREA_TAG[@STORAGE_TAG]
//
// AREA_TAG[@STORAGE_TAG] remove all entries matching
// supplied area/storage tags
//
// --phys-file removes backing physical file(s)
//
if(argv._.length < 3) {
return printUsageAndSetExitCode(getHelpFor('FileBase'), ExitCodes.ERROR);
}
const removePhysFile = argv['phys-file'];
const src = getAreaAndStorage(argv._.slice(2));
async.waterfall(
[
function init(callback) {
return initConfigAndDatabases( err => {
if(!err) {
fileArea = require('../../core/file_base_area.js');
}
return callback(err);
});
},
function expandSources(callback) {
expandFileTargets(src, (err, srcEntries) => {
return callback(err, srcEntries);
});
},
function removeEntries(srcEntries, callback) {
const FileEntry = require('../../core/file_entry.js');
const extraOutput = removePhysFile ? ' (including physical file)' : '';
async.eachSeries(srcEntries, (entry, nextEntry) => {
process.stdout.write(`Removing ${entry.filePath}${extraOutput}... `);
FileEntry.removeEntry(entry, { removePhysFile }, err => {
if(err) {
console.info(`Failed: ${err.message}`);
} else {
console.info('Done');
}
return nextEntry(err);
});
}, err => {
return callback(err);
});
}
],
err => {
if(err) {
process.exitCode = ExitCodes.ERROR;
console.error(err.message);
}
}
);
} }
function handleFileBaseCommand() { function handleFileBaseCommand() {
@ -582,7 +656,13 @@ function handleFileBaseCommand() {
return ({ return ({
info : displayFileAreaInfo, info : displayFileAreaInfo,
scan : scanFileAreas, scan : scanFileAreas,
mv : moveFiles,
move : moveFiles, move : moveFiles,
rm : removeFiles,
remove : removeFiles, remove : removeFiles,
del : removeFiles,
delete : removeFiles,
}[action] || errUsage)(); }[action] || errUsage)();
} }

View File

@ -45,7 +45,7 @@ import-areas args:
--type TYPE specifies area import type. valid options are "bbs" and "na" --type TYPE specifies area import type. valid options are "bbs" and "na"
`, `,
FileBase : FileBase :
`usage: oputil.js fb <action> [<args>] <AREA_TAG|SHA|FILE_ID[@STORAGE_TAG] ...> [<args>] `usage: oputil.js fb <action> [<args>]
actions: actions:
scan AREA_TAG[@STORAGE_TAG] scan specified area scan AREA_TAG[@STORAGE_TAG] scan specified area
@ -53,14 +53,16 @@ actions:
info AREA_TAG|SHA|FILE_ID display information about areas and/or files info AREA_TAG|SHA|FILE_ID display information about areas and/or files
SHA may be a full or partial SHA-256 SHA may be a full or partial SHA-256
move SRC [SRC...]] DST move entry(s) from SRC to DST mv SRC [SRC...] DST move entry(s) from SRC to DST
* SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG] SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
* DST: AREA_TAG[@STORAGE_TAG] DST: AREA_TAG[@STORAGE_TAG]
remove SHA|FILE_ID removes a entry from the system rm SRC [SRC...] remove entry(s) from the system matching SRC
SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
scan args: scan args:
--tags TAG1,TAG2,... specify tag(s) to assign to discovered entries --tags TAG1,TAG2,... specify tag(s) to assign to discovered entries
--desc-file [PATH] prefer file descriptions from DESCRIPT.ION file over --desc-file [PATH] prefer file descriptions from DESCRIPT.ION file over
other sources such as FILE_ID.DIZ. other sources such as FILE_ID.DIZ.
if PATH is specified, use DESCRIPT.ION at PATH instead if PATH is specified, use DESCRIPT.ION at PATH instead
@ -71,7 +73,7 @@ info args:
--show-desc display short description, if any --show-desc display short description, if any
remove args: remove args:
--delete also remove underlying physical file --phys-file also remove underlying physical file
`, `,
FileOpsInfo : FileOpsInfo :
` `