Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion packages/cli/src/runtime-install.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ const ephemeral: RuntimePaths = {
serviceTemplate: join(npxCli, 'packaging/systemd/codor.service'),
};

const dlxCli = join(
HOME,
'.local/share/pnpm/pnpm-cache/dlx/abcd1234ef567890/1706000000000/node_modules/@richhardry/codor/node_modules/@codor/cli',
);
const dlxEphemeral: RuntimePaths = {
root: dlxCli,
layout: 'installed-package',
cliEntrypoint: join(dlxCli, 'dist/index.js'),
staticRoot: join(dlxCli, 'runtime/web'),
serviceTemplate: join(dlxCli, 'packaging/systemd/codor.service'),
};

const checkoutRoot = join(HOME, 'git/codor');
const checkout: RuntimePaths = {
root: checkoutRoot,
Expand Down Expand Up @@ -95,8 +107,9 @@ function fakeIo(options: { existing?: string; failCopy?: boolean; incompleteCopy

// harn:assume setup-installs-durable-per-user-runtime-atomically ref=durable-runtime-install-regression
describe('isEphemeralRuntime', () => {
it('flags npx cache and temp paths, not stable locations', () => {
it('flags npx cache, pnpm dlx cache, and temp paths, not stable locations', () => {
expect(isEphemeralRuntime(join(HOME, '.npm/_npx/abcd1234'))).toBe(true);
expect(isEphemeralRuntime(join(HOME, '.local/share/pnpm/pnpm-cache/dlx/abcd1234ef567890/1706000000000'))).toBe(true);
expect(isEphemeralRuntime(join(tmpdir(), 'x'))).toBe(true);
expect(isEphemeralRuntime('/opt/codor')).toBe(false);
expect(isEphemeralRuntime(checkoutRoot)).toBe(false);
Expand All @@ -117,6 +130,17 @@ describe('installDurableRuntime', () => {
expect(result.runtime.cliEntrypoint).not.toContain('_npx');
});

it('stages, validates, and swaps an ephemeral pnpm dlx runtime into ~/.codor/runtime', () => {
const { io, moves } = fakeIo();
const result = installDurableRuntime({ runtime: dlxEphemeral, dataDir: DATA, version: '0.10.0', io });
expect(result.action).toBe('installed');
expect(result.location).toBe(LOCATION);
expect(moves).toContainEqual([`${LOCATION}.staging`, LOCATION]);
// Rooted at the durable location, not the dlx cache the source runtime lived in.
expect(result.runtime.cliEntrypoint).toContain(LOCATION);
expect(result.runtime.cliEntrypoint).not.toContain('dlx');
});

it('uses a source checkout in place without copying', () => {
const { io, copies } = fakeIo();
const result = installDurableRuntime({ runtime: checkout, dataDir: DATA, version: '0.10.0', io });
Expand Down
12 changes: 9 additions & 3 deletions packages/cli/src/runtime-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ export function durableRuntimeLocation(dataDir: string): string {
return join(dataDir, 'runtime');
}

/** A path is ephemeral when it lives in an npx cache or the OS temp directory. */
/** A path is ephemeral when it lives in an npx cache, a pnpm dlx cache, or the OS temp directory. */
export function isEphemeralRuntime(path: string): boolean {
const temp = tmpdir();
return path.includes(`${sep}_npx${sep}`) || path === temp || path.startsWith(temp + sep);
return (
path.includes(`${sep}_npx${sep}`) ||
path.includes(`${sep}dlx${sep}`) ||
path === temp ||
path.startsWith(temp + sep)
);
}

function installedWrapperPackageJson(location: string): string {
Expand All @@ -65,7 +70,8 @@ function installedWrapperPackageJson(location: string): string {
// harn:assume setup-installs-durable-per-user-runtime-atomically ref=durable-runtime-install
/** The self-contained module tree the running CLI resolves against, and whether
* it is already durable (a source checkout or a stable install) or ephemeral
* (an npx cache / temp dir that must be copied before a service points at it). */
* (an npx cache, a pnpm dlx cache, or a temp dir that must be copied before a
* service points at it). */
export function resolveInstallSource(runtime: RuntimePaths): { installRoot: string; nodeModules: string; durable: boolean } {
if (runtime.layout === 'source-checkout') {
return { installRoot: runtime.root, nodeModules: join(runtime.root, 'node_modules'), durable: true };
Expand Down