pantry/scripts/brewkit/fix-shebangs.ts
Max Howell abb0921f3d
don’t need cli checkouts anymore (#146)
* don’t need cli checkouts anymore
* tidy

Co-authored-by: Jacob Heider <jacob@tea.xyz>
2023-02-02 09:00:52 -05:00

73 lines
1.7 KiB
TypeScript
Executable file

#!/usr/bin/env -S tea -E
/* ---
args:
- deno
- run
- --allow-run
- --allow-env
- --allow-read
- --allow-write={{tea.prefix}}
--- */
import Path from "path"
import { undent } from "utils"
import { useFlags } from "hooks"
useFlags()
const has_shebang = (() => {
const encoder = new TextDecoder()
return (buf: Uint8Array) => {
return encoder.decode(buf) == '#!'
}
})()
for (const path of Deno.args) {
if (!Path.cwd().join(path).isFile()) continue
console.debug({ path })
const rid = await Deno.open(path, { read: true })
try {
const buf = new Uint8Array(2)
await rid.read(buf)
if (!has_shebang(buf)) continue
} finally {
rid.close()
}
//FIXME this could be pretty damn efficient if we can find the time
//NOTE as it stands this is HIDEOUSLY inefficient
const contents = await Deno.readFile(path)
const txt = new TextDecoder().decode(contents)
const [line0, ...lines] = txt.split("\n") //lol
const match = line0.match(/^#!\s*(\/[^\s]+)/)
if (!match) throw new Error()
const interpreter = match[1]
switch (interpreter) {
case "/usr/bin/env":
case "/bin/sh":
console.verbose({ line0, path })
console.verbose("^^ skipped acceptable shebang")
continue
}
const shebang = `#!/usr/bin/env ${new Path(interpreter).basename()}`
const rewrite = undent`
${shebang}
${lines.join("\n")}
`
console.verbose({rewrote: path, to: `#!/usr/bin/env ${interpreter}`})
const stat = Deno.lstatSync(path)
const needs_chmod = stat.mode && !(stat.mode & 0o200)
if (needs_chmod) Deno.chmodSync(path, 0o666)
await Deno.writeFile(path, new TextEncoder().encode(rewrite))
if (needs_chmod) Deno.chmodSync(path, stat.mode!)
}