Updates
This commit is contained in:
@@ -2,6 +2,48 @@
|
||||
* rm — remove files or directories.
|
||||
* Flags: -r -R --recursive, -f --force, -d --dir, -- ; bundled e.g. -rf
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} vfs
|
||||
* @param {string} p logical path
|
||||
* @param {boolean} force
|
||||
*/
|
||||
async function rmTreeManual(vfs, p, force) {
|
||||
/** @type {{ type?: string } | null} */
|
||||
let st = null
|
||||
try {
|
||||
st = await vfs.lstat(p)
|
||||
} catch (e) {
|
||||
if (!force) throw e
|
||||
return
|
||||
}
|
||||
if (!st) {
|
||||
if (!force) throw new Error('No such file')
|
||||
return
|
||||
}
|
||||
if (st.type === 'directory') {
|
||||
/** @type {string[]} */
|
||||
const names = []
|
||||
try {
|
||||
for await (const n of vfs.readdir(p)) names.push(n)
|
||||
} catch (e) {
|
||||
if (!force) throw e
|
||||
return
|
||||
}
|
||||
for (const n of names) {
|
||||
const child =
|
||||
p.replace(/\/+$/, '') === ''
|
||||
? '/' + n
|
||||
: p.replace(/\/$/, '') + '/' + n
|
||||
await rmTreeManual(vfs, child, force)
|
||||
}
|
||||
if (typeof vfs.rmdir === 'function') await vfs.rmdir(p)
|
||||
else await vfs.unlink(p)
|
||||
return
|
||||
}
|
||||
await vfs.unlink(p)
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
let recursive = false
|
||||
@@ -56,7 +98,7 @@ async function run(ctx, argv) {
|
||||
vfs && typeof vfs.rm === 'function'
|
||||
? (p) => vfs.rm(p, { recursive, force })
|
||||
: async (p) => {
|
||||
if (recursive) throw new Error('recursive rm not supported')
|
||||
if (recursive) return rmTreeManual(vfs, p, force)
|
||||
return vfs.unlink(p)
|
||||
}
|
||||
for (const f of files) {
|
||||
|
||||
@@ -1,27 +1,51 @@
|
||||
/**
|
||||
* @param {string} raw
|
||||
* @param {number} curLen
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function resolveTruncateSize(raw, curLen) {
|
||||
const s = String(raw).trim()
|
||||
if (!s) return null
|
||||
if (/%$/.test(s)) {
|
||||
const inner = s.startsWith('+') || s.startsWith('-') ? s.slice(1) : s
|
||||
const pct = Number.parseFloat(inner.replace(/%$/, ''))
|
||||
if (!Number.isFinite(pct)) return null
|
||||
const delta = Math.floor((curLen * pct) / 100)
|
||||
if (s.startsWith('+')) return Math.max(0, curLen + delta)
|
||||
if (s.startsWith('-')) return Math.max(0, curLen - delta)
|
||||
return Math.max(0, Math.floor((curLen * pct) / 100))
|
||||
}
|
||||
if (s.startsWith('+')) {
|
||||
const n = Number.parseInt(s.slice(1), 10)
|
||||
if (!Number.isFinite(n)) return null
|
||||
return Math.max(0, curLen + n)
|
||||
}
|
||||
if (s.startsWith('-')) {
|
||||
const n = Number.parseInt(s.slice(1), 10)
|
||||
if (!Number.isFinite(n)) return null
|
||||
return Math.max(0, curLen - n)
|
||||
}
|
||||
const abs = Number.parseInt(s, 10)
|
||||
if (!Number.isFinite(abs) || abs < 0) return null
|
||||
return abs
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
let size = null
|
||||
/** @type {string | null} */
|
||||
let sizeSpec = null
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: truncate -s SIZE FILE\nSet file length to SIZE bytes (padded with zeros if growing).'
|
||||
'usage: truncate -s SIZE FILE\n' +
|
||||
'SIZE: bytes, +N, -N, +N%, -N%, or N% (of current length).\n' +
|
||||
'Sets file length (padded with zeros if growing).'
|
||||
)
|
||||
return
|
||||
}
|
||||
if ((a === '-s' || a === '--size') && argv[i + 1]) {
|
||||
const raw = argv[++i]
|
||||
if (raw.startsWith('+') || raw.startsWith('-')) {
|
||||
ctx.console.error('truncate: relative sizes not supported')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
size = parseInt(raw, 10)
|
||||
if (!Number.isFinite(size) || size < 0) {
|
||||
ctx.console.error('truncate: invalid size')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
sizeSpec = argv[++i]
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('-')) {
|
||||
@@ -31,7 +55,7 @@ async function run(ctx, argv) {
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
if (size == null || paths.length !== 1) {
|
||||
if (!sizeSpec || paths.length !== 1) {
|
||||
ctx.console.error('usage: truncate -s SIZE FILE')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
@@ -42,7 +66,13 @@ async function run(ctx, argv) {
|
||||
const b = await ctx.vfs.readFile(file)
|
||||
if (b) cur = b instanceof Uint8Array ? b : new Uint8Array(b)
|
||||
} catch {
|
||||
/* new file */
|
||||
/* new file — relative sizes use curLen 0 */
|
||||
}
|
||||
const size = resolveTruncateSize(sizeSpec, cur.length)
|
||||
if (size == null) {
|
||||
ctx.console.error('truncate: invalid size: ' + sizeSpec)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
const out = new Uint8Array(size)
|
||||
out.set(cur.subarray(0, Math.min(cur.length, size)))
|
||||
|
||||
Reference in New Issue
Block a user