Skip to content

Commit 8662db5

Browse files
authored
Merge pull request #64 from pkgxdev/dev-aware-stubs
Install dev aware stubs
2 parents 4ece506 + e416286 commit 8662db5

File tree

4 files changed

+99
-27
lines changed

4 files changed

+99
-27
lines changed

.github/workflows/cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
mv pkgm.ts pkgm
4444
tar czf pkgm-$V.tgz pkgm
4545
46-
- uses: pkgxdev/setup@v3
46+
- uses: pkgxdev/setup@v4
4747

4848
- name: verify `pkgm --version`
4949
run: test "$(./pkgm --version)" = "pkgm $V"

.github/workflows/ci.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525
#TODO test on linux! we are currently broken due to rpath issues
2626
# https://github.com/pkgxdev/pkgm/pull/30#issuecomment-2678957666
2727
test:
28+
continue-on-error: true
2829
strategy:
2930
matrix:
3031
os:
@@ -33,7 +34,7 @@ jobs:
3334
runs-on: ${{ matrix.os }}
3435
steps:
3536
- uses: actions/checkout@v4
36-
- uses: pkgxdev/setup@v3
37+
- uses: pkgxdev/setup@v4
3738

3839
- run: ./pkgm.ts i git
3940
- run: ~/.local/bin/git --version
@@ -90,6 +91,19 @@ jobs:
9091
env:
9192
XDG_DATA_HOME: /tmp/foo
9293
94+
- run: |
95+
set -x
96+
sudo ./pkgm.ts i node@22 dev
97+
[[ $(node --version) = v22* ]] || exit 2
98+
mkdir foo
99+
cd foo
100+
echo "dependencies: node@20" > pkgx.yaml
101+
mkdir -p /tmp/bar/pkgx/dev$PWD/
102+
touch /tmp/bar/pkgx/dev$PWD/dev.pkgx.activated # `dev .` doesn’t work in CI (fix in dev^2)
103+
[[ $(node --version) = v20* ]] || exit 3
104+
env:
105+
XDG_DATA_HOME: /tmp/bar
106+
93107
# https://github.com/pkgxdev/pkgm/issues/62
94108
- run: |
95109
./pkgm.ts i spotify_player

README.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,26 @@ Install `pkgx` packages to `/usr/local`.
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-
1510
## Usage
1611

1712
```sh
18-
$ pkgm install git
19-
# ^^ installs latest git to ~/.local. ie. you get ~/.local/bin/git
13+
$ pkgm install node
14+
# ^^ installs latest node to ~/.local. ie. you get ~/.local/bin/node
2015

21-
$ pkgm install git@2.41
22-
# ^^ installs git^2.41 or switches out the installed git to 2.41
16+
$ pkgm install node@20.1
17+
# ^^ installs node^20.1 or switches out the installed node to 20.1
2318

24-
$ pkgm uninstall git
19+
$ pkgm uninstall node
2520

26-
$ sudo pkgm install git
27-
# ^^ installs git to /usr/local. ie. you get /usr/local/bin/git
21+
$ sudo pkgm install node
22+
# ^^ installs node to /usr/local. ie. you get /usr/local/bin/node
2823

29-
$ pkgm shim git
30-
# ^^ creates a shim for git in ~/.local/bin
31-
# these shims mimic the pkgx v1 lazy-loading shims, and are desirable for
32-
# certain types of self-healing and dev-setup containers, among other things
33-
# requires pkgx^2.4.0 for --shebang option
24+
$ pkgm shim node
25+
# ^^ creates a shim for node at ~/.local/bin/node
26+
# see the docs below for details about shims
3427

3528
$ pkgm list
36-
# ^^ lists what is installed
29+
# ^^ lists what’s installed
3730

3831
$ pkgm outdated
3932
# ^^ lists outdated installations
@@ -43,9 +36,6 @@ $ pkgm update
4336

4437
$ sudo pkgm update
4538
# ^^ updates /usr/local packages to latest versions
46-
47-
$ pkgm pin git
48-
# ^^ prevents the installed git from being updated
4939
```
5040

5141
> [!TIP]
@@ -55,6 +45,25 @@ $ pkgm pin git
5545
> - `pkgm ls` is an alias for `pkgm list`
5646
> - `pkgm up` is an alias for `pkgm update`
5747
48+
> [!WARNING]
49+
>
50+
> You should probably `sudo pkgm install` rather than install to `~/.local`.
51+
> This is because many other tools will not look in `~/.local` for packages
52+
> _even_ if it’s in `PATH`. Having said this—by all means—see how it goes!
53+
54+
> ### Shims
55+
>
56+
> Shims are files with a single line, eg `#!/usr/bin/env -S pkgx -q! node@22`.
57+
>
58+
> Thus using the shell to reinvoke the file via `pkgx`. You get all the benefits
59+
> of an installed package without actually it actually being installed until it
60+
> is needed. Traits desirable for certain types of self-healing, devops
61+
> containers and plenty more one-off or ephemeral tasks.
62+
>
63+
> Shims are pretty great—but have caveats. Some software might be surprised that
64+
> a package is not fully “installed” and lead to errors. In practice we have
65+
> seen issues only rarely and for more complex package combinations.
66+
5867
## Installation
5968

