Skip to content

Commit 181b7f8

Browse files
authored
Merge branch 'main' into fix-resymlink-broken-installs
2 parents 1323752 + 08b77ce commit 181b7f8

3 files changed

Lines changed: 56 additions & 24 deletions

File tree

.github/workflows/cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ jobs:
6969
repo: pkgxdev/homebrew-made
7070
ref: main
7171
token: ${{secrets.GH_TOKEN}}
72-
inputs: '{ "formula": "pkgx" }'
72+
inputs: '{ "formula": "pkgm" }'

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
- run: ./pkgm.ts i pkgx.sh/brewkit
3939
- run: /usr/local/bin/bk --help
4040

41+
- run: ./pkgm.ts li pkgx.sh/brewkit
42+
- run: ~/.local/bin/bk --help
43+
4144
- run: |
4245
if [[ "$(/usr/local/bin/pkgx --version)" != "pkgx 2"* ]]; then
4346
exit 1

pkgm.ts

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
1-
#!/usr/bin/env -S pkgx --quiet deno^2.1 run --ext=ts --allow-sys=uid --allow-run --allow-env=PKGX_DIR,HOMEBREW_PREFIX,HOME --allow-read=/usr/local/pkgs
1+
#!/usr/bin/env -S pkgx --quiet deno^2.1 run --ext=ts --allow-sys=uid --allow-run --allow-env=PKGX_DIR,HOMEBREW_PREFIX,HOME --allow-read=/usr/local/pkgs,${HOME}/.local/pkgs
22
import { dirname, fromFileUrl, join } from "jsr:@std/path@^1";
33
import { ensureDir, existsSync } from "jsr:@std/fs@^1";
4-
import { parse as parse_args } from "jsr:@std/flags@0.224.0";
4+
import { parseArgs } from "jsr:@std/cli@^1";
55
import * as semver from "jsr:@std/semver@^1";
66

