diff --git a/README.md b/README.md
index 5f163fd40..23630d131 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,8 @@ Install ESP-IDF and ESP-IDF Tools by following the [install tutorial](./docs/tut
> **NOTE:** Please take a look at [Working with multiple projects](./docs/MULTI_PROJECTS.md) for more information. Default is User settings.
-- On the first time using the extension, press F1 to show the Visual Studio Code Command Palette and type **ESP-IDF: Configure ESP-IDF Extension** to open the extension configuration wizard. This will install ESP-IDF, ESP-IDF tools, create a virtual python environment with ESP-IDF and this extension python packages and configure the extension settings with these values. **NOTE: Make sure that there is no spaces in any configured path since [ESP-IDF build system doesn't support spaces yet.](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#start-a-project)**.
+- On the first time using the extension, press F1 to show the Visual Studio Code Command Palette and type **ESP-IDF: Configure ESP-IDF extension** to open the extension configuration wizard. This will install ESP-IDF, ESP-IDF tools, create a virtual python environment with ESP-IDF and this extension python packages and configure the extension settings with these values.
+ > **NOTE:** For versions of ESP-IDF < 5.0, spaces are not supported inside configured paths.
> **NOTE:** Please take a look at [Install tutorial](./docs/tutorial/install.md) documentation or the [Setup documentation](./docs/SETUP.md) for details about extension setup and configuration.
diff --git a/docs/SETUP.md b/docs/SETUP.md
index d83cb14d8..237a56def 100644
--- a/docs/SETUP.md
+++ b/docs/SETUP.md
@@ -55,7 +55,7 @@ so make sure that if using an existing python virtual environment that installin
> **NOTE:** Currently the python package `pygdbmi` used by the debug adapter still depends on some Python 2.7 libraries (libpython2.7.so.1.0) so make sure that the Python executable in `idf.pythonBinPath` you use contains these libraries. This will be dropped in later versions of ESP-IDF.
-> **NOTE:** Make sure that `IDF_PATH` and `IDF_TOOLS_PATH` doesn't have any spaces to avoid any build issues since [ESP-IDF Build System does NOT support spaces yet.](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#start-a-project).
+> **NOTE**: If you want to use an ESP-IDF version < 5.0, make sure that IDF_PATH and IDF_TOOLS_PATH don't have any spaces since they were no suported in previous versions.
After choosing any of the previous options, a status page is displayed showing ESP-IDF, tools and python environment setup progress status. When the setup is finished, a message is shown that "All settings have been configured. You can close this window."
@@ -114,8 +114,6 @@ where:
**DO NOT USE ~, $HOME OR %USERPROFILE% ENVIRONMENT VARIABLES ARE NOT RESOLVED IN THIS CONFIGURATION SETTINGS. You must use ${env:HOME} instead of \$HOME (Linux/MacOS) or %HOME% (Windows).**
-> **NOTE:** Make sure that your configurations settings doesn't have any spaces to avoid any build issues.
-
Make sure to install the extension and extension debug adapter Python requirements by running the following commands in your terminal:
```
diff --git a/docs/tutorial/install.md b/docs/tutorial/install.md
index a39619b30..74c79a4af 100644
--- a/docs/tutorial/install.md
+++ b/docs/tutorial/install.md
@@ -26,9 +26,7 @@
- Pick an ESP-IDF version to download (or find ESP-IDF in your system) and the python executable to create the virtual environment.
- Choose the location for ESP-IDF Tools and python virtual environment (also known as `IDF_TOOLS_PATH`) which is `$HOME\.espressif` on MacOS/Linux and `%USERPROFILE%\.espressif` on Windows by default.
> **NOTE:** Windows users don't need to select a python executable since it is part of the setup.
-
-> **NOTE:** Make sure that `IDF_PATH` and `IDF_TOOLS_PATH` doesn't have any spaces to avoid any build issues.
-
+ > **NOTE:** Make sure that `IDF_TOOLS_PATH` doesn't have any spaces to avoid any build issues.
@@ -60,7 +58,7 @@
-> **NOTE**: The advance mode allows the user to choose to use existing ESP-IDF tools by manually entering each ESP-IDF tool absolute path. Make sure each ESP-IDF tool path doesn't have any spaces.
+> **NOTE**: > The advance mode allows the user to choose to use existing ESP-IDF tools by manually entering each ESP-IDF tool absolute path. Again, if chose an ESP-IDF version < 5.0, make sure each ESP-IDF tool path doesn't have any spaces, since they were no suported in previous versions..
15. Now that the extension setup is finally done, check the [Basic use](./basic_use.md) to learn how to use the SDK Configuration editor, build, flash and monitor your Espressif device.
diff --git a/src/PlatformInformation.ts b/src/PlatformInformation.ts
index 6862c7e61..bf192845f 100644
--- a/src/PlatformInformation.ts
+++ b/src/PlatformInformation.ts
@@ -80,8 +80,10 @@ export class PlatformInformation {
}
public static GetUnixArchitecture(): Promise {
+ const command = "uname";
+ const args = ["-m"];
return utils
- .execChildProcess("uname -m", utils.extensionContext.extensionPath)
+ .execChildProcess(command, args, utils.extensionContext.extensionPath)
.then((architecture) => {
if (architecture) {
return architecture.trim();
@@ -90,11 +92,10 @@ export class PlatformInformation {
}
private static GetWindowsArchitecture(): Promise {
+ const command = "wmic";
+ const args = ["os", "get", "osarchitecture"];
return utils
- .execChildProcess(
- "wmic os get osarchitecture",
- utils.extensionContext.extensionPath
- )
+ .execChildProcess(command, args, utils.extensionContext.extensionPath)
.then((architecture) => {
if (architecture) {
const archArray: string[] = architecture.split(os.EOL);
diff --git a/src/build/buildTask.ts b/src/build/buildTask.ts
index ff6e4753b..031e744ee 100644
--- a/src/build/buildTask.ts
+++ b/src/build/buildTask.ts
@@ -28,23 +28,35 @@ import { selectedDFUAdapterId } from "../flash/dfu";
export class BuildTask {
public static isBuilding: boolean;
private buildDirPath: string;
- private curWorkspace: vscode.Uri;
+ private currentWorkspace: vscode.Uri;
private idfPathDir: string;
private adapterTargetName: string;
+ private processOptions: vscode.ProcessExecutionOptions;
+ private modifiedEnv: { [key: string]: string };
+ private pythonBinPath: string;
- constructor(workspace: vscode.Uri) {
- this.curWorkspace = workspace;
+ constructor(workspaceUri: vscode.Uri) {
+ this.currentWorkspace = workspaceUri;
this.idfPathDir = idfConf.readParameter(
"idf.espIdfPath",
- workspace
+ workspaceUri
) as string;
this.adapterTargetName = idfConf.readParameter(
"idf.adapterTargetName",
- workspace
+ workspaceUri
) as string;
this.buildDirPath = idfConf.readParameter(
"idf.buildPath",
- workspace
+ workspaceUri
+ ) as string;
+ this.modifiedEnv = appendIdfAndToolsToPath(workspaceUri);
+ this.processOptions = {
+ cwd: this.buildDirPath,
+ env: this.modifiedEnv,
+ };
+ this.pythonBinPath = idfConf.readParameter(
+ "idf.pythonBinPath",
+ workspaceUri
) as string;
}
@@ -55,45 +67,13 @@ export class BuildTask {
private async saveBeforeBuild() {
const shallSaveBeforeBuild = idfConf.readParameter(
"idf.saveBeforeBuild",
- this.curWorkspace
+ this.currentWorkspace
);
if (shallSaveBeforeBuild) {
await vscode.workspace.saveAll();
}
}
- public getShellExecution(
- args: string[],
- options?: vscode.ShellExecutionOptions
- ) {
- return new vscode.ShellExecution(`cmake ${args.join(" ")}`, options);
- }
-
- public getNinjaShellExecution(
- args: string[],
- options?: vscode.ShellExecutionOptions
- ) {
- return new vscode.ShellExecution(`ninja ${args.join(" ")}`, options);
- }
-
- public dfuShellExecution(options?: vscode.ShellExecutionOptions) {
- const pythonBinPath = idfConf.readParameter(
- "idf.pythonBinPath",
- this.curWorkspace
- ) as string;
- return new vscode.ShellExecution(
- `${pythonBinPath} ${join(
- this.idfPathDir,
- "tools",
- "mkdfu.py"
- )} write -o ${join(this.buildDirPath, "dfu.bin")} --json ${join(
- this.buildDirPath,
- "flasher_args.json"
- )} --pid ${selectedDFUAdapterId(this.adapterTargetName)}`,
- options
- );
- }
-
public async build() {
try {
await this.saveBeforeBuild();
@@ -107,17 +87,16 @@ export class BuildTask {
throw new Error("ALREADY_BUILDING");
}
this.building(true);
- const modifiedEnv = appendIdfAndToolsToPath(this.curWorkspace);
await ensureDir(this.buildDirPath);
const canAccessCMake = await isBinInPath(
"cmake",
- this.curWorkspace.fsPath,
- modifiedEnv
+ this.currentWorkspace.fsPath,
+ this.modifiedEnv
);
const canAccessNinja = await isBinInPath(
"ninja",
- this.curWorkspace.fsPath,
- modifiedEnv
+ this.currentWorkspace.fsPath,
+ this.modifiedEnv
);
const cmakeCachePath = join(this.buildDirPath, "CMakeCache.txt");
@@ -127,33 +106,13 @@ export class BuildTask {
throw new Error("CMake or Ninja executables not found");
}
- const options: vscode.ShellExecutionOptions = {
- cwd: this.buildDirPath,
- env: modifiedEnv,
- };
- const shellExecutablePath = idfConf.readParameter(
- "idf.customTerminalExecutable",
- this.curWorkspace
- ) as string;
- const shellExecutableArgs = idfConf.readParameter(
- "idf.customTerminalExecutableArgs",
- this.curWorkspace
- ) as string[];
- if (shellExecutablePath) {
- options.executable = shellExecutablePath;
- }
-
- if (shellExecutableArgs && shellExecutableArgs.length) {
- options.shellArgs = shellExecutableArgs;
- }
-
- const curWorkspaceFolder = vscode.workspace.workspaceFolders.find(
- (w) => w.uri === this.curWorkspace
+ const currentWorkspaceFolder = vscode.workspace.workspaceFolders.find(
+ (w) => w.uri === this.currentWorkspace
);
const notificationMode = idfConf.readParameter(
"idf.notificationMode",
- this.curWorkspace
+ this.currentWorkspace
) as string;
const showTaskOutput =
notificationMode === idfConf.NotificationMode.All ||
@@ -164,7 +123,7 @@ export class BuildTask {
if (!cmakeCacheExists) {
let compilerArgs = (idfConf.readParameter(
"idf.cmakeCompilerArgs",
- this.curWorkspace
+ this.currentWorkspace
) as Array) || [
"-G",
"Ninja",
@@ -178,7 +137,7 @@ export class BuildTask {
compilerArgs.push("-B", this.buildDirPath);
if (compilerArgs.indexOf("-S") === -1) {
- compilerArgs.push("-S", this.curWorkspace.fsPath);
+ compilerArgs.push("-S", this.currentWorkspace.fsPath);
}
const sdkconfigDefaults =
@@ -196,7 +155,7 @@ export class BuildTask {
const enableCCache = idfConf.readParameter(
"idf.enableCCache",
- this.curWorkspace
+ this.currentWorkspace
) as boolean;
if (enableCCache && compilerArgs && compilerArgs.length) {
const indexOfCCache = compilerArgs.indexOf("-DCCACHE_ENABLE=1");
@@ -204,7 +163,7 @@ export class BuildTask {
compilerArgs.push("-DCCACHE_ENABLE=1");
}
}
- const compileExecution = this.getShellExecution(compilerArgs, options);
+ const compileExecution = new vscode.ProcessExecution(canAccessCMake, compilerArgs, this.processOptions);
const compilePresentationOptions = {
reveal: showTaskOutput,
showReuseMessage: false,
@@ -217,7 +176,7 @@ export class BuildTask {
command: "ESP-IDF Compile",
taskId: "idf-compile-task",
},
- curWorkspaceFolder || vscode.TaskScope.Workspace,
+ currentWorkspaceFolder || vscode.TaskScope.Workspace,
"ESP-IDF Compile",
compileExecution,
["espIdf"],
@@ -227,10 +186,11 @@ export class BuildTask {
}
const buildArgs =
- (idfConf.readParameter("idf.ninjaArgs", this.curWorkspace) as Array<
+ (idfConf.readParameter("idf.ninjaArgs", this.currentWorkspace) as Array<
string
>) || [];
- const buildExecution = this.getNinjaShellExecution(buildArgs, options);
+ const ninjaCommand = "ninja";
+ const buildExecution = new vscode.ProcessExecution(ninjaCommand, buildArgs, this.processOptions);
const buildPresentationOptions = {
reveal: showTaskOutput,
showReuseMessage: false,
@@ -239,7 +199,7 @@ export class BuildTask {
} as vscode.TaskPresentationOptions;
TaskManager.addTask(
{ type: "esp-idf", command: "ESP-IDF Build", taskId: "idf-build-task" },
- curWorkspaceFolder || vscode.TaskScope.Workspace,
+ currentWorkspaceFolder || vscode.TaskScope.Workspace,
"ESP-IDF Build",
buildExecution,
["espIdf"],
@@ -249,36 +209,16 @@ export class BuildTask {
public async buildDfu() {
this.building(true);
- const modifiedEnv = appendIdfAndToolsToPath(this.curWorkspace);
+ const modifiedEnv = appendIdfAndToolsToPath(this.currentWorkspace);
await ensureDir(this.buildDirPath);
- const options: vscode.ShellExecutionOptions = {
- cwd: this.curWorkspace.fsPath,
- env: modifiedEnv,
- };
-
- const shellExecutablePath = idfConf.readParameter(
- "idf.customTerminalExecutable",
- this.curWorkspace
- ) as string;
- const shellExecutableArgs = idfConf.readParameter(
- "idf.customTerminalExecutableArgs",
- this.curWorkspace
- ) as string[];
- if (shellExecutablePath) {
- options.executable = shellExecutablePath;
- }
- if (shellExecutableArgs && shellExecutableArgs.length) {
- options.shellArgs = shellExecutableArgs;
- }
-
- const curWorkspaceFolder = vscode.workspace.workspaceFolders.find(
- (w) => w.uri === this.curWorkspace
+ const currentWorkspaceFolder = vscode.workspace.workspaceFolders.find(
+ (w) => w.uri === this.currentWorkspace
);
const notificationMode = idfConf.readParameter(
"idf.notificationMode",
- this.curWorkspace
+ this.currentWorkspace
) as string;
const showTaskOutput =
notificationMode === idfConf.NotificationMode.All ||
@@ -286,7 +226,17 @@ export class BuildTask {
? vscode.TaskRevealKind.Always
: vscode.TaskRevealKind.Silent;
- const writeExecution = this.dfuShellExecution(options);
+ const args = [
+ join(this.idfPathDir, "tools", "mkdfu.py"),
+ "write",
+ "-o",
+ join(this.buildDirPath, "dfu.bin"),
+ "--json",
+ join(this.buildDirPath, "flasher_args.json"),
+ "--pid",
+ selectedDFUAdapterId(this.adapterTargetName)
+ ];
+ const writeExecution = new vscode.ProcessExecution(this.pythonBinPath, args, this.processOptions);
const buildPresentationOptions = {
reveal: showTaskOutput,
showReuseMessage: false,
@@ -299,7 +249,7 @@ export class BuildTask {
command: "ESP-IDF Write DFU.bin",
taskId: "idf-write-dfu-task",
},
- curWorkspaceFolder || vscode.TaskScope.Workspace,
+ currentWorkspaceFolder || vscode.TaskScope.Workspace,
"ESP-IDF Write DFU.bin",
writeExecution,
["espIdf"],
diff --git a/src/common/abstractCloning.ts b/src/common/abstractCloning.ts
index 61d781c7e..cb9046b53 100644
--- a/src/common/abstractCloning.ts
+++ b/src/common/abstractCloning.ts
@@ -246,12 +246,14 @@ export class AbstractCloning {
"esp-components",
];
await execChildProcess(
- `${this.gitBinPath} submodule init`,
+ this.gitBinPath,
+ ["submodule", "init"],
repoPath,
OutputChannel.init()
);
const gitModules = await execChildProcess(
- `${this.gitBinPath} config -f .gitmodules --list`,
+ this.gitBinPath,
+ ["config", "-f", ".gitmodules", "--list"],
repoPath,
OutputChannel.init()
);
@@ -297,7 +299,8 @@ export class AbstractCloning {
}
await execChildProcess(
- `${this.gitBinPath} config submodule.${subPath}.url ${subUrl}`,
+ this.gitBinPath,
+ ["config", `submodule.${subPath}.url`, subUrl],
repoPath,
OutputChannel.init()
);
diff --git a/src/customTasks/customTaskProvider.ts b/src/customTasks/customTaskProvider.ts
index acffaa10c..5c071536f 100644
--- a/src/customTasks/customTaskProvider.ts
+++ b/src/customTasks/customTaskProvider.ts
@@ -17,8 +17,8 @@
*/
import {
- ShellExecution,
- ShellExecutionOptions,
+ ProcessExecution,
+ ProcessExecutionOptions,
TaskPanelKind,
TaskPresentationOptions,
TaskRevealKind,
@@ -40,68 +40,57 @@ export enum CustomTaskType {
export class CustomTask {
public static isRunningCustomTask: boolean;
+ private processOptions: ProcessExecutionOptions;
+ private buildDirPath: string;
+ private currentWorkspace: Uri;
+ private modifiedEnv: { [key: string]: string };
- constructor(private currentWorkspace: Uri) {}
+ constructor(private workspaceUri: Uri) {
+ this.currentWorkspace = workspaceUri;
+ this.buildDirPath = readParameter(
+ "idf.buildPath",
+ this.currentWorkspace
+ ) as string;
+ this.modifiedEnv = appendIdfAndToolsToPath(workspaceUri);
+ this.processOptions = {
+ cwd: this.buildDirPath,
+ env: this.modifiedEnv,
+ };
+ }
public isRunning(flag: boolean) {
CustomTask.isRunningCustomTask = flag;
}
- public getProcessExecution(
- cmdString: string,
- options: ShellExecutionOptions
- ) {
- return new ShellExecution(`${cmdString}`, options);
- }
-
public addCustomTask(taskType: CustomTaskType) {
- let cmd: string;
+ let command: string;
let taskName: string;
switch (taskType) {
case CustomTaskType.PreBuild:
- cmd = readParameter("idf.preBuildTask", this.currentWorkspace);
+ command = readParameter("idf.preBuildTask", this.currentWorkspace);
taskName = "Pre Build";
break;
case CustomTaskType.PostBuild:
- cmd = readParameter("idf.postBuildTask", this.currentWorkspace);
+ command = readParameter("idf.postBuildTask", this.currentWorkspace);
taskName = "Post Build";
break;
case CustomTaskType.PreFlash:
- cmd = readParameter("idf.preFlashTask", this.currentWorkspace);
+ command = readParameter("idf.preFlashTask", this.currentWorkspace);
taskName = "Pre Flash";
break;
case CustomTaskType.PostFlash:
- cmd = readParameter("idf.postFlashTask", this.currentWorkspace);
+ command = readParameter("idf.postFlashTask", this.currentWorkspace);
taskName = "Post Flash";
break;
case CustomTaskType.Custom:
- cmd = readParameter("idf.customTask", this.currentWorkspace);
+ command = readParameter("idf.customTask", this.currentWorkspace);
taskName = "Custom task";
default:
break;
}
- if (!cmd) {
+ if (!command) {
return;
}
- const modifiedEnv = appendIdfAndToolsToPath(this.currentWorkspace);
- const options: ShellExecutionOptions = {
- cwd: this.currentWorkspace.fsPath,
- env: modifiedEnv,
- };
- const shellExecutablePath = readParameter(
- "idf.customTerminalExecutable",
- this.currentWorkspace
- ) as string;
- const shellExecutableArgs = readParameter(
- "idf.customTerminalExecutableArgs",
- this.currentWorkspace
- ) as string[];
- if (shellExecutablePath) {
- options.executable = shellExecutablePath;
- }
- if (shellExecutableArgs && shellExecutableArgs.length) {
- options.shellArgs = shellExecutableArgs;
- }
const notificationMode = readParameter(
"idf.notificationMode",
this.currentWorkspace
@@ -111,14 +100,14 @@ export class CustomTask {
notificationMode === NotificationMode.Output
? TaskRevealKind.Always
: TaskRevealKind.Silent;
- const customExecution = this.getProcessExecution(cmd, options);
+ const customExecution = new ProcessExecution(command, this.processOptions);
const customTaskPresentationOptions = {
reveal: showTaskOutput,
showReuseMessage: false,
clear: false,
panel: TaskPanelKind.Dedicated,
} as TaskPresentationOptions;
- const curWorkspaceFolder = workspace.workspaceFolders.find(
+ const currentWorkspaceFolder = workspace.workspaceFolders.find(
(w) => w.uri === this.currentWorkspace
);
TaskManager.addTask(
@@ -127,7 +116,7 @@ export class CustomTask {
command: `ESP-IDF ${taskName}`,
taskId: `idf-${taskType}-task`,
},
- curWorkspaceFolder || TaskScope.Workspace,
+ currentWorkspaceFolder || TaskScope.Workspace,
`ESP-IDF ${taskName}`,
customExecution,
["espIdf"],
@@ -136,38 +125,38 @@ export class CustomTask {
}
public async runTasks(taskType: CustomTaskType) {
- let cmd: string;
+ let command: string;
switch (taskType) {
case CustomTaskType.PreBuild:
- cmd = readParameter(
+ command = readParameter(
"idf.preBuildTask",
this.currentWorkspace
) as string;
break;
case CustomTaskType.PostBuild:
- cmd = readParameter(
+ command = readParameter(
"idf.postBuildTask",
this.currentWorkspace
) as string;
break;
case CustomTaskType.PreFlash:
- cmd = readParameter(
+ command = readParameter(
"idf.preFlashTask",
this.currentWorkspace
) as string;
break;
case CustomTaskType.PostFlash:
- cmd = readParameter(
+ command = readParameter(
"idf.postFlashTask",
this.currentWorkspace
) as string;
break;
case CustomTaskType.Custom:
- cmd = readParameter("idf.customTask", this.currentWorkspace) as string;
+ command = readParameter("idf.customTask", this.currentWorkspace) as string;
default:
break;
}
- if (cmd) {
+ if (command) {
await TaskManager.runTasks();
}
}
diff --git a/src/espBom/index.ts b/src/espBom/index.ts
index 4bdc44776..1f6c21bbf 100644
--- a/src/espBom/index.ts
+++ b/src/espBom/index.ts
@@ -23,8 +23,8 @@ import {
TaskPanelKind,
TaskPresentationOptions,
TaskScope,
- ShellExecutionOptions,
- ShellExecution,
+ ProcessExecutionOptions,
+ ProcessExecution,
} from "vscode";
import {
appendIdfAndToolsToPath,
@@ -66,24 +66,10 @@ export async function createSBOM(workspaceUri: Uri) {
);
}
}
- const options: ShellExecutionOptions = {
+ const options: ProcessExecutionOptions = {
cwd: workspaceUri.fsPath,
env: modifiedEnv,
};
- const shellExecutablePath = readParameter(
- "idf.customTerminalExecutable",
- workspaceUri
- ) as string;
- const shellExecutableArgs = readParameter(
- "idf.customTerminalExecutableArgs",
- workspaceUri
- ) as string[];
- if (shellExecutablePath) {
- options.executable = shellExecutablePath;
- }
- if (shellExecutableArgs && shellExecutableArgs.length) {
- options.shellArgs = shellExecutableArgs;
- }
const notificationMode = readParameter(
"idf.notificationMode",
workspaceUri
@@ -102,12 +88,23 @@ export async function createSBOM(workspaceUri: Uri) {
clear: false,
panel: TaskPanelKind.Shared,
} as TaskPresentationOptions;
- const sbomCreateExecution = new ShellExecution(
- `esp-idf-sbom create ${projectDescriptionJson} --output-file ${sbomFilePath}`,
+ const command = "esp-idf-sbom";
+ const argsCreating = [
+ "create",
+ projectDescriptionJson,
+ "--output-file",
+ sbomFilePath,
+ ];
+ const sbomCreateExecution = new ProcessExecution(
+ command,
+ argsCreating,
options
);
- const sbomCheckExecution = new ShellExecution(
- `esp-idf-sbom check ${sbomFilePath}`,
+
+ const argsChecking = ["check", sbomFilePath];
+ const sbomCheckExecution = new ProcessExecution(
+ command,
+ argsChecking,
options
);
TaskManager.addTask(
@@ -148,7 +145,8 @@ export async function installEspSBOM(workspace: Uri) {
const modifiedEnv = appendIdfAndToolsToPath(workspace);
try {
const showResult = await execChildProcess(
- `"${pythonBinPath}" -m pip show esp-idf-sbom`,
+ pythonBinPath,
+ ["-m", "pip", "show", "esp-idf-sbom"],
workspace.fsPath,
OutputChannel.init(),
{ env: modifiedEnv }
@@ -156,7 +154,8 @@ export async function installEspSBOM(workspace: Uri) {
OutputChannel.appendLine(showResult);
} catch (error) {
const installResult = await execChildProcess(
- `"${pythonBinPath}" -m pip install esp-idf-sbom`,
+ pythonBinPath,
+ ["-m", "pip", "install", "esp-idf-sbom"],
workspace.fsPath,
OutputChannel.init(),
{ env: modifiedEnv }
diff --git a/src/espIdf/monitor/index.ts b/src/espIdf/monitor/index.ts
index 1222672f3..fc61baabe 100644
--- a/src/espIdf/monitor/index.ts
+++ b/src/espIdf/monitor/index.ts
@@ -17,7 +17,7 @@
*/
import { ESP } from "../../config";
-import { appendIdfAndToolsToPath } from "../../utils";
+import { appendIdfAndToolsToPath, getUserShell } from "../../utils";
import { window, Terminal, Uri, env } from "vscode";
export interface MonitorConfig {
@@ -60,14 +60,20 @@ export class IDFMonitor {
});
this.terminal.show();
this.terminal.dispose = this.dispose.bind(this);
+ const shellType = getUserShell();
+ // Function to quote paths; PowerShell requires single quotes for paths with spaces
+ const quotePath = (path) =>
+ shellType === "PowerShell"
+ ? `'${path.replace(/'/g, "''")}'`
+ : `"${path}"`;
const baudRateToUse =
this.config.baudRate ||
modifiedEnv.IDF_MONITOR_BAUD ||
modifiedEnv.MONITORBAUD ||
"115200";
const args = [
- this.config.pythonBinPath,
- this.config.idfMonitorToolPath,
+ quotePath(this.config.pythonBinPath),
+ quotePath(this.config.idfMonitorToolPath),
"-p",
this.config.port,
"-b",
@@ -96,10 +102,18 @@ export class IDFMonitor {
if (this.config.wsPort) {
args.push("--ws", `ws://localhost:${this.config.wsPort}`);
}
- args.push(this.config.elfFilePath);
+ args.push(quotePath(this.config.elfFilePath));
const envSetCmd = process.platform === "win32" ? "set" : "export";
- this.terminal.sendText(`${envSetCmd} IDF_PATH=${modifiedEnv.IDF_PATH}`);
- this.terminal.sendText(args.join(" "));
+ const quotedIdfPath = quotePath(modifiedEnv.IDF_PATH);
+
+ if (shellType === "PowerShell") {
+ this.terminal.sendText(`& ${envSetCmd} IDF_PATH=${quotedIdfPath}`);
+ this.terminal.sendText(`& ${args.join(" ")}`);
+ } else {
+ this.terminal.sendText(`${envSetCmd} IDF_PATH=${modifiedEnv.IDF_PATH}`);
+ this.terminal.sendText(args.join(" "));
+ }
+
return this.terminal;
}
async dispose() {
diff --git a/src/espIdf/nvs/partitionTable/panel.ts b/src/espIdf/nvs/partitionTable/panel.ts
index 2a1ec0437..934bb47e2 100644
--- a/src/espIdf/nvs/partitionTable/panel.ts
+++ b/src/espIdf/nvs/partitionTable/panel.ts
@@ -182,7 +182,8 @@ export class NVSPartitionTable {
}
OutputChannel.appendLine(`${pythonBinPath} ${partToolArgs.join(" ")}`);
const result = await execChildProcess(
- `${pythonBinPath} ${partToolArgs.join(" ")}`,
+ pythonBinPath,
+ partToolArgs,
dirPath
);
OutputChannel.appendLine(result);
diff --git a/src/espIdf/size/idfSizeTask.ts b/src/espIdf/size/idfSizeTask.ts
index c066b2dbb..9e6ef8cad 100644
--- a/src/espIdf/size/idfSizeTask.ts
+++ b/src/espIdf/size/idfSizeTask.ts
@@ -19,14 +19,14 @@
import { ensureDir } from "fs-extra";
import { join } from "path";
import {
- ShellExecution,
- ShellExecutionOptions,
TaskPanelKind,
+ ProcessExecutionOptions,
TaskPresentationOptions,
TaskRevealKind,
TaskScope,
Uri,
workspace,
+ ProcessExecution
} from "vscode";
import { NotificationMode, readParameter } from "../../idfConfiguration";
import { TaskManager } from "../../taskManager";
@@ -34,28 +34,27 @@ import { appendIdfAndToolsToPath } from "../../utils";
import { getProjectName } from "../../workspaceConfig";
export class IdfSizeTask {
- private curWorkspace: Uri;
+ private currentWorkspace: Uri;
private pythonBinPath: string;
private idfSizePath: string;
private buildDirPath: string;
+ private processOptions: ProcessExecutionOptions;
+ private modifiedEnv: { [key: string]: string };
- constructor(workspacePath: Uri) {
- this.curWorkspace = workspacePath;
+ constructor(workspaceUri: Uri) {
+ this.currentWorkspace = workspaceUri;
this.pythonBinPath = readParameter(
"idf.pythonBinPath",
- workspacePath
+ workspaceUri
) as string;
- const idfPathDir = readParameter("idf.espIdfPath", workspacePath) as string;
+ const idfPathDir = readParameter("idf.espIdfPath", workspaceUri) as string;
this.idfSizePath = join(idfPathDir, "tools", "idf_size.py");
- this.buildDirPath = readParameter("idf.buildPath", workspacePath) as string;
- }
-
- public async getShellExecution(options: ShellExecutionOptions) {
- const mapFilePath = await this.mapFilePath();
- return new ShellExecution(
- `${this.pythonBinPath} ${this.idfSizePath} ${mapFilePath}`,
- options
- );
+ this.buildDirPath = readParameter("idf.buildPath", workspaceUri) as string;
+ this.modifiedEnv = appendIdfAndToolsToPath(this.currentWorkspace);
+ this.processOptions = {
+ cwd: this.buildDirPath,
+ env: this.modifiedEnv,
+ };
}
private async mapFilePath() {
@@ -64,33 +63,18 @@ export class IdfSizeTask {
}
public async getSizeInfo() {
- const modifiedEnv = appendIdfAndToolsToPath(this.curWorkspace);
await ensureDir(this.buildDirPath);
- const options: ShellExecutionOptions = {
- cwd: this.curWorkspace.fsPath,
- env: modifiedEnv,
- };
- const shellExecutablePath = readParameter(
- "idf.customTerminalExecutable",
- this.curWorkspace
- ) as string;
- const shellExecutableArgs = readParameter(
- "idf.customTerminalExecutableArgs",
- this.curWorkspace
- ) as string[];
- if (shellExecutablePath) {
- options.executable = shellExecutablePath;
- }
- if (shellExecutableArgs && shellExecutableArgs.length) {
- options.shellArgs = shellExecutableArgs;
- }
- const sizeExecution = await this.getShellExecution(options);
+ const pythonCommand = this.pythonBinPath;
+ const mapFilePath = await this.mapFilePath();
+ const args = [this.idfSizePath, mapFilePath];
+
+ const sizeExecution = new ProcessExecution(pythonCommand, args, this.processOptions);
const notificationMode = readParameter(
"idf.notificationMode",
- this.curWorkspace
+ this.currentWorkspace
) as string;
- const curWorkspaceFolder = workspace.workspaceFolders.find(
- (w) => w.uri === this.curWorkspace
+ const currentWorkspaceFolder = workspace.workspaceFolders.find(
+ (w) => w.uri === this.currentWorkspace
);
const showTaskOutput =
notificationMode === NotificationMode.All ||
@@ -105,7 +89,7 @@ export class IdfSizeTask {
} as TaskPresentationOptions;
TaskManager.addTask(
{ type: "esp-idf", command: "ESP-IDF Size", taskId: "idf-size-task" },
- curWorkspaceFolder || TaskScope.Workspace,
+ currentWorkspaceFolder || TaskScope.Workspace,
"ESP-IDF Size",
sizeExecution,
["espIdf"],
diff --git a/src/extension.ts b/src/extension.ts
index cb3aacf95..d140c0eba 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -680,8 +680,10 @@ export async function activate(context: vscode.ExtensionContext) {
cancelToken: vscode.CancellationToken
) => {
try {
+ const args = [flashScriptPath, "-p", port, "erase_flash"];
const result = await utils.execChildProcess(
- `${pythonBinPath} ${flashScriptPath} -p ${port} erase_flash`,
+ pythonBinPath,
+ args,
process.cwd(),
OutputChannel.init(),
null,
@@ -3462,8 +3464,10 @@ export async function activate(context: vscode.ExtensionContext) {
"idf.buildPath",
workspaceRoot
) as string;
+ const args = [ninjaSummaryScript, "-C", buildDir];
const summaryResult = await utils.execChildProcess(
- `${pythonBinPath} ${ninjaSummaryScript} -C ${buildDir}`,
+ pythonBinPath,
+ args,
workspaceRoot.fsPath,
OutputChannel.init()
);
diff --git a/src/flash/dfu.ts b/src/flash/dfu.ts
index d383d625f..a6d37217d 100644
--- a/src/flash/dfu.ts
+++ b/src/flash/dfu.ts
@@ -31,10 +31,11 @@ function deviceLabel(selectedDevice: string) {
return "ESP32-S3";
}
-export async function getDfuList(workspace: vscode.Uri) {
- const modifiedEnv = appendIdfAndToolsToPath(workspace);
+export async function getDfuList(workspaceUri: vscode.Uri) {
+ const modifiedEnv = appendIdfAndToolsToPath(workspaceUri);
return await execChildProcess(
- "dfu-util --list",
+ "dfu-util",
+ ["--list"],
process.cwd(),
OutputChannel.init(),
{
@@ -64,14 +65,14 @@ export async function listAvailableDfuDevices(text) {
* @param {string} chip - String to identify the chip (IDF_TARGET)
* @returns {number} PID Number for DFU
*/
- export function selectedDFUAdapterId(chip: string): number {
+ export function selectedDFUAdapterId(chip: string): string {
switch (chip) {
case "esp32s2":
- return 2;
+ return "2";
case "esp32s3":
- return 9;
+ return "9";
default:
- return -1;
+ return "-1";
}
}
diff --git a/src/flash/flashTask.ts b/src/flash/flashTask.ts
index 7cd6f7a48..8d58f83fc 100644
--- a/src/flash/flashTask.ts
+++ b/src/flash/flashTask.ts
@@ -28,19 +28,23 @@ import { ESP } from "../config";
export class FlashTask {
public static isFlashing: boolean;
- private workspaceUri: vscode.Uri;
+ private currentWorkspace: vscode.Uri;
private flashScriptPath: string;
private model: FlashModel;
private buildDirPath: string;
private encryptPartitions: boolean;
+ private idfPathDir: string;
+ private pythonBinPath: string;
+ private modifiedEnv: { [key: string]: string };
+ private processOptions: vscode.ProcessExecutionOptions;
constructor(
- workspace: vscode.Uri,
+ workspaceUri: vscode.Uri,
idfPath: string,
model: FlashModel,
- encryptPartitions: boolean
+ encryptPartitions: boolean,
) {
- this.workspaceUri = workspace;
+ this.currentWorkspace = workspaceUri;
this.flashScriptPath = join(
idfPath,
"components",
@@ -51,9 +55,22 @@ export class FlashTask {
this.model = model;
this.buildDirPath = idfConf.readParameter(
"idf.buildPath",
- workspace
+ workspaceUri
) as string;
this.encryptPartitions = encryptPartitions;
+ this.idfPathDir = idfConf.readParameter(
+ "idf.espIdfPath",
+ this.currentWorkspace
+ ) as string;
+ this.pythonBinPath = idfConf.readParameter(
+ "idf.pythonBinPath",
+ this.currentWorkspace
+ ) as string;
+ this.modifiedEnv = appendIdfAndToolsToPath(workspaceUri);
+ this.processOptions = {
+ cwd: this.buildDirPath,
+ env: this.modifiedEnv,
+ };
}
public flashing(flag: boolean) {
@@ -83,17 +100,17 @@ export class FlashTask {
this.verifyArgs();
const notificationMode = idfConf.readParameter(
"idf.notificationMode",
- this.workspaceUri
+ this.currentWorkspace
) as string;
- const curWorkspaceFolder = vscode.workspace.workspaceFolders.find(
- (w) => w.uri === this.workspaceUri
+ const currentWorkspaceFolder = vscode.workspace.workspaceFolders.find(
+ (w) => w.uri === this.currentWorkspace
);
const showTaskOutput =
notificationMode === idfConf.NotificationMode.All ||
notificationMode === idfConf.NotificationMode.Output
? vscode.TaskRevealKind.Always
: vscode.TaskRevealKind.Silent;
- let flashExecution: vscode.ShellExecution | vscode.ProcessExecution;
+ let flashExecution: vscode.ProcessExecution;
switch (flashType) {
case "UART":
flashExecution = this._flashExecution();
@@ -112,7 +129,7 @@ export class FlashTask {
} as vscode.TaskPresentationOptions;
TaskManager.addTask(
{ type: "esp-idf", command: "ESP-IDF Flash", taskId: "idf-flash-task" },
- curWorkspaceFolder || vscode.TaskScope.Workspace,
+ currentWorkspaceFolder || vscode.TaskScope.Workspace,
"ESP-IDF Flash",
flashExecution,
["espIdf"],
@@ -122,49 +139,39 @@ export class FlashTask {
public _flashExecution() {
this.flashing(true);
- const modifiedEnv = appendIdfAndToolsToPath(this.workspaceUri);
const flasherArgs = this.getFlasherArgs(this.flashScriptPath);
- const options: vscode.ShellExecutionOptions = {
- cwd: this.buildDirPath,
- env: modifiedEnv,
- };
- const pythonBinPath = idfConf.readParameter(
- "idf.pythonBinPath",
- this.workspaceUri
- ) as string;
- return new vscode.ProcessExecution(pythonBinPath, flasherArgs, options);
+ return new vscode.ProcessExecution(this.pythonBinPath, flasherArgs, this.processOptions);
}
public _dfuFlashing() {
this.flashing(true);
const selectedDfuPath = idfConf.readParameter(
"idf.selectedDfuDevicePath",
- this.workspaceUri
+ this.currentWorkspace
);
const listDfuDevices = idfConf.readParameter(
"idf.listDfuDevices",
- this.workspaceUri
+ this.currentWorkspace
);
if (listDfuDevices.length > 1) {
- const idfPathDir = idfConf.readParameter(
- "idf.espIdfPath",
- this.workspaceUri
- ) as string;
- const pythonPath = idfConf.readParameter(
- "idf.pythonBinPath",
- this.workspaceUri
- ) as string;
- const idfPy = path.join(idfPathDir, "tools", "idf.py");
- return new vscode.ShellExecution(
- `${pythonPath} ${idfPy} dfu-flash --path ${selectedDfuPath}`
- );
+ const pythonCommand = this.pythonBinPath;
+ const idfPy = path.join(this.idfPathDir, "tools", "idf.py");
+ const args = [
+ idfPy,
+ 'dfu-flash',
+ '--path',
+ selectedDfuPath
+ ];
+ return new vscode.ProcessExecution(pythonCommand, args, this.processOptions);
}
- return new vscode.ShellExecution(
- `dfu-util -d 303a:${selectedDFUAdapterId(this.model.chip)} -D ${join(
- this.buildDirPath,
- "dfu.bin"
- )}`
- );
+ const dfuCommand = "dfu-util";
+ const args = [
+ "-d",
+ `303a:${Number(selectedDFUAdapterId(this.model.chip)).toString(16)}`,
+ "-D",
+ join(this.buildDirPath, "dfu.bin")
+ ];
+ return new vscode.ProcessExecution(dfuCommand, args, this.processOptions);
}
public getFlasherArgs(toolPath: string, replacePathSep: boolean = false) {
diff --git a/src/flash/jtag.ts b/src/flash/jtag.ts
index 31df16d51..62e725c2b 100644
--- a/src/flash/jtag.ts
+++ b/src/flash/jtag.ts
@@ -20,11 +20,17 @@ import { TCLClient } from "../espIdf/openOcd/tcl/tclClient";
export class JTAGFlash {
constructor(private readonly client: TCLClient) {}
- async flash(command: string) {
+
+ async flash(command: string, ...args: string[]) {
+ const fullCommand = `${command} ${args.map((arg) => `"${arg}"`).join(" ")}`;
+
return new Promise((resolve, reject) => {
this.client
.on("response", (data) => {
- const response = data.toString().replace("\x1a", "").trim();
+ const response = data
+ .toString()
+ .replace(TCLClient.DELIMITER, "")
+ .trim();
if (response !== "0") {
return reject(
`Failed to flash the device (JTag), please try again [got response: '${response}', expecting: '0']`
@@ -39,7 +45,7 @@ export class JTAGFlash {
"Failed to flash (via JTag), due to some unknown error in tcl, please try to relaunch open-ocd"
);
})
- .sendCommand(command);
+ .sendCommand(fullCommand);
});
}
}
diff --git a/src/flash/jtagCmd.ts b/src/flash/jtagCmd.ts
index 511c3827e..0eccad407 100644
--- a/src/flash/jtagCmd.ts
+++ b/src/flash/jtagCmd.ts
@@ -32,7 +32,8 @@ export async function jtagFlashCommand(workspace: Uri) {
let continueFlag = true;
const isOpenOCDLaunched = await OpenOCDManager.init().promptUserToLaunchOpenOCDServer();
if (!isOpenOCDLaunched) {
- const errStr = "Can't perform JTag flash, because OpenOCD server is not running!";
+ const errStr =
+ "Can't perform JTag flash, because OpenOCD server is not running!";
OutputChannel.appendLineAndShow(errStr, "Flash");
return Logger.warnNotify(errStr);
}
@@ -57,7 +58,11 @@ export async function jtagFlashCommand(workspace: Uri) {
customTask.addCustomTask(CustomTaskType.PreFlash);
await customTask.runTasks(CustomTaskType.PreFlash);
await jtag.flash(
- `program_esp_bins ${buildPath} flasher_args.json verify reset`
+ "program_esp_bins",
+ buildPath,
+ "flasher_args.json",
+ "verify",
+ "reset"
);
customTask.addCustomTask(CustomTaskType.PostFlash);
await customTask.runTasks(CustomTaskType.PostFlash);
diff --git a/src/idfToolsManager.ts b/src/idfToolsManager.ts
index 9cf19f3d0..227f4ad20 100644
--- a/src/idfToolsManager.ts
+++ b/src/idfToolsManager.ts
@@ -221,13 +221,15 @@ export class IdfToolsManager {
) {
modifiedEnv[pathNameInEnv] = modifiedPath;
}
- const versionCmd = pkg.version_cmd.join(" ");
- if (versionCmd === "") {
+ if (pkg.version_cmd.length === 0) {
return "No command version";
}
+ const command = pkg.version_cmd[0];
+ const args = pkg.version_cmd.slice(1);
try {
const binVersionResponse = await utils.execChildProcess(
- versionCmd,
+ command,
+ args,
process.cwd(),
logToChannel ? this.toolsManagerChannel : undefined,
{
diff --git a/src/pythonManager.ts b/src/pythonManager.ts
index f56280a07..b1a8a3350 100644
--- a/src/pythonManager.ts
+++ b/src/pythonManager.ts
@@ -39,8 +39,10 @@ export async function installEspIdfToolFromIdf(
return reject(new Error("Process cancelled by user"));
}
try {
+ const args = [idfToolsPyPath, "install", toolName];
const processResult = await utils.execChildProcess(
- `"${pythonBinPath}" ${idfToolsPyPath} install ${toolName}`,
+ pythonBinPath,
+ args,
idfToolsPath,
channel,
{ cwd: idfToolsPath, env: modifiedEnv },
@@ -101,7 +103,8 @@ export async function installPythonEnvFromIdfTools(
const pyEnvPath = await getPythonEnvPath(espDir, idfToolsDir, pythonBinPath);
await execProcessWithLog(
- `"${pythonBinPath}" "${idfToolsPyPath}" install-python-env`,
+ pythonBinPath,
+ [idfToolsPyPath, "install-python-env"],
idfToolsDir,
pyTracker,
channel,
@@ -145,19 +148,19 @@ export async function installExtensionPyReqs(
`espidf.constraints.v${espIdfVersion}.txt`
);
const constrainsFileExists = await pathExists(constrainsFile);
- let constraintArg = "";
+ let constraintArg = [];
if (constrainsFileExists) {
- constraintArg = `--constraint "${constrainsFile}" `;
+ constraintArg = ["--constraint", constrainsFile];
} else {
const extensionConstraintsFile = join(
utils.extensionContext.extensionPath,
- `espidf.constraints.txt`
+ "espidf.constraints.txt"
);
const extensionConstraintsFileExists = await pathExists(
extensionConstraintsFile
);
if (extensionConstraintsFileExists) {
- constraintArg = `--constraint "${extensionConstraintsFile}" `;
+ constraintArg = ["--constraint", extensionConstraintsFile];
}
}
const installDAPyPkgsMsg = `Installing ESP-IDF Debug Adapter python packages in ${virtualEnvPython} ...\n`;
@@ -168,8 +171,19 @@ export async function installExtensionPyReqs(
if (channel) {
channel.appendLine(installDAPyPkgsMsg + "\n");
}
+ const args = [
+ "-m",
+ "pip",
+ "install",
+ "--upgrade",
+ ...constraintArg,
+ "--no-warn-script-location",
+ "-r",
+ debugAdapterRequirements,
+ ];
await execProcessWithLog(
- `"${virtualEnvPython}" -m pip install --upgrade ${constraintArg}--no-warn-script-location -r "${debugAdapterRequirements}"`,
+ virtualEnvPython,
+ args,
idfToolsDir,
pyTracker,
channel,
@@ -215,8 +229,18 @@ export async function installEspMatterPyReqs(
if (channel) {
channel.appendLine(installMatterPyPkgsMsg + "\n");
}
+ const args = [
+ "-m",
+ "pip",
+ "install",
+ "--upgrade",
+ "--no-warn-script-location",
+ "-r",
+ matterRequirements,
+ ];
await execProcessWithLog(
- `"${virtualEnvPython}" -m pip install --upgrade --no-warn-script-location -r "${matterRequirements}"`,
+ virtualEnvPython,
+ args,
idfToolsDir,
pyTracker,
channel,
@@ -227,6 +251,7 @@ export async function installEspMatterPyReqs(
}
export async function execProcessWithLog(
cmd: string,
+ args: string[],
workDir: string,
pyTracker?: PyReqLog,
channel?: OutputChannel,
@@ -235,6 +260,7 @@ export async function execProcessWithLog(
) {
const processResult = await utils.execChildProcess(
cmd,
+ args,
workDir,
channel,
opts,
@@ -254,11 +280,10 @@ export async function getPythonEnvPath(
idfToolsDir: string,
pythonBin: string
) {
+ const pythonCode = `import sys; print('{}.{}'.format(sys.version_info.major, sys.version_info.minor))`;
+ const args = ["-c", pythonCode];
const pythonVersion = (
- await utils.execChildProcess(
- `"${pythonBin}" -c "import sys; print('{}.{}'.format(sys.version_info.major, sys.version_info.minor))"`,
- espIdfDir
- )
+ await utils.execChildProcess(pythonBin, args, espIdfDir)
).replace(/(\n|\r|\r\n)/gm, "");
const fullEspIdfVersion = await utils.getEspIdfFromCMake(espIdfDir);
const majorMinorMatches = fullEspIdfVersion.match(/([0-9]+\.[0-9]+).*/);
@@ -275,7 +300,8 @@ export async function getPythonEnvPath(
export async function checkPythonExists(pythonBin: string, workingDir: string) {
try {
const versionResult = await utils.execChildProcess(
- `"${pythonBin}" --version`,
+ pythonBin,
+ ["--version"],
workingDir
);
if (versionResult) {
@@ -302,10 +328,8 @@ export async function checkPythonExists(pythonBin: string, workingDir: string) {
export async function checkPipExists(pyBinPath: string, workingDir: string) {
try {
- const pipResult = await utils.execChildProcess(
- `"${pyBinPath}" -m pip --version`,
- workingDir
- );
+ const args = ["-m", "pip", "--version"];
+ const pipResult = await utils.execChildProcess(pyBinPath, args, workingDir);
if (pipResult) {
const match = pipResult.match(/pip\s\d+(.\d+)?(.\d+)?/g);
if (match && match.length > 0) {
@@ -325,7 +349,8 @@ export async function checkPipExists(pyBinPath: string, workingDir: string) {
export async function checkVenvExists(pyBinPath: string, workingDir: string) {
try {
const pipResult = await utils.execChildProcess(
- `"${pyBinPath}" -c "import venv"`,
+ pyBinPath,
+ ["-c", "import venv"],
workingDir
);
return true;
@@ -349,16 +374,42 @@ export async function getPythonBinList(workingDir: string) {
export async function getUnixPythonList(workingDir: string) {
try {
- const pyVersionsStr = await utils.execChildProcess(
- "which -a python; which -a python3",
- workingDir
- );
- if (pyVersionsStr) {
- const resultList = pyVersionsStr.trim().split("\n");
- const uniquePathsSet = new Set(resultList);
- const uniquePathsArray = Array.from(uniquePathsSet);
- return uniquePathsArray;
+ let pythonVersions: string[] = [];
+ let python3Versions: string[] = [];
+
+ try {
+ const pythonVersionsRaw = await utils.execChildProcess(
+ "which",
+ ["-a", "python"],
+ workingDir
+ );
+ pythonVersions = pythonVersionsRaw.trim()
+ ? pythonVersionsRaw.trim().split("\n")
+ : [];
+ } catch (pythonError) {
+ Logger.warn("Error finding python versions", pythonError);
}
+
+ try {
+ const python3VersionsRaw = await utils.execChildProcess(
+ "which",
+ ["-a", "python3"],
+ workingDir
+ );
+ python3Versions = python3VersionsRaw.trim()
+ ? python3VersionsRaw.trim().split("\n")
+ : [];
+ } catch (python3Error) {
+ Logger.warn("Error finding python3 versions", python3Error);
+ }
+
+ const combinedVersionsArray = [...pythonVersions, ...python3Versions];
+ const uniquePathsSet = new Set(
+ combinedVersionsArray.filter((path) => path.length > 0)
+ );
+ const uniquePathsArray = Array.from(uniquePathsSet);
+
+ return uniquePathsArray;
} catch (error) {
Logger.errorNotify("Error looking for python in system", error);
return ["Not found"];
@@ -370,11 +421,12 @@ export async function checkIfNotVirtualEnv(
workDir: string
) {
try {
- const isVirtualEnvBuffer = await utils.execChildProcess(
- `"${pythonBinPath}" -c "import sys; print('{}'.format(sys.prefix == sys.base_prefix))"`,
+ const isVirtualEnv = await utils.execChildProcess(
+ pythonBinPath,
+ ["-c", "import sys; print(sys.prefix == sys.base_prefix)"],
workDir
);
- return isVirtualEnvBuffer.toString().indexOf("True") !== -1 ? true : false;
+ return isVirtualEnv.trim() === "True";
} catch (error) {
Logger.errorNotify("Error checking Python is virtualenv", error);
return false;
diff --git a/src/setup/SetupPanel.ts b/src/setup/SetupPanel.ts
index 0259ddef8..981923042 100644
--- a/src/setup/SetupPanel.ts
+++ b/src/setup/SetupPanel.ts
@@ -441,10 +441,7 @@ export class SetupPanel {
? espIdfPath
: idfContainerPath;
this.checkSpacesInPaths(
- pathToCheck,
toolsPath,
- idfGitPath,
- idfPythonPath
);
await expressInstall(
selectedIdfVersion,
@@ -576,10 +573,7 @@ export class SetupPanel {
idfPythonPath = embedPaths.idfPythonPath;
}
this.checkSpacesInPaths(
- idfPath,
toolsPath,
- idfGitPath,
- idfPythonPath
);
await downloadIdfTools(
idfPath,
@@ -694,29 +688,22 @@ export class SetupPanel {
return { idfPythonPath, idfGitPath };
}
+ private async getOpenOcdRulesPath() {
+ try {
+ await getOpenOcdRules(Uri.file(this.context.extensionPath));
+ } catch (error) {
+ this.setupErrHandler(error);
+ }
+ }
+
private checkSpacesInPaths(
- idfPath: string,
idfToolsPath: string,
- gitPath: string,
- pythonBinPath: string
) {
- const doesIdfPathHasSpaces = checkSpacesInPath(idfPath);
const doesIdfToolsPathHasSpaces = checkSpacesInPath(idfToolsPath);
- const doesGitPathHasSpaces = checkSpacesInPath(gitPath);
- const doesPythonBinPath = checkSpacesInPath(pythonBinPath);
let pathHasSpaces = "";
- if (doesIdfPathHasSpaces) {
- pathHasSpaces = `${idfPath} has spaces. Use another location. (IDF_PATH_WITH_SPACES)`;
- }
if (doesIdfToolsPathHasSpaces) {
pathHasSpaces = `${idfToolsPath} has spaces. Use another location. (IDF_TOOLS_PATH_WITH_SPACES)`;
}
- if (doesGitPathHasSpaces) {
- pathHasSpaces = `${gitPath} has spaces. Use another location. (GIT_PATH_WITH_SPACES)`;
- }
- if (doesPythonBinPath) {
- pathHasSpaces = `${pythonBinPath} has spaces. Use another location. (PYTHON_BIN_PATH_WITH_SPACES)`;
- }
if (pathHasSpaces) {
OutputChannel.appendLine(pathHasSpaces);
Logger.infoNotify(pathHasSpaces);
@@ -724,14 +711,6 @@ export class SetupPanel {
}
}
- private async getOpenOcdRulesPath() {
- try {
- await getOpenOcdRules(Uri.file(this.context.extensionPath));
- } catch (error) {
- this.setupErrHandler(error);
- }
- }
-
private async openFolder() {
const selectedFolder = await window.showOpenDialog({
canSelectFolders: true,
diff --git a/src/support/checkEspIdfRequirements.ts b/src/support/checkEspIdfRequirements.ts
index eb33763df..49a8e8ec9 100644
--- a/src/support/checkEspIdfRequirements.ts
+++ b/src/support/checkEspIdfRequirements.ts
@@ -64,7 +64,8 @@ export async function checkRequirements(
);
modifiedEnv.IDF_PATH = reportedResult.configurationSettings.espIdfPath;
const requirementsResult = await execChildProcess(
- `${reportedResult.configurationSettings.pythonBinPath} ${checkPythonDepsScript} -r "${requirementsPath}"`,
+ reportedResult.configurationSettings.pythonBinPath,
+ [checkPythonDepsScript, "-r", requirementsPath],
context.extensionPath,
{ env: modifiedEnv, cwd: context.extensionPath }
);
diff --git a/src/support/configurationAccess.ts b/src/support/configurationAccess.ts
index 5d7357e37..2de83a07a 100644
--- a/src/support/configurationAccess.ts
+++ b/src/support/configurationAccess.ts
@@ -71,13 +71,15 @@ export async function getConfigurationAccess(
}
if (process.platform !== "win32") {
const cmakePathInEnv = await execChildProcess(
- `which cmake`,
+ "which",
+ ["cmake"],
context.extensionPath
);
reportedResult.configurationAccess.cmakeInEnv =
cmakePathInEnv && cmakePathInEnv.indexOf("not found") === -1;
const ninjaPathInEnv = await execChildProcess(
- `which ninja`,
+ "which",
+ ["ninja"],
context.extensionPath
);
reportedResult.configurationAccess.ninjaInEnv =
diff --git a/src/support/execChildProcess.ts b/src/support/execChildProcess.ts
index 61e0e04f7..381d81be0 100644
--- a/src/support/execChildProcess.ts
+++ b/src/support/execChildProcess.ts
@@ -15,10 +15,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { exec, ExecOptions } from "child_process";
+import { execFile, ExecOptions } from "child_process";
export function execChildProcess(
- cmd: string,
+ command: string,
+ args: string[] = [],
pathWhereToExecute: string,
opts?: ExecOptions
) {
@@ -29,7 +30,7 @@ export function execChildProcess(
};
}
return new Promise((resolve, reject) => {
- exec(cmd, opts, (error: Error, stdout: string, stderr: string) => {
+ execFile(command, args, opts, (error: Error, stdout: string, stderr: string) => {
if (error) {
return reject(error);
}
diff --git a/src/support/gitVersion.ts b/src/support/gitVersion.ts
index 04a62f1f0..c5c3eb0d7 100644
--- a/src/support/gitVersion.ts
+++ b/src/support/gitVersion.ts
@@ -26,7 +26,8 @@ export async function getGitVersion(
context: vscode.ExtensionContext,
) {
const rawGitVersion = await execChildProcess(
- `"${reportedResult.configurationSettings.gitPath}" --version`,
+ reportedResult.configurationSettings.gitPath,
+ ["--version"],
context.extensionPath
);
reportedResult.gitVersion.output = rawGitVersion;
diff --git a/src/support/pipVersion.ts b/src/support/pipVersion.ts
index 5cfbd2529..813360b06 100644
--- a/src/support/pipVersion.ts
+++ b/src/support/pipVersion.ts
@@ -26,7 +26,8 @@ export async function getPipVersion(
) {
try {
const rawPipVersion = await execChildProcess(
- `"${reportedResult.configurationSettings.pythonBinPath}" -m pip --version`,
+ reportedResult.configurationSettings.pythonBinPath,
+ ["-m", "pip", "--version"],
context.extensionPath
);
reportedResult.pipVersion.output = rawPipVersion;
diff --git a/src/support/pythonPackages.ts b/src/support/pythonPackages.ts
index 77701f974..0ea287d71 100644
--- a/src/support/pythonPackages.ts
+++ b/src/support/pythonPackages.ts
@@ -24,7 +24,8 @@ export async function getPythonPackages(
context: vscode.ExtensionContext
) {
const rawPythonPackagesList = await execChildProcess(
- `${reportedResult.configurationSettings.pythonBinPath} -m pip list --format json`,
+ reportedResult.configurationSettings.pythonBinPath,
+ ["-m", "pip", "list", "--format", "json"],
context.extensionPath
);
reportedResult.pythonPackages.output = rawPythonPackagesList;
diff --git a/src/support/pythonVersion.ts b/src/support/pythonVersion.ts
index 5931537f9..b9b2846f8 100644
--- a/src/support/pythonVersion.ts
+++ b/src/support/pythonVersion.ts
@@ -26,7 +26,8 @@ export async function getPythonVersion(
) {
try {
const rawPythonVersion = await execChildProcess(
- `"${reportedResult.configurationSettings.pythonBinPath}" --version`,
+ reportedResult.configurationSettings.pythonBinPath,
+ ["--version"],
context.extensionPath
);
reportedResult.pythonVersion.output = rawPythonVersion;
diff --git a/src/utils.ts b/src/utils.ts
index 2b64a6c22..993b4b325 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -29,7 +29,7 @@ import {
} from "fs-extra";
import * as HttpsProxyAgent from "https-proxy-agent";
import { marked } from "marked";
-import { EOL } from "os";
+import { EOL, platform } from "os";
import * as path from "path";
import * as url from "url";
import * as vscode from "vscode";
@@ -495,23 +495,25 @@ export function isJson(jsonString: string) {
}
export function execChildProcess(
- processStr: string,
+ command: string,
+ args: string[] = [],
workingDirectory: string,
channel?: vscode.OutputChannel,
- opts?: childProcess.ExecOptions,
+ opts?: childProcess.ExecFileOptions,
cancelToken?: vscode.CancellationToken
): Promise {
- const execOpts: childProcess.ExecOptions = opts
+ const execOpts: childProcess.ExecFileOptions = opts
? opts
: {
cwd: workingDirectory,
maxBuffer: 500 * 1024,
};
return new Promise((resolve, reject) => {
- childProcess.exec(
- processStr,
+ childProcess.execFile(
+ command,
+ args,
execOpts,
- (error: Error, stdout: string, stderr: string) => {
+ (error: Error | null, stdout: string, stderr: string) => {
if (cancelToken && cancelToken.isCancellationRequested) {
return reject(new Error("Process cancelled by user"));
}
@@ -523,7 +525,7 @@ export function execChildProcess(
}
if (stderr && stderr.length > 0) {
message += stderr;
- if (stderr.indexOf("Error") !== -1) {
+ if (stderr.includes("Error")) {
err = true;
}
}
@@ -545,8 +547,8 @@ export function execChildProcess(
}
if (stderr && stderr.length > 2) {
Logger.error(stderr, new Error(stderr));
- if (stderr.indexOf("Error") !== -1) {
- return reject(stderr);
+ if (stderr.includes("Error")) {
+ return reject(new Error(stderr));
}
}
return resolve(stdout.concat(stderr));
@@ -766,7 +768,8 @@ export async function checkGitExists(workingDir: string, gitPath: string) {
gitPath = gitInPath;
}
const gitRawVersion = await execChildProcess(
- `"${gitPath}" --version`,
+ gitPath,
+ ["--version"],
workingDir
);
const match = gitRawVersion.match(
@@ -795,7 +798,8 @@ export async function cleanDirtyGitRepository(
const workingDirUri = vscode.Uri.file(workingDir);
const modifiedEnv = appendIdfAndToolsToPath(workingDirUri);
const resetResult = await execChildProcess(
- `"${gitPath}" reset --hard --recurse-submodule`,
+ gitPath,
+ ["reset", "--hard", "--recurse-submodule"],
workingDir,
OutputChannel.init(),
{ env: modifiedEnv, cwd: workingDir }
@@ -820,13 +824,24 @@ export async function fixFileModeGitRepository(
const workingDirUri = vscode.Uri.file(workingDir);
const modifiedEnv = appendIdfAndToolsToPath(workingDirUri);
const fixFileModeResult = await execChildProcess(
- `"${gitPath}" config --local core.fileMode false`,
+ gitPath,
+ ["config", "--local", "core.fileMode", "false"],
workingDir,
OutputChannel.init(),
{ env: modifiedEnv, cwd: workingDir }
);
const fixSubmodulesFileModeResult = await execChildProcess(
- `"${gitPath}" submodule foreach --recursive git config --local core.fileMode false`,
+ gitPath,
+ [
+ "submodule",
+ "foreach",
+ "--recursive",
+ "git",
+ "config",
+ "--local",
+ "core.fileMode",
+ "false",
+ ],
workingDir,
OutputChannel.init(),
{ env: modifiedEnv, cwd: workingDir }
@@ -1103,7 +1118,8 @@ export async function startPythonReqsProcess(
);
const modifiedEnv = appendIdfAndToolsToPath(extensionContext.extensionUri);
return execChildProcess(
- `"${pythonBinPath}" "${reqFilePath}" -r "${requirementsPath}"`,
+ pythonBinPath,
+ [reqFilePath, "-r", requirementsPath],
extensionContext.extensionPath,
OutputChannel.init(),
{ env: modifiedEnv, cwd: extensionContext.extensionPath }
@@ -1227,3 +1243,42 @@ export function markdownToWebviewHtml(
cleanHtml = cleanHtml.replace(/</g, "<").replace(/>/g, ">");
return cleanHtml;
}
+
+export function getUserShell() {
+ if (idfConf.readParameter("idf.customTerminalExecutable")) {
+ return "custom";
+ }
+
+ const config = vscode.workspace.getConfiguration("terminal.integrated");
+
+ const shellWindows = config.get("defaultProfile.windows") as string;
+ const shellMac = config.get("defaultProfile.osx") as string;
+ const shellLinux = config.get("defaultProfile.linux") as string;
+
+ // list of shells to check
+ const shells = ["PowerShell", "Command Prompt", "bash", "zsh"];
+
+ // if user's shell is in the list, return it
+ for (let i = 0; i < shells.length; i++) {
+ if (shellWindows && shellWindows.includes(shells[i])) {
+ return shells[i];
+ } else if (shellMac && shellMac.includes(shells[i])) {
+ return shells[i];
+ } else if (shellLinux && shellLinux.includes(shells[i])) {
+ return shells[i];
+ }
+ }
+
+ // if no match or no defaultProfile, pick one based on user's OS
+ const userOS = platform();
+ if (userOS === "win32") {
+ return "PowerShell";
+ } else if (userOS === "darwin") {
+ return "zsh";
+ } else if (userOS === "linux") {
+ return "bash";
+ }
+
+ // if no match, return null
+ return null;
+}
diff --git a/src/views/setup/Install.vue b/src/views/setup/Install.vue
index ffc796edf..1fcda6c40 100644
--- a/src/views/setup/Install.vue
+++ b/src/views/setup/Install.vue
@@ -2,7 +2,7 @@
import { storeToRefs } from "pinia";
import { useSetupStore } from "./store";
import { SetupMode } from "./types";
-import { computed } from "vue";
+import { computed, watchEffect } from "vue";
import folderOpen from "./components/folderOpen.vue";
import selectEspIdf from "./components/selectEspIdf.vue";
import selectPyVersion from "./components/selectPyVersion.vue";
@@ -17,6 +17,9 @@ const {
pyExecErrorStatus,
toolsFolder,
setupMode,
+ selectedEspIdfVersion,
+ espIdf,
+ espIdfContainer,
} = storeToRefs(store);
const isNotWinPlatform = computed(() => {
@@ -27,6 +30,64 @@ const actionButtonText = computed(() => {
return setupMode.value === SetupMode.advanced ? "Configure Tools" : "Install";
});
+const hasToolsWhitespace = computed(() => {
+ return /\s/.test(toolsFolder.value);
+});
+
+const isVersionLessThanFive = computed(() => {
+ if (!selectedEspIdfVersion.value || !selectedEspIdfVersion.value.version) {
+ return false;
+ }
+
+ const versionString = selectedEspIdfVersion.value.version.match(
+ /(\d+\.\d+\.\d+|\d+\.\d+)/
+ );
+ if (!versionString) {
+ return false;
+ }
+
+ const version = versionString[0].split(".").map((num) => parseInt(num));
+ if (version[0] < 5) {
+ return true;
+ } else if (version[0] === 5 && version[1] === 0 && version[2] === 0) {
+ return true;
+ }
+
+ return false;
+});
+
+const hasWhitespaceInEspIdf = computed(() => {
+ return /\s/.test(espIdf.value);
+});
+
+const hasWhitespaceInEspIdfContainer = computed(() => {
+ return /\s/.test(espIdfContainer.value);
+});
+
+const isInstallDisabled = computed(() => {
+ return (
+ hasToolsWhitespace.value ||
+ (selectedEspIdfVersion.value.filename !== "manual" &&
+ isVersionLessThanFive.value &&
+ hasWhitespaceInEspIdfContainer.value) ||
+ !espIdf.value ||
+ !espIdfContainer.value ||
+ !toolsFolder.value
+ );
+});
+
+watchEffect(() => {
+ if (!hasWhitespaceInEspIdf.value) {
+ store.whiteSpaceErrorIDF = "";
+ }
+ if (!hasWhitespaceInEspIdfContainer.value) {
+ store.whiteSpaceErrorIDFContainer = "";
+ }
+ if (!hasToolsWhitespace.value) {
+ store.whiteSpaceErrorTools = "";
+ }
+});
+
function setEspIdfErrorStatus() {
store.espIdfErrorStatus = "";
}
@@ -42,6 +103,20 @@ function setToolsFolder(newToolsPath: string) {
+
+
{{ espIdfErrorStatus }}
+
+
+
+
+
+
+
{{ pyExecErrorStatus }}
+
+
+
+
+
-
-
-
-
{{ espIdfErrorStatus }}
-
-
-
-
+
-
+
+ White spaces are not allowed in the ESP-IDF Tools path.
+
-
-
{{ pyExecErrorStatus }}
-
-
-
+
+ ESP-IDF Tools path should not be empty.
+
+
{{ actionButtonText }}
diff --git a/src/views/setup/components/selectEspIdf.vue b/src/views/setup/components/selectEspIdf.vue
index ceb646694..c0b29a941 100644
--- a/src/views/setup/components/selectEspIdf.vue
+++ b/src/views/setup/components/selectEspIdf.vue
@@ -3,7 +3,7 @@ import { storeToRefs } from "pinia";
import { useSetupStore } from "../store";
import { IdfMirror } from "../types";
import folderOpen from "./folderOpen.vue";
-import { computed } from "vue";
+import { computed, watchEffect } from "vue";
const store = useSetupStore();
@@ -22,7 +22,7 @@ const {
} = storeToRefs(store);
const idfVersionList = computed(() => {
- if (showIdfTagList) {
+ if (showIdfTagList.value) {
const idfVersionWithTagsList = [...espIdfVersionList.value];
for (const idfTag of espIdfTags.value) {
const existingVersion = espIdfVersionList.value.find(
@@ -54,6 +54,60 @@ const resultingIdfPath = computed(() => {
store.pathSep
}esp-idf`;
});
+
+const isVersionLessThanFive = computed(() => {
+ if (!selectedEspIdfVersion.value || !selectedEspIdfVersion.value.version) {
+ return false;
+ }
+
+ const versionString = selectedEspIdfVersion.value.version.match(
+ /(\d+\.\d+\.\d+|\d+\.\d+)/
+ );
+ if (!versionString) {
+ return false;
+ }
+
+ const version = versionString[0].split(".").map((num) => parseInt(num));
+ if (version[0] < 5) {
+ return true;
+ } else if (version[0] === 5 && version[1] === 0 && version[2] === 0) {
+ return true;
+ }
+
+ return false;
+});
+
+const hasWhitespaceInEspIdf = computed(() => {
+ return /\s/.test(espIdf.value);
+});
+
+const hasWhitespaceInEspIdfContainer = computed(() => {
+ return /\s/.test(espIdfContainer.value);
+});
+
+const isPathEmpty = computed(() => {
+ if (selectedEspIdfVersion.value.filename === "manual") {
+ return !espIdf.value;
+ } else {
+ return !espIdfContainer.value;
+ }
+});
+
+const showManualVersionWarning = computed(() => {
+ return (
+ selectedEspIdfVersion.value.filename === "manual" &&
+ hasWhitespaceInEspIdf.value
+ );
+});
+
+watchEffect(() => {
+ if (!hasWhitespaceInEspIdf.value) {
+ store.whiteSpaceErrorIDF = "";
+ }
+ if (!hasWhitespaceInEspIdfContainer.value) {
+ store.whiteSpaceErrorIDFContainer = "";
+ }
+});
@@ -120,6 +174,24 @@ const resultingIdfPath = computed(() => {
selectedEspIdfVersion && selectedEspIdfVersion.filename !== 'manual'
"
/>
+
+ Make sure the ESP-IDF version is not lower than 5.0, since white spaces
+ are not supported for earlier versions.
+
+
+ White spaces are only supported for ESP-IDF path for versions > 5.0.
+
+
+ ESP-IDF path should not be empty.
+
diff --git a/src/views/setup/store.ts b/src/views/setup/store.ts
index 2ff140e25..49f338e92 100644
--- a/src/views/setup/store.ts
+++ b/src/views/setup/store.ts
@@ -72,6 +72,9 @@ export const useSetupStore = defineStore("setup", () => {
let pathSep: Ref
= ref("/");
let platform: Ref = ref("");
let pyExecErrorStatus: Ref = ref("");
+ let whiteSpaceErrorIDF: Ref = ref("");
+ let whiteSpaceErrorTools: Ref = ref("");
+ let whiteSpaceErrorIDFContainer: Ref = ref("");
let pyReqsLog: Ref = ref("");
let pyVersionsList: Ref = ref([]);
let saveScope: Ref = ref(1);
@@ -430,5 +433,8 @@ export const useSetupStore = defineStore("setup", () => {
openShowExamplesPanel,
requestInitValues,
toggleContent,
+ whiteSpaceErrorIDF,
+ whiteSpaceErrorTools,
+ whiteSpaceErrorIDFContainer,
};
});