fix(desktop): handle quoted paths with spaces in extension commands (#6430)
Signed-off-by: Abhijay007 <Abhijay007j@gmail.com>
This commit is contained in:
@@ -251,6 +251,13 @@ describe('Extension Utils', () => {
|
|||||||
"java -classpath '/path/with spaces/lib.jar' Main",
|
"java -classpath '/path/with spaces/lib.jar' Main",
|
||||||
{ cmd: 'java', args: ['-classpath', '/path/with spaces/lib.jar', 'Main'] },
|
{ cmd: 'java', args: ['-classpath', '/path/with spaces/lib.jar', 'Main'] },
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'"/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java" -classpath "/path/with spaces/lib.jar" Main',
|
||||||
|
{
|
||||||
|
cmd: '/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java',
|
||||||
|
args: ['-classpath', '/path/with spaces/lib.jar', 'Main'],
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'node --max-old-space-size=4096 app.js',
|
'node --max-old-space-size=4096 app.js',
|
||||||
{ cmd: 'node', args: ['--max-old-space-size=4096', 'app.js'] },
|
{ cmd: 'node', args: ['--max-old-space-size=4096', 'app.js'] },
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { parse, quote } from 'shell-quote';
|
import type { FixedExtensionEntry } from '../../ConfigContext';
|
||||||
|
import type { ExtensionConfig } from '../../../api/types.gen';
|
||||||
|
import { parse as parseShellQuote, quote as quoteShell } from 'shell-quote';
|
||||||
|
|
||||||
// Default extension timeout in seconds
|
// Default extension timeout in seconds
|
||||||
// TODO: keep in sync with rust better
|
// TODO: keep in sync with rust better
|
||||||
@@ -17,9 +19,6 @@ export function nameToKey(name: string): string {
|
|||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
import { FixedExtensionEntry } from '../../ConfigContext';
|
|
||||||
import { ExtensionConfig } from '../../../api/types.gen';
|
|
||||||
|
|
||||||
export interface ExtensionFormData {
|
export interface ExtensionFormData {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -105,7 +104,7 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
|
|||||||
extension.type === 'platform'
|
extension.type === 'platform'
|
||||||
? 'stdio'
|
? 'stdio'
|
||||||
: extension.type,
|
: extension.type,
|
||||||
cmd: extension.type === 'stdio' ? quote([extension.cmd, ...extension.args]) : undefined,
|
cmd: extension.type === 'stdio' ? quoteShell([extension.cmd, ...extension.args]) : undefined,
|
||||||
endpoint:
|
endpoint:
|
||||||
extension.type === 'streamable_http' || extension.type === 'sse'
|
extension.type === 'streamable_http' || extension.type === 'sse'
|
||||||
? (extension.uri ?? undefined)
|
? (extension.uri ?? undefined)
|
||||||
@@ -170,8 +169,25 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function splitCmdAndArgs(str: string): { cmd: string; args: string[] } {
|
export function splitCmdAndArgs(str: string): { cmd: string; args: string[] } {
|
||||||
const parts = parse(str.trim()).filter((p): p is string => typeof p === 'string');
|
const trimmed = str.trim();
|
||||||
return { cmd: parts[0] || '', args: parts.slice(1) };
|
if (!trimmed) {
|
||||||
|
return { cmd: '', args: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = parseShellQuote(trimmed);
|
||||||
|
const words = parsed.filter((item): item is string => typeof item === 'string').map(String);
|
||||||
|
|
||||||
|
const cmd = words[0] || '';
|
||||||
|
const args = words.slice(1);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cmd,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function combineCmdAndArgs(cmd: string, args: string[]): string {
|
||||||
|
return quoteShell([cmd, ...args]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractCommand(link: string): string {
|
export function extractCommand(link: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user