6069
```sh
@@ -78,4 +87,6 @@ brew rm pkgm || sudo rm /usr/local/bin/pkgm
7887
- Blazingly fast
7988
- Install specific versions of any pkg
8089
- You install by executable name—thus you _don’t have to do a search first_
81-
- Installed packages are installed as `root`
90+
- Installed packages can be installed as `root`
91+
- `dev`-aware installations
92+
- Self-healing shims

pkgm.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,14 @@ async function install(args: string[], basePath: string) {
136136
`${x.pkg.project}/v${x.pkg.version}`
137137
);
138138

139-
const pkgx_dir = Deno.env.get("PKGX_DIR") || `${Deno.env.get("HOME")}/.pkgx`;
139+
// get the pkgx_dir this way as it is a) more reliable and b) the only way if
140+
// we are running as sudo on linux since it doesn’t give us a good way to get
141+
// the home directory of the pre-sudo user
142+
const pkgx_dir = (() => {
143+
const { path, pkg } = json.pkgs[0]!;
144+
const remove = pkg.project + "/v" + pkg.version;
145+
return path.string.slice(0, -remove.length - 1);
146+
})();
140147

141148
const runtime_env = expand_runtime_env(json, basePath);
142149

@@ -178,10 +185,13 @@ async function install(args: string[], basePath: string) {
178185
for (const [key, value] of Object.entries(env)) {
179186
sh += `export ${key}="${value}"\n`;
180187
}
181-
sh += `exec "${bin_prefix}/${entry.name}" "$@"\n`;
188+
189+
sh += "\n";
190+
//TODO should be specific with the project
191+
sh += dev_stub_text(to_stub, bin_prefix, entry.name);
182192

183193
await Deno.remove(to_stub); //FIXME inefficient to symlink for no reason
184-
await Deno.writeTextFile(to_stub, sh);
194+
await Deno.writeTextFile(to_stub, sh.trim() + "\n");
185195
await Deno.chmod(to_stub, 0o755);
186196

187197
rv.push(to_stub);
@@ -282,6 +292,7 @@ async function query_pkgx(
282292
set("PKGX_DIR");
283293
set("PKGX_PANTRY_DIR");
284294
set("PKGX_DIST_URL");
295+
set("XDG_DATA_HOME");
285296

286297
const needs_sudo_backwards = install_prefix().string == "/usr/local";
287298
let cmd = needs_sudo_backwards ? "/usr/bin/sudo" : pkgx;
@@ -316,6 +327,7 @@ async function query_pkgx(
316327

317328
const out = await proc.output();
318329
const json = JSON.parse(new TextDecoder().decode(out.stdout));
330+
319331
const pkgs =
320332
(json.pkgs as { path: string; project: string; version: string }[]).map(
321333
(x) => {
@@ -726,3 +738,38 @@ function install_prefix() {
726738
return Path.home().join(".local");
727739
}
728740
}
741+
742+
function dev_stub_text(selfpath: string, bin_prefix: string, name: string) {
743+
if (selfpath.startsWith("/usr/local") && selfpath != "/usr/local/bin/dev") {
744+
return `
745+
dev_check() {
746+
[ -x /usr/local/bin/dev ] || return 1
747+
local d="$PWD"
748+
until [ "$d" = / ]; do
749+
if [ -f "${datadir()}/pkgx/dev/$d/dev.pkgx.activated" ]; then
750+
echo $d
751+
return 0
752+
fi
753+
d="$(dirname "$d")"
754+
done
755+
return 1
756+
}
757+
758+
if d="$(dev_check)"; then
759+
eval "$(/usr/local/bin/dev "$d" 2>/dev/null)"
760+
[ "$(command -v ${name} 2>/dev/null)" != "${selfpath}" ] && exec ${name} "$@"
761+
fi
762+
763+
exec ${bin_prefix}/${name} "$@"
764+
`.trim();
765+
} else {
766+
return `exec ${bin_prefix}/${name} "$@"`;
767+
}
768+
}
769+
770+
function datadir() {
771+
const default_data_home = Deno.build.os == "darwin"
772+
? "/Library/Application Support"
773+
: "/.local/share";
774+
return `\${XDG_DATA_HOME:-$HOME${default_data_home}}`;
775+
}

0 commit comments

Comments
 (0)