From 723515973209c00ff20565976786c894d4fa622f Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sat, 11 May 2024 23:03:53 +0530 Subject: [PATCH 1/7] feat(install): add support for `--unsafe` install Signed-off-by: Rajdeep Malakar --- src/modes/install.ts | 34 ++++++++++++++++++++++++++++++++-- src/modes/uninstall.ts | 11 ++++++++++- src/parse-args.ts | 9 +++++++-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/modes/install.ts b/src/modes/install.ts index c517919b..fa6e15af 100644 --- a/src/modes/install.ts +++ b/src/modes/install.ts @@ -6,6 +6,12 @@ const { usePantry } = hooks // * maybe impl `$XDG_BIN_HOME` +export function is_unsafe(): boolean { + // $PKGX_UNSAFE_INSTALL takes precedence over the `--unsafe` flag + const IS_UNSAFE = parseInt(Deno.env.get("PKGX_UNSAFE_INSTALL") || "0") ? true : (Deno.args.includes("--unsafe")); + return IS_UNSAFE; +} + export default async function(pkgs: PackageRequirement[]) { const usrlocal = new Path("/usr/local/bin") let n = 0 @@ -30,6 +36,7 @@ export default async function(pkgs: PackageRequirement[]) { } async function write(dst: Path, pkgs: PackageRequirement[]) { + const UNSAFE = is_unsafe(); for (const pkg of pkgs) { const programs = await usePantry().project(pkg).provides() program_loop: @@ -39,7 +46,30 @@ export default async function(pkgs: PackageRequirement[]) { if (program.includes("{{")) continue const pkgstr = utils.pkg.str(pkg) - const exec = `exec pkgx +${pkgstr} -- ${program} "$@"` + if (UNSAFE) { + const parts = pkgstr.split("/") + parts.pop() + await Deno.mkdir(Path.home().join(`.cache/pkgx/envs/${parts.join("/")}`).toString(), {recursive: true}) + } + //FIXME: doing `set -a` clears the args env + const exec = UNSAFE ? undent` + ARGS="$@" + pkgx_resolve() { + mkdir -p "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs" + pkgx +${pkgstr} 1>"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" + run + } + run() { + if [[ -e "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" && -e "$\{PKGX_HOME:-$HOME/.pkgx\}/${pkgstr}/v*/bin/${program}" ]]; then + set -a + source "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" + exec "$\{PKGX_HOME:-$HOME/.pkgx\}/${pkgstr}/v*/bin/${program}" "$ARGS" + else + pkgx_resolve + fi + } + run + ` : `exec pkgx +${pkgstr} -- ${program} "$@"` const script = undent` if [ "$PKGX_UNINSTALL" != 1 ]; then ${exec} @@ -65,7 +95,7 @@ export default async function(pkgs: PackageRequirement[]) { if (done) { throw new PkgxError(`${f} already exists and is not a pkgx installation`) } - const found = value.match(/^\s*exec pkgx \+([^ ]+)/)?.[1] + const found = value.match(/^\s*pkgx \+([^ ]+)/)?.[1] if (found) { n++ console.warn(`pkgx: already installed: ${blurple(program)} ${dim(`(${found})`)}`) diff --git a/src/modes/uninstall.ts b/src/modes/uninstall.ts index 2e3ac44f..dedd7f02 100644 --- a/src/modes/uninstall.ts +++ b/src/modes/uninstall.ts @@ -1,5 +1,5 @@ import parse_pkg_str from "../prefab/parse-pkg-str.ts" -import { hooks, PackageRequirement, Path, PkgxError } from "pkgx" +import { hooks, PackageRequirement, Path, PkgxError, utils } from "pkgx" export default async function(pkgspecs: string[]) { const pkgs = await Promise.all(pkgspecs.map(x => parse_pkg_str(x, {latest: 'ok'}))) @@ -11,9 +11,18 @@ export default async function(pkgspecs: string[]) { async function uninstall(prefix: Path, pkgs: PackageRequirement[]) { for (const pkg of pkgs) { const programs = await hooks.usePantry().project(pkg).provides() + const pkgstr = utils.pkg.str(pkg) + const parts = pkgstr.split("/") + parts.pop() + //FIXME: it removes the dir successfully. however, it still complains that it didn't delete that + try { + await Deno.remove(Path.home().join(`.cache/pkgx/envs/${parts}`).toString(), {recursive: true}) + } catch (e) { + } for (const program of programs) { const f = prefix.join(program) if (f.isFile()) { + console.log(f) const cmd = new Deno.Command(f.string, {env: {PKGX_UNINSTALL: '1'}}) const proc = await cmd.spawn().status if (!proc.success) { diff --git a/src/parse-args.ts b/src/parse-args.ts index 8e056575..6677f4b4 100644 --- a/src/parse-args.ts +++ b/src/parse-args.ts @@ -45,7 +45,8 @@ interface Flags { sync: boolean update: boolean verbosity?: number - keepGoing: boolean + keepGoing: boolean, + unsafe: boolean } export default function(input: string[]): Args { @@ -56,7 +57,8 @@ export default function(input: string[]): Args { const flags: Flags = { sync: false, update: false, - keepGoing: false + keepGoing: false, + unsafe: false } let mode: string | undefined let dryrun: boolean | undefined @@ -89,6 +91,9 @@ export default function(input: string[]): Args { case 'update': flags.update = true break + case 'unsafe': + flags.unsafe = true + break case 'provides': if (mode) throw new UsageError({msg: 'multiple modes specified'}) console.error("%cdeprecated: %cuse pkgx --provider instead", 'color: red', 'color: initial') From ae5fa3a1008d76b2ad24ec2a1b33f70334b93197 Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sat, 11 May 2024 23:16:30 +0530 Subject: [PATCH 2/7] forgot to remove debug --- src/modes/uninstall.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modes/uninstall.ts b/src/modes/uninstall.ts index dedd7f02..d10db50e 100644 --- a/src/modes/uninstall.ts +++ b/src/modes/uninstall.ts @@ -22,7 +22,6 @@ async function uninstall(prefix: Path, pkgs: PackageRequirement[]) { for (const program of programs) { const f = prefix.join(program) if (f.isFile()) { - console.log(f) const cmd = new Deno.Command(f.string, {env: {PKGX_UNINSTALL: '1'}}) const proc = await cmd.spawn().status if (!proc.success) { From 132605aeed6faacf25ea6cb7ef590aea0caaba71 Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sat, 11 May 2024 23:21:21 +0530 Subject: [PATCH 3/7] --unsafe takes precedence, not the env Signed-off-by: Rajdeep Malakar --- src/modes/install.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/install.ts b/src/modes/install.ts index fa6e15af..397c2d42 100644 --- a/src/modes/install.ts +++ b/src/modes/install.ts @@ -7,7 +7,7 @@ const { usePantry } = hooks // * maybe impl `$XDG_BIN_HOME` export function is_unsafe(): boolean { - // $PKGX_UNSAFE_INSTALL takes precedence over the `--unsafe` flag + // `--unsafe` takes precedence over the `$PKGX_UNSAFE_INSTALL` flag const IS_UNSAFE = parseInt(Deno.env.get("PKGX_UNSAFE_INSTALL") || "0") ? true : (Deno.args.includes("--unsafe")); return IS_UNSAFE; } From 31d63d6b1cfb935d5181370f090ff63a53b4c656 Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sat, 11 May 2024 23:24:32 +0530 Subject: [PATCH 4/7] let's just warn if deleting cache fails Signed-off-by: Rajdeep Malakar --- src/modes/uninstall.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modes/uninstall.ts b/src/modes/uninstall.ts index d10db50e..2534c7b7 100644 --- a/src/modes/uninstall.ts +++ b/src/modes/uninstall.ts @@ -18,6 +18,7 @@ async function uninstall(prefix: Path, pkgs: PackageRequirement[]) { try { await Deno.remove(Path.home().join(`.cache/pkgx/envs/${parts}`).toString(), {recursive: true}) } catch (e) { + console.warn(e); } for (const program of programs) { const f = prefix.join(program) From cae08c460ecc3a844657c87fcb1e4ede057d30f2 Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sun, 12 May 2024 00:12:03 +0530 Subject: [PATCH 5/7] use pre-parsed unsafe flag Signed-off-by: Rajdeep Malakar --- src/app.ts | 2 +- src/modes/install.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app.ts b/src/app.ts index 1a6d44db..d24e9a21 100644 --- a/src/app.ts +++ b/src/app.ts @@ -74,7 +74,7 @@ export default async function({ flags, ...opts }: Args, logger_prefix?: string) case 'install': try { await ensure_pantry() - await install(await Promise.all(opts.args.map(x => parse_pkg_str(x, {latest: 'ok'})))) + await install(await Promise.all(opts.args.map(x => parse_pkg_str(x, {latest: 'ok'}))), flags.unsafe) } catch (err) { if (err instanceof AmbiguityError) { err.ctx = 'install' diff --git a/src/modes/install.ts b/src/modes/install.ts index 397c2d42..6d85ef5e 100644 --- a/src/modes/install.ts +++ b/src/modes/install.ts @@ -6,13 +6,13 @@ const { usePantry } = hooks // * maybe impl `$XDG_BIN_HOME` -export function is_unsafe(): boolean { +export function is_unsafe(unsafe: boolean): boolean { // `--unsafe` takes precedence over the `$PKGX_UNSAFE_INSTALL` flag - const IS_UNSAFE = parseInt(Deno.env.get("PKGX_UNSAFE_INSTALL") || "0") ? true : (Deno.args.includes("--unsafe")); + const IS_UNSAFE = parseInt(Deno.env.get("PKGX_UNSAFE_INSTALL") || "0") ? true : unsafe; return IS_UNSAFE; } -export default async function(pkgs: PackageRequirement[]) { +export default async function(pkgs: PackageRequirement[], unsafe: boolean) { const usrlocal = new Path("/usr/local/bin") let n = 0 @@ -36,7 +36,7 @@ export default async function(pkgs: PackageRequirement[]) { } async function write(dst: Path, pkgs: PackageRequirement[]) { - const UNSAFE = is_unsafe(); + const UNSAFE = is_unsafe(unsafe); for (const pkg of pkgs) { const programs = await usePantry().project(pkg).provides() program_loop: From 09b1e76e9e4dedabe6939c1363a4591bc7f4aece Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Sun, 12 May 2024 21:28:33 +0530 Subject: [PATCH 6/7] do mkdir -p on the expected dir instead of just the cache one (prevents nested package caches from failing) --- src/modes/install.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/install.ts b/src/modes/install.ts index 6d85ef5e..3c556172 100644 --- a/src/modes/install.ts +++ b/src/modes/install.ts @@ -55,7 +55,7 @@ export default async function(pkgs: PackageRequirement[], unsafe: boolean) { const exec = UNSAFE ? undent` ARGS="$@" pkgx_resolve() { - mkdir -p "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs" + mkdir -p "$(dirname \\"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env\\")" pkgx +${pkgstr} 1>"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" run } From b8dd655862a55185d8f65aa8e65b0967a38652d6 Mon Sep 17 00:00:00 2001 From: Rajdeep Malakar Date: Wed, 15 May 2024 00:56:19 +0530 Subject: [PATCH 7/7] improve it --- src/modes/install.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modes/install.ts b/src/modes/install.ts index 3c556172..16eea794 100644 --- a/src/modes/install.ts +++ b/src/modes/install.ts @@ -46,24 +46,29 @@ export default async function(pkgs: PackageRequirement[], unsafe: boolean) { if (program.includes("{{")) continue const pkgstr = utils.pkg.str(pkg) + const config = hooks.useConfig() if (UNSAFE) { const parts = pkgstr.split("/") parts.pop() - await Deno.mkdir(Path.home().join(`.cache/pkgx/envs/${parts.join("/")}`).toString(), {recursive: true}) + config.cache.join(`pkgx/envs/${parts.join("/")}`).mkdir("p") } //FIXME: doing `set -a` clears the args env const exec = UNSAFE ? undent` ARGS="$@" + ENV_FILE=\"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env\" + PKGX_DIR=$\{PKGX_DIR:-$HOME/.pkgx\} + pkgx_resolve() { - mkdir -p "$(dirname \\"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env\\")" - pkgx +${pkgstr} 1>"$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" + mkdir -p "$(dirname \"$ENV_FILE\")" + pkgx +${pkgstr} 1>"$ENV_FILE" run } run() { - if [[ -e "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" && -e "$\{PKGX_HOME:-$HOME/.pkgx\}/${pkgstr}/v*/bin/${program}" ]]; then + if [[ -e "$ENV_FILE" && -e "$PKGX_DIR/${pkgstr}/v*/bin/${program}" ]]; then set -a - source "$\{XDG_CACHE_DIR:-$HOME/.cache\}/pkgx/envs/${pkgstr}.env" - exec "$\{PKGX_HOME:-$HOME/.pkgx\}/${pkgstr}/v*/bin/${program}" "$ARGS" + source "$ENV_FILE" + set +a + exec "$PKGX_DIR/v*/bin/${program}" "$ARGS" else pkgx_resolve fi