77
function standardPath() {
8-
const basePath = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
9-
// for pkgm installed via homebrew
10-
const homebrew = `${Deno.env.get("HOMEBREW_PREFIX") || "/opt/homebrew"}/bin`;
11-
if (Deno.build.os === "darwin") {
12-
return `${homebrew}:${basePath}`;
13-
} else {
14-
return basePath;
8+
let path = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
9+
10+
// for pkgx installed via homebrew
11+
let homebrewPrefix = "";
12+
switch (Deno.build.os) {
13+
case "darwin":
14+
homebrewPrefix = "/opt/homebrew"; // /usr/local is already in the path
15+
break;
16+
case "linux":
17+
homebrewPrefix = `/home/linuxbrew/.linuxbrew:${
18+
Deno.env.get("HOME")
19+
}/.linuxbrew`;
20+
break;
21+
}
22+
if (homebrewPrefix) {
23+
homebrewPrefix = Deno.env.get("HOMEBREW_PREFIX") ?? homebrewPrefix;
24+
path = `${homebrewPrefix}/bin:${path}`;
1525
}
26+
27+
return path;
1628
}
1729

18-
const parsedArgs = parse_args(Deno.args, {
30+
const parsedArgs = parseArgs(Deno.args, {
1931
alias: {
2032
v: "version",
2133
h: "help",
@@ -34,7 +46,11 @@ if (parsedArgs.help) {
3446
switch (parsedArgs._[0]) {
3547
case "install":
3648
case "i":
37-
await install(args);
49+
await install(args, "/usr/local");
50+
break;
51+
case "local-install":
52+
case "li":
53+
await install(args, `${Deno.env.get("HOME")!}/.local`);
3854
break;
3955
case "uninstall":
4056
case "rm":
@@ -49,12 +65,12 @@ if (parsedArgs.help) {
4965
Deno.exit(1);
5066
break;
5167
case "sudo-install": {
52-
const [pkgx_dir, runtime_env, ...paths] = args;
68+
const [pkgx_dir, runtime_env, basePath, ...paths] = args;
5369
const parsed_runtime_env = JSON.parse(runtime_env) as Record<
5470
string,
5571
Record<string, string>
5672
>;
57-
await sudo_install(pkgx_dir, paths, parsed_runtime_env);
73+
await sudo_install(pkgx_dir, paths, parsed_runtime_env, basePath);
5874
break;
5975
}
6076
default:
@@ -67,7 +83,7 @@ if (parsedArgs.help) {
6783
}
6884
}
6985

70-
async function install(args: string[]) {
86+
async function install(args: string[], basePath: string) {
7187
if (args.length === 0) {
7288
console.error("no packages specified");
7389
Deno.exit(1);
@@ -106,9 +122,9 @@ async function install(args: string[]) {
106122

107123
const self = fromFileUrl(import.meta.url);
108124
const pkgx_dir = Deno.env.get("PKGX_DIR") || `${Deno.env.get("HOME")}/.pkgx`;
109-
const needs_sudo = Deno.uid() != 0;
125+
const needs_sudo = Deno.uid() != 0 && basePath === "/usr/local";
110126

111-
const runtime_env = expand_runtime_env(json.runtime_env);
127+
const runtime_env = expand_runtime_env(json.runtime_env, basePath);
112128

113129
args = [
114130
"pkgx",
@@ -121,9 +137,20 @@ async function install(args: string[]) {
121137
"sudo-install",
122138
pkgx_dir,
123139
runtime_env,
140+
basePath,
124141
...pkg_prefixes,
125142
];
126-
const cmd = needs_sudo ? "/usr/bin/sudo" : args.shift()!;
143+
let cmd = "";
144+
if (needs_sudo) {
145+
cmd = "/usr/bin/sudo";
146+
args.unshift(
147+
"-E", // we already cleared the env, it's safe
148+
"env",
149+
`PATH=${env.PATH}`,
150+
);
151+
} else {
152+
cmd = args.shift()!;
153+
}
127154
status = await new Deno.Command(cmd, { args, env, clearEnv: true })
128155
.spawn().status;
129156
Deno.exit(status.code);
@@ -133,12 +160,13 @@ async function sudo_install(
133160
pkgx_dir: string,
134161
pkg_prefixes: string[],
135162
runtime_env: Record<string, Record<string, string>>,
163+
basePath: string,
136164
) {
137-
const dst = "/usr/local";
165+
const dst = basePath;
138166
for (const pkg_prefix of pkg_prefixes) {
139-
// create /usr/local/pkgs/${prefix}
167+
// create ${dst}/pkgs/${prefix}
140168
await mirror_directory(join(dst, "pkgs"), pkgx_dir, pkg_prefix);
141-
// symlink /usr/local/pkgs/${prefix} to /usr/local
169+
// symlink ${dst}/pkgs/${prefix} to ${dst}
142170
if (!pkg_prefix.startsWith("pkgx.sh/v")) {
143171
// ^^ don’t overwrite ourselves
144172
// ^^ * https://github.com/pkgxdev/pkgm/issues/14
@@ -157,14 +185,14 @@ async function sudo_install(
157185
if (!pkg_prefix) continue; //FIXME wtf?
158186

159187
for (const bin of ["bin", "sbin"]) {
160-
const bin_prefix = join("/usr/local/pkgs", pkg_prefix, bin);
188+
const bin_prefix = join(`${dst}/pkgs`, pkg_prefix, bin);
161189

162190
if (!existsSync(bin_prefix)) continue;
163191

164192
for await (const entry of Deno.readDir(bin_prefix)) {
165193
if (!entry.isFile) continue;
166194

167-
const to_stub = join("/usr/local", bin, entry.name);
195+
const to_stub = join(dst, bin, entry.name);
168196

169197
let sh = `#!/bin/sh\n`;
170198
for (const [key, value] of Object.entries(env)) {
@@ -280,12 +308,13 @@ async function create_v_symlinks(prefix: string) {
280308

281309
function expand_runtime_env(
282310
runtime_env: Record<string, Record<string, string>>,
311+
basePath: string,
283312
) {
284313
const expanded: Record<string, Record<string, string>> = {};
285314
for (const [project, env] of Object.entries(runtime_env)) {
286315
const expanded_env: Record<string, string> = {};
287316
for (const [key, value] of Object.entries(env)) {
288-
const new_value = value.replaceAll(/\$?{{.*prefix}}/g, "/usr/local");
317+
const new_value = value.replaceAll(/\$?{{.*prefix}}/g, basePath);
289318
expanded_env[key] = new_value;
290319
}
291320
expanded[project] = expanded_env;

0 commit comments

Comments
 (0)