Skip to content

Commit 8e1f3e9

Browse files
committed
Unfortunately, we must stub for runtime-env
1 parent 76641c8 commit 8e1f3e9

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
Install `pkgx` packages to `/usr/local`.
44

5-
> [!WARNING]
5+
> [!CAUTION]
66
>
77
> `pkgm` is new software. Please report any issues you encounter and try it out
88
> in parallel with your current package manager.
99
10+
> [!WARNING]
11+
>
12+
> `pkgm` is new software. Some features listed here are not yet implemented. You
13+
> can help! Or we’ll get to it soon.
14+
1015
## Usage
1116

1217
```sh

pkgm.ts

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env -S pkgx deno^2.1 run --ext=ts --allow-sys=uid --allow-run=pkgx,/usr/bin/sudo --allow-env=PKGX_DIR,HOME --allow-read=/usr/local/pkgs
22
import { dirname, fromFileUrl, join } from "jsr:@std/path@^1";
3-
import { ensureDir, exists, existsSync } from "jsr:@std/fs@^1";
3+
import { ensureDir, existsSync } from "jsr:@std/fs@^1";
44
import { parse as parse_args } from "jsr:@std/flags@0.224.0";
55
import * as semver from "jsr:@std/semver@^1";
66

@@ -46,8 +46,12 @@ if (parsedArgs.help) {
4646
Deno.exit(1);
4747
break;
4848
case "sudo-install": {
49-
const [pkgx_dir, ...paths] = args;
50-
await sudo_install(pkgx_dir, paths);
49+
const [pkgx_dir, runtime_env, ...paths] = args;
50+
const parsed_runtime_env = JSON.parse(runtime_env) as Record<
51+
string,
52+
Record<string, string>
53+
>;
54+
await sudo_install(pkgx_dir, paths, parsed_runtime_env);
5155
break;
5256
}
5357
default:
@@ -109,6 +113,8 @@ async function install(args: string[]) {
109113
const pkgx_dir = Deno.env.get("PKGX_DIR") || `${Deno.env.get("HOME")}/.pkgx`;
110114
const needs_sudo = Deno.uid() != 0;
111115

116+
const runtime_env = expand_runtime_env(json.runtime_env);
117+
112118
args = [
113119
"pkgx",
114120
"deno^2.1",
@@ -119,6 +125,7 @@ async function install(args: string[]) {
119125
self,
120126
"sudo-install",
121127
pkgx_dir,
128+
runtime_env,
122129
...to_install,
123130
];
124131
const cmd = needs_sudo ? "/usr/bin/sudo" : args.shift()!;
@@ -127,7 +134,11 @@ async function install(args: string[]) {
127134
Deno.exit(status.code);
128135
}
129136

130-
async function sudo_install(pkgx_dir: string, pkg_prefixes: string[]) {
137+
async function sudo_install(
138+
pkgx_dir: string,
139+
pkg_prefixes: string[],
140+
runtime_env: Record<string, Record<string, string>>,
141+
) {
131142
const dst = "/usr/local";
132143
for (const pkg_prefix of pkg_prefixes) {
133144
// create /usr/local/pkgs/${prefix}
@@ -137,6 +148,31 @@ async function sudo_install(pkgx_dir: string, pkg_prefixes: string[]) {
137148
// create v1, etc. symlinks
138149
await create_v_symlinks(join("/usr/local/pkgs", pkg_prefix));
139150
}
151+
152+
for (const [project, env] of Object.entries(runtime_env)) {
153+
const pkg_prefix = pkg_prefixes.find((x) => x.startsWith(project))!;
154+
for (const bin of ["bin", "sbin"]) {
155+
const bin_prefix = join("/usr/local/pkgs", pkg_prefix, bin);
156+
157+
if (!existsSync(bin_prefix)) continue;
158+
159+
for await (const entry of Deno.readDir(bin_prefix)) {
160+
if (!entry.isFile) continue;
161+
162+
const to_stub = join("/usr/local", bin, entry.name);
163+
164+
let sh = `#!/bin/sh\n`;
165+
for (const [key, value] of Object.entries(env)) {
166+
sh += `export ${key}="${value}"\n`;
167+
}
168+
sh += `exec "${bin_prefix}/${entry.name}" "$@"\n`;
169+
170+
await Deno.remove(to_stub); //FIXME inefficient to symlink for no reason
171+
await Deno.writeTextFile(to_stub, sh);
172+
await Deno.chmod(to_stub, 0o755);
173+
}
174+
}
175+
}
140176
}
141177

142178
async function mirror_directory(dst: string, src: string, prefix: string) {
@@ -185,6 +221,10 @@ async function symlink(src: string, dst: string) {
185221
await processEntry(entrySourcePath, entryTargetPath);
186222
}
187223
} else {
224+
// resinstall
225+
if (existsSync(targetPath)) {
226+
await Deno.remove(targetPath);
227+
}
188228
await Deno.symlink(sourcePath, targetPath);
189229
}
190230
}
@@ -223,3 +263,18 @@ async function create_v_symlinks(prefix: string) {
223263
await Deno.symlink(`v${semver.format(value)}`, join(shelf, `v${key}`));
224264
}
225265
}
266+
267+
function expand_runtime_env(
268+
runtime_env: Record<string, Record<string, string>>,
269+
) {
270+
const expanded: Record<string, Record<string, string>> = {};
271+
for (const [project, env] of Object.entries(runtime_env)) {
272+
const expanded_env: Record<string, string> = {};
273+
for (const [key, value] of Object.entries(env)) {
274+
const new_value = value.replaceAll(/\$?{{.*prefix}}/g, "/usr/local");
275+
expanded_env[key] = new_value;
276+
}
277+
expanded[project] = expanded_env;
278+
}
279+
return JSON.stringify(expanded);
280+
}

0 commit comments

Comments
 (0)