Skip to content

Commit

Permalink
Create a project from external components (espressif#994)
Browse files Browse the repository at this point in the history
* Add link to display open Component Registry tab

* Add create project functionality

* Remove leftovers; Open new window

* Add progression notification

* Add documentation

* Fix for modified env
  • Loading branch information
radurentea authored Aug 30, 2023
1 parent a305386 commit 0de6afe
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 12 deletions.
2 changes: 1 addition & 1 deletion docs/SETTINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ The **Install ESP-MDF** command will clone ESP-MDF and set `idf.espMdfPath` (`id
The **Install ESP-Matter** command will clone ESP-Matter and set `idf.espMatterPath` (`idf.espMatterPathWin` in Windows). The **Set ESP-MATTER Device Path (ESP_MATTER_DEVICE_PATH)** is used to define the device path for ESP-Matter.
The **Install ESP-Rainmaker** command will clone ESP-Rainmaker and set `idf.espRainmakerPath` (`idf.espRainmakerPathWin` in Windows) configuration setting.

The **Show Examples Projects** command allows you create a new project using one of the examples in ESP-IDF, ESP-ADF, ESP-Matter or ESP-MDF directory if related configuration settings are set.
The **Show Examples Projects** command allows you create a new project using one of the examples in ESP-IDF, ESP-ADF, ESP-Matter or ESP-MDF directory if related configuration settings are set, or to create projects from examples found in the Component Registry.

## Use of environment variables in ESP-IDF settings.json and tasks.json

Expand Down
60 changes: 49 additions & 11 deletions src/component-manager/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ import { join } from "path";
import { Disposable, Uri, ViewColumn, WebviewPanel, window } from "vscode";
import { ESP } from "../config";
import { readParameter } from "../idfConfiguration";
import { addDependency } from "./utils";
import { addDependency, createProject } from "./utils";
import * as vscode from "vscode";

interface IMessage {
message: string;
example?: string;
dependency?: string;
component?: string;
}

export class ComponentManagerUIPanel {
private static instance: ComponentManagerUIPanel;
Expand Down Expand Up @@ -88,18 +96,48 @@ export class ComponentManagerUIPanel {
);
this.panel.webview.html = this.initWebView(url);
}
private onMessage(message: any) {
switch (message.message) {
case "install":
if (message.dependency) {
const component = message.component || "main";
addDependency(this.workspaceRoot, message.dependency, component);

private async onMessage(message: IMessage) {
switch (message.message) {
case "install":
if (!message.dependency) return;
const component = message.component || "main";
addDependency(this.workspaceRoot, message.dependency, component);
break;

case "create-project-from-example":
if (!message.example) return;

const selectedFolder = await vscode.window.showOpenDialog({
canSelectFolders: true,
canSelectFiles: false,
canSelectMany: false,
});

if(!selectedFolder) {
return;
}
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: "Creating project...",
cancellable: false
}, async () => {
await createProject(selectedFolder[0], message.example);
const match = message.example.match(/(?<=:).*/);
if(!match) {
return;
}
break;
default:
break;
}
let projectName = (process.platform === "win32" ? "\\" : "/") + match[0];
const projectPath = vscode.Uri.file(selectedFolder[0].fsPath + projectName);
await vscode.commands.executeCommand("vscode.openFolder", projectPath ,{ forceNewWindow: true});
});
break;

default:
break;
}
}

private initWebView(url: string): string {
return `<!DOCTYPE html>
<html lang="en">
Expand Down
43 changes: 43 additions & 0 deletions src/component-manager/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { existsSync } from 'fs';
import { Logger } from "../logger/logger";
import { spawn, appendIdfAndToolsToPath } from "../utils";
import { LocDictionary } from "../localizationDictionary";
Expand Down Expand Up @@ -62,3 +63,45 @@ export async function addDependency(
throw throwableError;
}
}

export async function createProject(
workspace: Uri,
example: string
): Promise<void> {
try {
const idfPathDir = readParameter("idf.espIdfPath");
const idfPy = join(idfPathDir, "tools", "idf.py");
const modifiedEnv = appendIdfAndToolsToPath(workspace);
const pythonBinPath = readParameter("idf.pythonBinPath") as string;

if (!existsSync(idfPathDir) || !existsSync(idfPy) || !existsSync(pythonBinPath)) {
throw new Error('The paths to idf, idf.py or pythonBin do not exist.');
}

const createProjectCommand: string[] = [idfPy, "create-project-from-example", `${example}`];

const createProjectResult = await spawn(
pythonBinPath,
createProjectCommand,
{
cwd: workspace.fsPath,
env: modifiedEnv,
}
);

Logger.infoNotify(
`Creating project from ${example}"`
);
Logger.info(createProjectResult.toString());

} catch (error) {
const throwableError = new Error(
`${locDict.localize(
"idfpy.commandError",
`Error encountered while creating project from example ${example}"`
)}. Original error: ${error.message}`
);
Logger.error(error.message, error);
throw throwableError;
}
}
10 changes: 10 additions & 0 deletions src/examples/ExamplesPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import * as utils from "../utils";
import { createExamplesHtml } from "./createExamplesHtml";
import { ESP } from "../config";
import { getExamplesList, IExampleCategory } from "./Example";
import { ComponentManagerUIPanel } from "../component-manager/panel";
import { OutputChannel } from "../logger/outputChannel";

const locDic = new LocDictionary("ExamplesPanel");

Expand Down Expand Up @@ -159,6 +161,14 @@ export class ExamplesPlanel {
}
}
break;
case "showRegistry":
const emptyURI: vscode.Uri = undefined;
try {
ComponentManagerUIPanel.show(extensionPath, emptyURI);
} catch (error) {
OutputChannel.appendLine(error.message);
Logger.errorNotify(error.message, error);
}
default:
return;
}
Expand Down
1 change: 1 addition & 0 deletions src/newProject/newProjectPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ export class NewProjectPanel {
}
}
} catch (error) {
OutputChannel.appendLine(error.message);
Logger.errorNotify(error.message, error);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/views/examples/Examples.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div id="examples-window">
<div id="sidenav" class="content">
<p>For external components examples, check <a v-on:click="showRegistry">IDF Component Registry</a></p>
<ul>
<ExampleList :node="exampleRootPath" :key="exampleRootPath.name" />
</ul>
Expand Down Expand Up @@ -45,6 +46,7 @@ export default class Examples extends Vue {
@State("selectedExample") private storeSelectedExample;
@Action("openExample") private storeOpenExample;
@Action private getExamplesList;
@Action private showRegistry;
get selectedExample() {
return this.storeSelectedExample;
Expand Down
5 changes: 5 additions & 0 deletions src/views/examples/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export const mutations: MutationTree<IState> = {
};

export const actions: ActionTree<IState, any> = {
showRegistry() {
vscode.postMessage({
command: "showRegistry",
});
},
getExamplesList() {
vscode.postMessage({ command: "getExamplesList" });
},
Expand Down

0 comments on commit 0de6afe

Please sign in to comment.