From 6717cd517932f10cd6f08f43683c948d0783ab03 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 18 Feb 2017 19:00:09 -0700 Subject: [PATCH] Add fb 'info' support to oputil --- core/file_base_area.js | 1 + core/file_entry.js | 29 +++++++ core/oputil/oputil_common.js | 2 +- core/oputil/oputil_file_base.js | 139 +++++++++++++++++++++++++++++++- core/oputil/oputil_help.js | 16 ++-- 5 files changed, 180 insertions(+), 7 deletions(-) diff --git a/core/file_base_area.js b/core/file_base_area.js index bce81fac..c2d83c22 100644 --- a/core/file_base_area.js +++ b/core/file_base_area.js @@ -23,6 +23,7 @@ const iconv = require('iconv-lite'); exports.isInternalArea = isInternalArea; exports.getAvailableFileAreas = getAvailableFileAreas; exports.getSortedAvailableFileAreas = getSortedAvailableFileAreas; +exports.getAreaStorageDirectoryByTag = getAreaStorageDirectoryByTag; exports.getAreaDefaultStorageDirectory = getAreaDefaultStorageDirectory; exports.getAreaStorageLocations = getAreaStorageLocations; exports.getDefaultFileAreaTag = getDefaultFileAreaTag; diff --git a/core/file_entry.js b/core/file_entry.js index f7836555..50faf360 100644 --- a/core/file_entry.js +++ b/core/file_entry.js @@ -289,8 +289,37 @@ module.exports = class FileEntry { } } + // :TODO: Use static get accessor: static getWellKnownMetaValues() { return Object.keys(FILE_WELL_KNOWN_META); } + static findFileBySha(sha, cb) { + // full or partial SHA-256 + fileDb.all( + `SELECT file_id + FROM file + WHERE file_sha256 LIKE "${sha}%" + LIMIT 2;`, // limit 2 such that we can find if there are dupes + (err, fileIdRows) => { + if(err) { + return cb(err); + } + + if(!fileIdRows || 0 === fileIdRows.length) { + return cb(Errors.DoesNotExist('No matches')); + } + + if(fileIdRows.length > 1) { + return cb(Errors.Invalid('SHA is ambiguous')); + } + + const fileEntry = new FileEntry(); + return fileEntry.load(fileIdRows[0].file_id, err => { + return cb(err, fileEntry); + }); + } + ); + } + static findFiles(filter, cb) { filter = filter || {}; diff --git a/core/oputil/oputil_common.js b/core/oputil/oputil_common.js index 3b99bf11..3bdb5ec0 100644 --- a/core/oputil/oputil_common.js +++ b/core/oputil/oputil_common.js @@ -64,7 +64,7 @@ function initConfigAndDatabases(cb) { function getAreaAndStorage(tags) { return tags.map(tag => { - const parts = tag.split('@'); + const parts = tag.toString().split('@'); const entry = { areaTag : parts[0], }; diff --git a/core/oputil/oputil_file_base.js b/core/oputil/oputil_file_base.js index fe9ebb54..da837180 100644 --- a/core/oputil/oputil_file_base.js +++ b/core/oputil/oputil_file_base.js @@ -8,11 +8,13 @@ const argv = require('./oputil_common.js').argv; const initConfigAndDatabases = require('./oputil_common.js').initConfigAndDatabases; const getHelpFor = require('./oputil_help.js').getHelpFor; const getAreaAndStorage = require('./oputil_common.js').getAreaAndStorage; - +const Errors = require('../../core/enig_error.js').Errors; const async = require('async'); const fs = require('fs'); const paths = require('path'); +const _ = require('lodash'); +const moment = require('moment'); exports.handleFileBaseCommand = handleFileBaseCommand; @@ -119,6 +121,140 @@ function scanFileAreaForChanges(areaInfo, options, cb) { }); } +function dumpAreaInfo(areaInfo, areaAndStorageInfo, cb) { + console.info(`areaTag: ${areaInfo.areaTag}`); + console.info(`name: ${areaInfo.name}`); + console.info(`desc: ${areaInfo.desc}`); + + areaInfo.storage.forEach(si => { + console.info(`storageTag: ${si.storageTag} => ${si.dir}`); + }); + console.info(''); + + return cb(null); +} + +function dumpFileInfo(shaOrFileId, cb) { + const FileEntry = require('../../core/file_entry.js'); + + async.waterfall( + [ + function getBySha(callback) { + FileEntry.findFileBySha(shaOrFileId, (err, fileEntry) => { + return callback(null, fileEntry); + }); + }, + function getByFileId(fileEntry, callback) { + if(fileEntry) { + return callback(null, fileEntry); // already got it by sha + } + + const fileId = parseInt(shaOrFileId); + if(isNaN(fileId)) { + return callback(Errors.DoesNotExist('Not found')); + } + + fileEntry = new FileEntry(); + fileEntry.load(shaOrFileId, err => { + return callback(err, fileEntry); + }); + }, + function dumpInfo(fileEntry, callback) { + const fullPath = paths.join(fileArea.getAreaStorageDirectoryByTag(fileEntry.storageTag), fileEntry.fileName); + + console.info(`file_id: ${fileEntry.fileId}`); + console.info(`sha_256: ${fileEntry.fileSha256}`); + console.info(`area_tag: ${fileEntry.areaTag}`); + console.info(`path: ${fullPath}`); + console.info(`hashTags: ${Array.from(fileEntry.hashTags).join(', ')}`); + console.info(`uploaded: ${moment(fileEntry.uploadTimestamp).format()}`); + + _.each(fileEntry.meta, (metaValue, metaName) => { + console.info(`${metaName}: ${metaValue}`); + }); + + if(argv['show-desc']) { + console.info(`${fileEntry.desc}`); + } + console.info(''); + + return callback(null); + } + ], + err => { + return cb(err); + } + ); +/* + FileEntry.findFileBySha(sha, (err, fileEntry) => { + if(err) { + return cb(err); + } + + const fullPath = paths.join(fileArea.getAreaStorageDirectoryByTag(fileEntry.storageTag), fileEntry.fileName); + + console.info(`file_id: ${fileEntry.fileId}`); + console.info(`sha_256: ${fileEntry.fileSha256}`); + console.info(`area_tag: ${fileEntry.areaTag}`); + console.info(`path: ${fullPath}`); + console.info(`hashTags: ${Array.from(fileEntry.hashTags).join(', ')}`); + console.info(`uploaded: ${moment(fileEntry.uploadTimestamp).format()}`); + + _.each(fileEntry.meta, (metaValue, metaName) => { + console.info(`${metaName}: ${metaValue}`); + }); + + if(argv['show-desc']) { + console.info(`${fileEntry.desc}`); + } + }); + */ +} + +function displayFileAreaInfo() { + // AREA_TAG[@STORAGE_TAG] + // SHA256|PARTIAL + // if sha: dump file info + // if area/stoarge dump area(s) + + + async.series( + [ + function init(callback) { + return initConfigAndDatabases(callback); + }, + function dumpInfo(callback) { + const Config = require('../../core/config.js').config; + let suppliedAreas = argv._.slice(2); + if(!suppliedAreas || 0 === suppliedAreas.length) { + suppliedAreas = _.map(Config.fileBase.areas, (areaInfo, areaTag) => areaTag); + } + + const areaAndStorageInfo = getAreaAndStorage(suppliedAreas); + + fileArea = require('../../core/file_base_area.js'); + + async.eachSeries(areaAndStorageInfo, (areaAndStorage, nextArea) => { + const areaInfo = fileArea.getFileAreaByTag(areaAndStorage.areaTag); + if(areaInfo) { + return dumpAreaInfo(areaInfo, areaAndStorageInfo, nextArea); + } else { + return dumpFileInfo(areaAndStorage.areaTag, nextArea); + } + }, + err => { + return callback(err); + }); + } + ], + err => { + if(err) { + process.exitCode = ExitCodes.ERROR; + console.error(err.message); + } + } + ); +} + function scanFileAreas() { const options = {}; @@ -170,6 +306,7 @@ function handleFileBaseCommand() { const action = argv._[1]; switch(action) { + case 'info' : return displayFileAreaInfo(); case 'scan' : return scanFileAreas(); } } \ No newline at end of file diff --git a/core/oputil/oputil_help.js b/core/oputil/oputil_help.js index 60c59595..b04bdb38 100644 --- a/core/oputil/oputil_help.js +++ b/core/oputil/oputil_help.js @@ -38,16 +38,22 @@ valid args: --new : generate a new/initial configuration `, FileBase : -`usage: oputil.js fb [] [] +`usage: oputil.js fb [] [] where is one of: - scan AREA_TAG : (re)scan area specified by AREA_TAG for new files - multiple area tags can be specified in form of AREA_TAG1 AREA_TAG2 ... + scan AREA_TAG|SHA|FILE_ID : scan specified areas + AREA_TAG may be suffixed with @STORAGE_TAG; for example: retro@bbs + + info AREA_TAG|FILE_ID|SHA : display information about areas and/or files + SHA may be a full or partial SHA-256 valid scan : - --tags TAG1,TAG2,... : specify tag(s) to assign to discovered entries + --tags TAG1,TAG2,... : specify tag(s) to assign to discovered entries + +valid info : + --show-desc : display short description, if any + -ARE_TAG can optionally contain @STORAGE_TAG; for example: retro_pc@bbs ` };