Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement runtime package manager detection #164

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
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
22 changes: 21 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import { consola } from "consola";
import { name, version, description } from "../package.json";
import { addDependency, installDependencies, removeDependency } from "./api";
import { detectPackageManager } from "./package-manager";
import {
detectPackageManager,
detectRuntimePackageManager,
} from "./package-manager";

Check warning on line 10 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L10

Added line #L10 was not covered by tests

const operationArgs = {
cwd: {
Expand Down Expand Up @@ -94,6 +97,22 @@
},
});

const detectRunner = defineCommand({
meta: {
description: "Detect the current package runner using runtime checks",
},
run: () => {
const packageManager = detectRuntimePackageManager();
if (!packageManager) {
consola.error(`Cannot detect package runner`);
return process.exit(1);
}
consola.log(
`Detected package runner \`${packageManager.name}@${packageManager.version}\``,
);
},
});

Check warning on line 114 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L100-L114

Added lines #L100 - L114 were not covered by tests

const main = defineCommand({
meta: {
name,
Expand All @@ -109,6 +128,7 @@
uninstall: remove,
un: remove,
detect,
"detect-runner": detectRunner,

Check warning on line 131 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L131

Added line #L131 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we simplify to have nypm detect that displays both detection results.

},
});

Expand Down
52 changes: 46 additions & 6 deletions src/package-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { join, resolve } from "pathe";
import { env, process } from "std-env";
import { findup } from "./_utils";
import type { PackageManager } from "./types";

Expand All @@ -27,7 +28,12 @@
includeParentDirs?: boolean;

/**
* Weather to ignore argv[1] to detect script
* Weather to ignore runtime checks to detect package manager or script runner
*/
ignoreRuntime?: boolean;

/**
* Whether to ignore argv[1] to detect package manager or script runner, implied if `ignoreRuntimeChecks` is `true`
*/
ignoreArgv?: boolean;
};
Expand All @@ -37,30 +43,35 @@
name: "npm",
command: "npm",
lockFile: "package-lock.json",
packageRunner: "npx",
},
{
name: "pnpm",
command: "pnpm",
lockFile: "pnpm-lock.yaml",
files: ["pnpm-workspace.yaml"],
packageRunner: "pnpm dlx",
},
{
name: "bun",
command: "bun",
lockFile: ["bun.lockb", "bun.lock"],
packageRunner: "bunx",
},
{
name: "yarn",
command: "yarn",
majorVersion: "1",
lockFile: "yarn.lock",
packageRunner: undefined,
},
{
name: "yarn",
command: "yarn",
majorVersion: "3",
lockFile: "yarn.lock",
files: [".yarnrc.yml"],
packageRunner: "yarn dlx",
},
] as const;

Expand Down Expand Up @@ -127,10 +138,41 @@
},
);

if (!detected && !options.ignoreArgv) {
// 3. Try to detect based on dlx/exec command
if (!detected && !options.ignoreRuntime) {
return detectRuntimePackageManager(options);
}

Check warning on line 143 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L142-L143

Added lines #L142 - L143 were not covered by tests

return detected;
}

export function detectRuntimePackageManager(
options: DetectPackageManagerOptions = {},
): PackageManager | undefined {
const userAgent = env["npm_config_user_agent"];

Check warning on line 151 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L149-L151

Added lines #L149 - L151 were not covered by tests

const engine = userAgent?.split(" ")?.[0] ?? "";

Check warning on line 153 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L153

Added line #L153 was not covered by tests

const [name, version = "0.0.0"] = engine.split("/");

Check warning on line 155 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L155

Added line #L155 was not covered by tests

if (name) {
const majorVersion = version.split(".")[0];
const packageManager =
packageManagers.find(
(pm) => pm.name === name && pm.majorVersion === majorVersion,
) || packageManagers.find((pm) => pm.name === name);
if (packageManager) {
return {
...packageManager,
command: name,
version,
majorVersion,
};
}
}
if (!options.ignoreArgv) {

Check warning on line 172 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L157-L172

Added lines #L157 - L172 were not covered by tests
// Fallback to detecting based on argv
// https://github.com/unjs/nypm/issues/116
const scriptArg = process.argv[1];
const scriptArg = process.argv?.[1];

Check warning on line 175 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L175

Added line #L175 was not covered by tests
if (scriptArg) {
for (const packageManager of packageManagers) {
// Check /.[name] or /[name] in path
Expand All @@ -141,6 +183,4 @@
}
}
}

return detected;
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type PackageManagerName = "npm" | "yarn" | "pnpm" | "bun";
export type PackageManager = {
name: PackageManagerName;
command: string;
packageRunner?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might make it an array. It is a map of known args => package runner

version?: string;
majorVersion?: string;
lockFile?: string | string[];
Expand Down