format strings here instead of in component template, gen uniqueID

This commit is contained in:
joshuaboud 2022-06-15 17:21:25 -03:00
parent 85be57d26a
commit 58315a56b2
No known key found for this signature in database
GPG Key ID: 17EFB59E2A8BF50E

View File

@ -1,10 +1,12 @@
import { useSpawn, errorString } from "@45drives/cockpit-helpers"; import { useSpawn, errorString } from "@45drives/cockpit-helpers";
import { UNIT_SEPARATOR, RECORD_SEPARATOR } from "../constants"; import { UNIT_SEPARATOR, RECORD_SEPARATOR } from "../constants";
import { szudzikPair } from "./szudzikPair";
import { escapeStringHTML } from "./escapeStringHTML";
/** /**
* Get list of directory entry objects from list of directory entry names * Get list of directory entry objects from list of directory entry names
* *
* find -H path -maxdepth 1 -mindepth 1 -printf '%f:%m:%M:%s:%u:%g:%B@:%T@:%A@:%y:%Y:%l\n' * find -H path -maxdepth 1 -mindepth 1 -printf '%D:%i%f:%m:%M:%s:%u:%g:%B@:%T@:%A@:%y:%Y:%l\n'
* *
* @param {String} cwd - Working directory to run find in * @param {String} cwd - Working directory to run find in
* @param {String} host - Host to run find on * @param {String} host - Host to run find on
@ -14,6 +16,8 @@ import { UNIT_SEPARATOR, RECORD_SEPARATOR } from "../constants";
*/ */
async function getDirEntryObjects(cwd, host, extraFindArgs = [], failCallback = console.error, byteFormatter = cockpit.format_bytes) { async function getDirEntryObjects(cwd, host, extraFindArgs = [], failCallback = console.error, byteFormatter = cockpit.format_bytes) {
const fields = [ const fields = [
'%D', // dev id
'%i', // inode
'%f', // name '%f', // name
'%p', // full path '%p', // full path
'%m', // mode (octal) '%m', // mode (octal)
@ -85,39 +89,50 @@ async function getDirEntryStats(cwd, host, outputFormat, extraFindArguments = []
*/ */
function parseRawEntryStats(records, cwd, host, failCallback, byteFormatter = cockpit.format_bytes) { function parseRawEntryStats(records, cwd, host, failCallback, byteFormatter = cockpit.format_bytes) {
return records.map(fields => { return records.map(fields => {
try { try {
let [name, path, mode, modeStr, size, owner, group, ctime, mtime, atime, type, symlinkTargetType, symlinkTargetName] = fields; let [devId, inode, name, path, mode, modeStr, size, owner, group, ctime, mtime, atime, type, symlinkTargetType, symlinkTargetName] = fields;
[size, ctime, mtime, atime] = [size, ctime, mtime, atime].map(num => parseInt(num)); [size, ctime, mtime, atime] = [size, ctime, mtime, atime].map(num => parseInt(num));
[ctime, mtime, atime] = [ctime, mtime, atime].map(ts => ts ? new Date(ts * 1000) : null); [devId, inode] = [devId, inode].map(num => BigInt(num));
mode = parseInt(mode, 8); [ctime, mtime, atime] = [ctime, mtime, atime].map(ts => (ts && ts > 0) ? new Date(ts * 1000) : null);
return { let [ctimeStr, mtimeStr, atimeStr] = [ctime, mtime, atime].map(date => date?.toLocaleString() ?? '-');
name, let [nameHTML, symlinkTargetNameHTML] = [name, symlinkTargetName].map(escapeStringHTML);
path, mode = parseInt(mode, 8);
mode, return {
modeStr, uniqueId: szudzikPair(host, devId, inode),
size, devId,
sizeHuman: byteFormatter(size, 1000).replace(/(?<!B)$/, ' B'), inode,
owner, name,
group, nameHTML,
ctime, path,
mtime, mode,
atime, modeStr,
type, size,
target: { sizeHuman: byteFormatter(size, 1000).replace(/(?<!B)$/, ' B'),
type: symlinkTargetType, owner,
rawPath: symlinkTargetName, group,
path: type === 'l' ? symlinkTargetName.replace(/^(?!\/)/, `${cwd}/`) : '', ctime,
broken: ['L', 'N', '?'].includes(symlinkTargetType), // L: loop N: nonexistent ?: error mtime,
}, atime,
selected: false, ctimeStr,
host, mtimeStr,
cut: false, atimeStr,
}; type,
} catch (error) { target: {
failCallback(errorString(error) + `\ncaused by: ${fields.toString()}`); type: symlinkTargetType,
return null; rawPath: symlinkTargetName,
} rawPathHTML: symlinkTargetNameHTML,
}).filter(entry => entry !== null) path: type === 'l' ? symlinkTargetName.replace(/^(?!\/)/, `${cwd}/`) : '',
broken: ['L', 'N', '?'].includes(symlinkTargetType), // L: loop N: nonexistent ?: error
},
selected: false,
host,
cut: false,
};
} catch (error) {
failCallback(errorString(error) + `\ncaused by: ${fields.toString()}`);
return null;
}
}).filter(entry => entry !== null)
} }
export { getDirEntryObjects, getDirEntryStats, parseRawEntryStats }; export { getDirEntryObjects, getDirEntryStats, parseRawEntryStats };
@ -143,6 +158,9 @@ export default getDirEntryObjects;
* Object representing file system entry * Object representing file system entry
* *
* @typedef {Object} DirectoryEntryObj * @typedef {Object} DirectoryEntryObj
* @property {BigInt} uniqueId - Unique ID generated from pairing function on [devId, inode]
* @property {BigInt} devId - Device ID containing the file
* @property {BigInt} inode - The file's inode
* @property {String} name - File/directory name * @property {String} name - File/directory name
* @property {String} path - Full path to entry * @property {String} path - Full path to entry
* @property {Number} mode - File mode (number) * @property {Number} mode - File mode (number)
@ -154,6 +172,9 @@ export default getDirEntryObjects;
* @property {Date} ctime - Creation time * @property {Date} ctime - Creation time
* @property {Date} mtime - Last Modified time * @property {Date} mtime - Last Modified time
* @property {Date} atime - Last Accessed time * @property {Date} atime - Last Accessed time
* @property {String} ctimeStr - Creation time string
* @property {String} mtimeStr - Last Modified time string
* @property {String} atimeStr - Last Accessed time string
* @property {String} type - Type of inode returned by find * @property {String} type - Type of inode returned by find
* @property {Object} target - Object for symlink target * @property {Object} target - Object for symlink target
* @property {String} target.rawPath - Symlink target path directly grabbed from find * @property {String} target.rawPath - Symlink target path directly grabbed from find