-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathinstall.ts
86 lines (75 loc) · 2.81 KB
/
install.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { PackageRequirement, Path, PkgxError, hooks, utils } from "pkgx"
import { is_shebang } from "../utils/get-shebang.ts"
import { blurple, dim } from "../utils/color.ts"
import undent from 'outdent'
const { usePantry } = hooks
// * maybe impl `$XDG_BIN_HOME`
export default async function(pkgs: PackageRequirement[]) {
const usrlocal = new Path("/usr/local/bin")
let n = 0
try {
await write(usrlocal, pkgs)
} catch (err) {
//FIXME we should check if /usr/local/bin is writable, but were having trouble with that
if (err instanceof Deno.errors.PermissionDenied) {
const bindir = Path.home().join(".local/bin")
await write(bindir, pkgs)
if (n > 0 && !Deno.env.get("PATH")?.split(":").includes(bindir.string)) {
console.warn("pkgx: %c`%s` is not in `PATH`", 'color: red', bindir)
}
} else {
throw err
}
}
if (n == 0) {
console.error('pkgx: no programs provided by pkgs')
}
async function write(dst: Path, pkgs: PackageRequirement[]) {
for (const pkg of pkgs) {
const programs = await usePantry().project(pkg).provides()
program_loop:
for (const program of programs) {
// skip for now since we would require specific versions and we haven't really got that
if (program.includes("{{")) continue
const pkgstr = utils.pkg.str(pkg)
const exec = `exec pkgx +${pkgstr} -- ${program} "$@"`
const script = undent`
if [ "$PKGX_UNINSTALL" != 1 ]; then
${exec}
else
cd "$(dirname "$0")"
rm ${programs.join(' ')} && echo "uninstalled: ${pkgstr}" >&2
fi`
const f = dst.mkdir('p').join(program)
if (f.exists()) {
if (!f.isFile()) throw new PkgxError(`${f} already exists and is not a file`)
const fd = is_shebang(f).catch(() => undefined)
if (!fd) throw new PkgxError(`${f} already exists and is not a pkgx installation`)
const lines = f.readLines()
const { value: shebang } = await lines.next()
if (shebang != "#!/bin/sh") {
throw new PkgxError(`${f} already exists and is not a pkgx installation`)
}
while (true) {
const { value, done } = await lines.next()
if (done) {
throw new PkgxError(`${f} already exists and is not a pkgx installation`)
}
const found = value.match(/^\s*exec pkgx \+([^ ]+)/)?.[1]
if (found) {
n++
console.warn(`pkgx: already installed: ${blurple(program)} ${dim(`(${found})`)}`)
continue program_loop
}
}
}
f.write({ force: true, text: undent`
#!/bin/sh
${script}`
}).chmod(0o755)
console.error('pkgx: installed:', f)
n++
}
}
}
}