New utils

This commit is contained in:
Raven Scott
2026-04-03 23:04:42 -04:00
parent eeef3da6e1
commit f42f50eb73
214 changed files with 17562 additions and 615 deletions
+97 -1
View File
@@ -166,10 +166,12 @@ async function walk(ctx, dir, o, curDepth) {
const nameOk = !o.nameRe || o.nameRe.test(n)
let match = pathOk && nameOk && (!o.wantType || st.type === o.wantType)
if (match && o.mtimeSpec) match = match && findMatchMtime(st, o.mtimeSpec)
if (match && o.newerThanMs != null) match = match && st.mtimeMs > o.newerThanMs
if (match && o.newerThanMs != null)
match = match && st.mtimeMs > o.newerThanMs
if (match && o.wantEmpty) {
match = match && (await findIsEmpty(ctx, path, st))
}
if (match && o.regexPath && !o.regexPath.test(path)) match = false
if (match && gnuDepth >= o.minDepth) {
if (o.doDelete) {
if (ctx.vfs.env.BARE_OS_FIND_DELETE !== '1') {
@@ -189,6 +191,40 @@ async function walk(ctx, dir, o, curDepth) {
ctx.exitCode = 1
}
}
} else if (o.execTemplate && o.execTemplate.length) {
if (typeof ctx.runBinCommand !== 'function') {
const stw = /** @type {{ noRun?: boolean }} */ (o.deleteState)
if (!stw.noRun) {
ctx.console.error('find: -exec requires ctx.runBinCommand')
stw.noRun = true
}
ctx.exitCode = 1
} else if (o.execCount >= o.execMax) {
const stw = /** @type {{ execCap?: boolean }} */ (o.deleteState)
if (!stw.execCap) {
ctx.console.error(
'find: -exec/-ok: invocation limit (' +
o.execMax +
') exceeded (raise BARE_OS_FIND_EXEC_MAX)'
)
stw.execCap = true
}
ctx.exitCode = 1
} else {
const ok =
!o.execUseOk ||
ctx.vfs.env.BARE_OS_FIND_OK === '1' ||
ctx.vfs.env.BARE_OS_FIND_OK === 'true'
if (o.execUseOk && !ok) {
/* skip without running */
} else {
const subst = o.execTemplate.map((arg) =>
arg === '{}' ? path : arg.split('{}').join(path)
)
o.execCount++
await ctx.runBinCommand(subst)
}
}
} else {
findEmitLine(ctx, path, o.print0)
}
@@ -219,6 +255,11 @@ async function run(ctx, argv) {
let prunePath = null
let wantEmpty = false
let doDelete = false
/** @type {string[] | null} */
let execTemplate = null
let execUseOk = false
/** @type {string | null} */
let regexPathStr = null
const rest = []
for (let i = 1; i < argv.length; i++) {
const a = argv[i]
@@ -281,6 +322,39 @@ async function run(ctx, argv) {
doDelete = true
continue
}
if ((a === '-exec' || a === '-ok') && argv[i + 1]) {
execUseOk = a === '-ok'
i++
const parts = []
while (i < argv.length && argv[i] !== ';') {
parts.push(argv[i++])
}
if (i >= argv.length || argv[i] !== ';') {
ctx.console.error('find: ' + a + ' must be terminated with ;')
ctx.exitCode = 1
return
}
i++
if (!parts.length) {
ctx.console.error('find: empty ' + a)
ctx.exitCode = 1
return
}
execTemplate = parts
continue
}
if (a === '-regex' && argv[i + 1]) {
const pat = argv[++i]
try {
new RegExp(pat)
regexPathStr = pat
} catch {
ctx.console.error('find: invalid -regex')
ctx.exitCode = 1
return
}
continue
}
if (a === '--') {
rest.push(...argv.slice(i + 1))
break
@@ -333,6 +407,23 @@ async function run(ctx, argv) {
if (prunePath) {
pruneAbs = ctx.vfs.resolveLogical(prunePath).replace(/\/+$/, '') || '/'
}
/** @type {RegExp | null} */
let regexPath = null
if (regexPathStr) {
try {
regexPath = new RegExp(regexPathStr)
} catch {
ctx.console.error('find: invalid -regex')
ctx.exitCode = 1
return
}
}
const execMaxRaw = ctx.vfs.env.BARE_OS_FIND_EXEC_MAX
let execMax = 64
if (execMaxRaw != null && String(execMaxRaw).trim() !== '') {
const n = Number.parseInt(String(execMaxRaw), 10)
if (Number.isFinite(n)) execMax = Math.min(4096, Math.max(1, n))
}
const abs = ctx.vfs.resolveLogical(root)
const o = {
maxDepth,
@@ -346,6 +437,11 @@ async function run(ctx, argv) {
pruneAbs,
wantEmpty,
doDelete,
regexPath,
execTemplate,
execUseOk,
execCount: 0,
execMax,
deleteState: {}
}
await walk(ctx, abs, o, 0)