@@ -6,7 +6,6 @@ import { PassThrough } from "node:stream";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DefaultPackageManager, type ProgressEvent, type ResolvedResource } from "../src/core/package-manager.js";
|
||||
import { SettingsManager } from "../src/core/settings-manager.js";
|
||||
import { resolveSpawnCommand } from "../src/utils/child-process.js";
|
||||
|
||||
function normalizeForMatch(value: string): string {
|
||||
return value.replace(/\\/g, "/");
|
||||
@@ -617,59 +616,19 @@ Content`,
|
||||
});
|
||||
});
|
||||
|
||||
describe("windows command spawning", () => {
|
||||
it("should keep unresolved executables as argv commands", () => {
|
||||
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
|
||||
describe("command spawning", () => {
|
||||
it("should preserve argv entries containing spaces", () => {
|
||||
const managerWithInternals = packageManager as unknown as {
|
||||
runCommandSync(command: string, args: string[]): string;
|
||||
};
|
||||
const valueWithSpace = "C:\\Users\\A B\\.pi\\npm";
|
||||
const output = managerWithInternals.runCommandSync(process.execPath, [
|
||||
"-e",
|
||||
"console.log(process.argv[1])",
|
||||
valueWithSpace,
|
||||
]);
|
||||
|
||||
const resolved = resolveSpawnCommand("git", ["clone", "repo", "C:\\Users\\A B\\repo"], {
|
||||
env: { PATH: tempDir },
|
||||
});
|
||||
|
||||
expect(resolved).toEqual({ command: "git", args: ["clone", "repo", "C:\\Users\\A B\\repo"] });
|
||||
});
|
||||
|
||||
it("should prefer Windows executables over command scripts", () => {
|
||||
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
|
||||
const binDir = join(tempDir, "bin");
|
||||
mkdirSync(binDir, { recursive: true });
|
||||
writeFileSync(join(binDir, "npm.exe"), "");
|
||||
writeFileSync(join(binDir, "npm.cmd"), "@echo off\r\n");
|
||||
|
||||
const args = ["install", "pkg", "--prefix", "C:\\Users\\A B\\.pi\\npm"];
|
||||
const resolved = resolveSpawnCommand("npm", args, { env: { PATH: binDir } });
|
||||
|
||||
expect(resolved).toEqual({ command: join(binDir, "npm.exe"), args });
|
||||
});
|
||||
|
||||
it("should resolve npm command shims to their Node entrypoint without a shell", () => {
|
||||
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
|
||||
const binDir = join(tempDir, "node-bin");
|
||||
const npmCli = join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
||||
mkdirSync(join(binDir, "node_modules", "npm", "bin"), { recursive: true });
|
||||
writeFileSync(join(binDir, "node.exe"), "");
|
||||
writeFileSync(npmCli, "");
|
||||
writeFileSync(
|
||||
join(binDir, "npm.cmd"),
|
||||
'@ECHO off\r\nSET "dp0=%~dp0"\r\nSET "_prog=%dp0%\\node.exe"\r\nendLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\node_modules\\npm\\bin\\npm-cli.js" %*\r\n',
|
||||
);
|
||||
|
||||
const args = ["install", "pkg", "--prefix", "C:\\Users\\A B\\.pi\\npm"];
|
||||
const resolved = resolveSpawnCommand("npm", args, { env: { PATH: binDir } });
|
||||
|
||||
expect(resolved).toEqual({ command: join(binDir, "node.exe"), args: [npmCli, ...args] });
|
||||
});
|
||||
|
||||
it("should reject unrecognized Windows command scripts instead of using cmd.exe", () => {
|
||||
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
|
||||
const binDir = join(tempDir, "bin");
|
||||
mkdirSync(binDir, { recursive: true });
|
||||
writeFileSync(join(binDir, "npm.cmd"), "@echo off\r\necho %*\r\n");
|
||||
|
||||
expect(() =>
|
||||
resolveSpawnCommand("npm", ["install", "pkg"], {
|
||||
env: { PATH: binDir },
|
||||
}),
|
||||
).toThrow("Refusing to run Windows command shim without a shell");
|
||||
expect(output).toBe(valueWithSpace);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user