Skip to content

Commit 579d303

Browse files
authored
fix: runtime detection on Windows (#785)
1 parent b434987 commit 579d303

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apify-cli",
3-
"version": "0.21.4",
3+
"version": "0.21.5",
44
"description": "Apify command-line interface (CLI) helps you manage the Apify cloud platform and develop, build, and deploy Apify Actors.",
55
"exports": "./dist/index.js",
66
"types": "./dist/index.d.ts",

src/lib/exec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type SpawnOptions, type SpawnOptionsWithoutStdio, spawn } from 'node:child_process';
2-
import { isAbsolute } from 'node:path';
32

3+
import { normalizeExecutablePath } from './hooks/runtimes/utils.js';
44
import { run } from './outputs.js';
55

66
const windowsOptions: SpawnOptions = {
@@ -12,7 +12,7 @@ const windowsOptions: SpawnOptions = {
1212
* Run child process and returns stdout and stderr to user stout
1313
*/
1414
const spawnPromised = async (cmd: string, args: string[], opts: SpawnOptionsWithoutStdio) => {
15-
const escapedCommand = isAbsolute(cmd) && process.platform === 'win32' ? `"${cmd}"` : cmd;
15+
const escapedCommand = normalizeExecutablePath(cmd);
1616

1717
// NOTE: Pipes stderr, stdout to main process
1818
const childProcess = spawn(escapedCommand, args, {

src/lib/hooks/runtimes/javascript.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { execa } from 'execa';
55
import which from 'which';
66

77
import type { Runtime } from '../useCwdProject.js';
8+
import { normalizeExecutablePath } from './utils.js';
89

910
const cwdCache = new Map<string, Option<Runtime>>();
1011

@@ -55,7 +56,7 @@ export async function useJavaScriptRuntime(cwd = process.cwd()): Promise<Option<
5556

5657
for (const [runtime, args] of Object.entries(runtimesToCheck) as [keyof typeof runtimesToCheck, string[]][]) {
5758
try {
58-
const runtimePath = await which(runtime);
59+
const runtimePath = normalizeExecutablePath(await which(runtime));
5960

6061
const version = await getRuntimeVersion(runtimePath, args);
6162

@@ -67,7 +68,7 @@ export async function useJavaScriptRuntime(cwd = process.cwd()): Promise<Option<
6768

6869
// For npm, we also fetch the npm version
6970
if (runtime === 'node') {
70-
const npmPath = await which('npm').catch(() => null);
71+
const npmPath = normalizeExecutablePath(await which('npm').catch(() => null));
7172

7273
if (npmPath) {
7374
res.pmPath = npmPath;

src/lib/hooks/runtimes/python.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { execa } from 'execa';
88
import which from 'which';
99

1010
import type { Runtime } from '../useCwdProject.js';
11+
import { normalizeExecutablePath } from './utils.js';
1112

1213
const cwdCache = new Map<string, Option<Runtime>>();
1314

@@ -51,12 +52,15 @@ export async function usePythonRuntime({
5152
const pathParts = isWindows ? ['Scripts', 'python.exe'] : ['bin', 'python3'];
5253

5354
let fullPythonVenvPath;
55+
5456
if (process.env.VIRTUAL_ENV) {
5557
fullPythonVenvPath = join(process.env.VIRTUAL_ENV, ...pathParts);
5658
} else {
5759
fullPythonVenvPath = join(cwd, '.venv', ...pathParts);
5860
}
5961

62+
fullPythonVenvPath = normalizeExecutablePath(fullPythonVenvPath);
63+
6064
try {
6165
await access(fullPythonVenvPath);
6266

@@ -84,7 +88,7 @@ export async function usePythonRuntime({
8488

8589
for (const fallback of fallbacks) {
8690
try {
87-
const fullPath = await which(fallback);
91+
const fullPath = normalizeExecutablePath(await which(fallback));
8892

8993
const version = await getPythonVersion(fullPath);
9094

src/lib/hooks/runtimes/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { isAbsolute } from 'node:path';
2+
import process from 'node:process';
3+
4+
export function normalizeExecutablePath(path: string): string;
5+
export function normalizeExecutablePath(path: string | null): string | null;
6+
export function normalizeExecutablePath(path: string | null) {
7+
if (!path) {
8+
return null;
9+
}
10+
11+
// Already escaped
12+
if (path.startsWith('"')) {
13+
return path;
14+
}
15+
16+
if (process.platform === 'win32') {
17+
if (isAbsolute(path)) {
18+
return `"${path}"`;
19+
}
20+
21+
return path;
22+
}
23+
24+
return path;
25+
}

0 commit comments

Comments
 (0)