diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9eb43b58d..45e499231 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,33 +5,31 @@ name: Java CI with Maven on: push: - branches: [ master ] + branches: + - master + - release/** pull_request: - branches: [ master ] + branches: + - master + - release/** jobs: - build: + build_linux: - runs-on: - - self-hosted - - eclipse - - BrnoUBU0004 + runs-on: [self-hosted, eclipse, BrnoUBU0004] steps: - - uses: actions/checkout@v2 - - - name: Clone IDF Release From Github - uses: actions/checkout@v2 - with: - repository: espressif/esp-idf - path: dependencies/idf-tools - submodules: 'true' - ref: release/v5.4 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.10' + python-version: '3.10' + + - name: Install ESP-IDF via eim + uses: espressif/install-esp-idf-action@v1 + with: + version: 'v5.4' - name: Set up Maven uses: stCarolas/setup-maven@v5 @@ -42,8 +40,9 @@ jobs: uses: actions/setup-java@v4 with: java-version: '21' - distribution: 'temurin' - + distribution: 'temurin' + cache: 'maven' + - name: Build with Maven run: export NO_AT_BRIDGE=1 && mvn clean verify -Djarsigner.skip=true -DskipTests=false -DtestWorkspace=/opt/actions-runner/_work/workspace diff --git a/.github/workflows/ci_release.yml b/.github/workflows/ci_release.yml index f573ba395..bbc4858f0 100644 --- a/.github/workflows/ci_release.yml +++ b/.github/workflows/ci_release.yml @@ -4,7 +4,7 @@ on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" - - "v[0-9]+\\.[0-9]+\\.[0-9]+-beta" + - "v[0-9]+.[0-9]+.[0-9]+-beta.*" env: ARCHIVE_PREFIX: com.espressif.idf.update- diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index f17702167..1d2e10c18 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -5,9 +5,13 @@ name: Java CI with Maven on Windows on: push: - branches: [ master ] + branches: + - master + - release/** pull_request: - branches: [ master ] + branches: + - master + - release/** jobs: build_windows: diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml index db21711e6..8e895e186 100644 --- a/.github/workflows/docs_build.yml +++ b/.github/workflows/docs_build.yml @@ -38,7 +38,7 @@ jobs: # Update the path to include them and run. cd ./docs PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary - PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en + PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs - name: Archive Docs uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/docs_production.yml b/.github/workflows/docs_production.yml index e838dea50..7960ef853 100644 --- a/.github/workflows/docs_production.yml +++ b/.github/workflows/docs_production.yml @@ -46,7 +46,7 @@ jobs: echo "PIP install requirements..." pip3 install --user -r ./docs/requirements.txt echo "Building the Docs..." - cd ./docs && build-docs -l en + cd ./docs && build-docs echo "Deploy the Docs..." export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/ cd $GITHUB_WORKSPACE/docs diff --git a/bundles/com.espressif.idf.branding/META-INF/MANIFEST.MF b/bundles/com.espressif.idf.branding/META-INF/MANIFEST.MF index c5fdb4649..d40fa739b 100644 --- a/bundles/com.espressif.idf.branding/META-INF/MANIFEST.MF +++ b/bundles/com.espressif.idf.branding/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: com.espressif.idf.branding;singleton:=true -Bundle-Version: 3.7.0.qualifier +Bundle-Version: 4.0.0.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 diff --git a/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF b/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF index 05973eecf..9edd0e4e6 100644 --- a/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF +++ b/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF @@ -46,8 +46,10 @@ Export-Package: com.espressif.idf.core, com.espressif.idf.core.resources, com.espressif.idf.core.toolchain, com.espressif.idf.core.tools, + com.espressif.idf.core.tools.exceptions, com.espressif.idf.core.tools.util, com.espressif.idf.core.tools.vo, + com.espressif.idf.core.tools.watcher, com.espressif.idf.core.util, com.espressif.idf.core.variable, org.json.simple, diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java index 1338b5152..2fde5d21c 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java @@ -7,14 +7,11 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; -import com.espressif.idf.core.util.IDFUtil; - /** * @author Kondal Kolipaka * @@ -32,16 +29,6 @@ public class IDFCorePreferenceConstants public static final boolean CMAKE_CCACHE_DEFAULT_STATUS = true; public static final boolean AUTOMATE_BUILD_HINTS_DEFAULT_STATUS = true; public static final boolean HIDE_ERRORS_IDF_COMPONENTS_DEFAULT_STATUS = true; - public static final String IDF_GITHUB_ASSETS = "IDF_GITHUB_ASSETS"; //$NON-NLS-1$ - public static final String IDF_GITHUB_ASSETS_DEFAULT_GLOBAL = "dl.espressif.com/github_assets"; //$NON-NLS-1$ - public static final String IDF_GITHUB_ASSETS_DEFAULT_CHINA = "dl.espressif.cn/github_assets"; //$NON-NLS-1$ - public static final String PIP_EXTRA_INDEX_URL = "PIP_EXTRA_INDEX_URL"; //$NON-NLS-1$ - public static final String PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL = "https://dl.espressif.com/pypi"; //$NON-NLS-1$ - public static final String PIP_EXTRA_INDEX_URL_DEFAULT_CHINA = "https://dl.espressif.cn/pypi"; //$NON-NLS-1$ - public static final String IDF_TOOLS_PATH = "IDF_TOOLS_PATH"; //$NON-NLS-1$ - public static final String IDF_TOOLS_PATH_DEFAULT = Platform.getOS().equals(Platform.OS_WIN32) - ? IDFUtil.resolveEnvVariable("%USERPROFILE%\\.espressif") //$NON-NLS-1$ - : IDFUtil.resolveEnvVariable("$HOME/.espressif"); //$NON-NLS-1$ /** * Returns the node in the preference in the given context. diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFEnvironmentVariables.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFEnvironmentVariables.java index e60d02acd..480eb0b4e 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFEnvironmentVariables.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFEnvironmentVariables.java @@ -18,7 +18,6 @@ import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.StringUtil; /** @@ -52,6 +51,12 @@ public class IDFEnvironmentVariables public static final String IDF_CCACHE_ENABLE = "IDF_CCACHE_ENABLE"; //$NON-NLS-1$ + public static final String ESP_IDF_EIM_ID = "ESP_IDF_EIM_ID"; //$NON-NLS-1$ + + public static final String EIM_PATH = "EIM_PATH"; //$NON-NLS-1$ + + public static final String SYSTEM_PATH = "SYSTEM_PATH"; //$NON-NLS-1$ + /** * @param variableName Environment variable Name * @return IEnvironmentVariable @@ -129,16 +134,12 @@ public Map getSystemEnvMap() IEnvironmentVariableManager buildEnvironmentManager = CCorePlugin.getDefault().getBuildEnvironmentManager(); IEnvironmentVariable[] variables = buildEnvironmentManager.getVariables((ICConfigurationDescription) null, true); - Map envMap = IDFUtil.getSystemEnv(); + Map envMap = new HashMap(System.getenv()); if (variables != null) { for (IEnvironmentVariable iEnvironmentVariable : variables) { String key = iEnvironmentVariable.getName(); - if (key.equals(IDFCorePreferenceConstants.IDF_TOOLS_PATH)) - { - continue; - } String value = iEnvironmentVariable.getValue(); envMap.put(key, value); } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/bug/BugReportGenerator.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/bug/BugReportGenerator.java index 3663feb5c..31f3ea425 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/bug/BugReportGenerator.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/bug/BugReportGenerator.java @@ -323,16 +323,6 @@ private File getInstalledToolsInfoFile() throws IOException Logger.log(environment.toString()); environment.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - environment.put("IDF_GITHUB_ASSETS", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_GLOBAL, null)); - - environment.put("PIP_EXTRA_INDEX_URL", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL, null)); - if (StringUtil.isEmpty(gitExecutablePath)) { Logger.log("Git executable path is empty. Please check GIT_PATH environment variable."); //$NON-NLS-1$ diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java index 45220ff0c..c9694185c 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java @@ -359,9 +359,6 @@ private void runCmakeBuildCommand(IConsole console, IProgressMonitor monitor, IP } } - envVars.add(new EnvironmentVariable(IDFCorePreferenceConstants.IDF_TOOLS_PATH, - IDFUtil.getIDFToolsPathFromPreferences())); - String buildCommand = getProperty(BUILD_COMMAND); if (buildCommand.isBlank()) { @@ -481,10 +478,8 @@ private void runCmakeCommand(IConsole console, IProgressMonitor monitor, IProjec // Set PYTHONUNBUFFERED to 1/TRUE to dump the messages back immediately without // buffering IEnvironmentVariable bufferEnvVar = new EnvironmentVariable("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - IEnvironmentVariable idfToolsPathEnvVar = new EnvironmentVariable(IDFCorePreferenceConstants.IDF_TOOLS_PATH, - IDFUtil.getIDFToolsPathFromPreferences()); - Process p = startBuildProcess(command, new IEnvironmentVariable[] { bufferEnvVar, idfToolsPathEnvVar }, + Process p = startBuildProcess(command, new IEnvironmentVariable[] { bufferEnvVar }, workingDir, errConsole, monitor); if (p == null) { diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/Messages.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/Messages.java index 52b468c4e..1bcfde257 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/Messages.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/Messages.java @@ -33,8 +33,26 @@ public class Messages extends NLS public static String ToolsInitializationDifferentPathMessageBoxOptionYes; public static String ToolsInitializationDifferentPathMessageBoxOptionNo; public static String IDFToolChainsMissingErrorMsg; + + public static String ToolsInitializationEimMissingMsgBoxTitle; + public static String ToolsInitializationEimMissingMsgBoxMessage; public static String RefreshingProjects_JobName; + + public static String NoActiveEspIdfInWorkspaceMsgTitle; + public static String NoActiveEspIdfInWorkspaceMsg; + + public static String OldConfigFoundMsgBoxTitle; + public static String OldConfigFoundMsgBoxMsg; + public static String OldConfigExportDirectorSelectionDialogTitle; + public static String OldConfigExportDirectorSelectionDialogInfo; + public static String OldConfigExportCompleteSuccessMsgTitle; + public static String OldConfigExportCompleteSuccessMsg; + public static String OldConfigExportCompleteFailMsgTitle; + public static String OldConfigExportCompleteFailMsg; + + public static String EIMNotInApplicationsTitle; + public static String EIMNotInApplicationsMessage; static { diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/messages.properties b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/messages.properties index db0836990..4155b4dea 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/messages.properties +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/messages.properties @@ -19,9 +19,26 @@ IDFBuildConfiguration_ParseCommand=Parse Compile Commands File IncreasePartitionSizeTitle=Low Application Partition Size IncreasePartitionSizeMessage=Less than 30% of application partition size is free({0} of {1} bytes), would you like to increase it? Please click here to check more details. ToolsInitializationDifferentPathMessageBoxTitle=Different IDF path found in the config file +ToolsInitializationEimMissingMsgBoxTitle=ESP-IDF Installation Required +ToolsInitializationEimMissingMsgBoxMessage=ESP-IDF is not currently installed on your system.\n\nThe IDE can automatically download and launch the EIM - GUI Installer to help you install it.\n\nWould you like to proceed with the installation?\n\nOnce complete, ESP-IDF will be detected automatically. You can also manage installations later from the ESP-IDF Manager (Espressif > ESP-IDF Manager). ToolsInitializationDifferentPathMessageBoxMessage=A different ESP-IDF path was found in the esp_idf.json.json configuration file. Do you want to install the tools in the new path or the old path? Please click on the appropriate button.\nNew Path: {0}\nOld Path: {1} -ToolsInitializationDifferentPathMessageBoxOptionYes=Use New Path -ToolsInitializationDifferentPathMessageBoxOptionNo=Use Old Path +ToolsInitializationDifferentPathMessageBoxOptionYes=Yes +ToolsInitializationDifferentPathMessageBoxOptionNo=No RefreshingProjects_JobName=Refreshing Projects... IDFBuildConfiguration_PreCheck_DifferentIdfPath=The project was built using the ESP-IDF located at the {0} path.\nThe currently active ESP-IDF path in the IDE is {1}.\nPlease clean the project using "ESP-IDF:Project Full Clean" menu option to use the active ESP-IDF configuration. -IDFToolChainsMissingErrorMsg=Toolchains are missing. Please use ESP-IDF Manager for configuring \ No newline at end of file +IDFToolChainsMissingErrorMsg=Toolchains are missing. Please use ESP-IDF Manager for configuring + +NoActiveEspIdfInWorkspaceMsgTitle=ESP-IDF Setup +NoActiveEspIdfInWorkspaceMsg=ESP-IDF tools installed via EIM have been detected, but this workspace is not configured yet. The IDE needs to complete setup to enable full functionality. Would you like to proceed now? + +EIMNotInApplicationsTitle=EIM Not Located in Applications Folder +EIMNotInApplicationsMessage=Espressif Installation Manager (EIM) is not located in the Applications folder.\nRunning EIM from a temporary location (e.g., a mounted disk image) may cause issues during configuration import or tool setup.\nTo avoid problems, please move EIM to the /Applications directory and launch it from there. + +OldConfigFoundMsgBoxTitle=Old Configuration Detected +OldConfigFoundMsgBoxMsg=Espressif IDE now uses the EIM system to manage ESP-IDF installations. A legacy configuration was found in your current workspace. Converting it to the EIM format will allow proper environment setup and ensure the IDE works seamlessly with your existing projects. Would you like to convert the configuration now? +OldConfigExportDirectorSelectionDialogTitle=Select Destination +OldConfigExportDirectorSelectionDialogInfo=Choose a directory to save the exported settings. +OldConfigExportCompleteSuccessMsgTitle=Import Successful +OldConfigExportCompleteSuccessMsg=The old configuration has been successfully imported. +OldConfigExportCompleteFailMsgTitle=Conversion Failed +OldConfigExportCompleteFailMsg=An error occurred while importing old configuration. diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java index 897bdd92b..3d2ae93a9 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/logging/Logger.java @@ -20,6 +20,10 @@ */ public class Logger { + public static void log(String message, Exception e) + { + log(IDFCorePlugin.getPlugin(), message, e); + } public static void log(String message) { diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java index c647f6f4d..780973333 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/toolchain/ESPToolChainManager.java @@ -179,7 +179,7 @@ public File findToolChain(List paths, String filePattern) private Path[] getDirectories(String path) { - return Arrays.stream(path.split(File.pathSeparator)).map(String::trim).map(Paths::get).filter(Files::exists) + return Arrays.stream(path.split(File.pathSeparator)).map(String::trim).map(Paths::get).filter(Files::exists).filter(Files::isDirectory) .toArray(Path[]::new); } @@ -318,7 +318,7 @@ protected String getIdfToolsExportPath() Logger.log(commands.toString()); IStatus idfToolsExportStatus = new ProcessBuilderFactory().runInBackground(commands, - org.eclipse.core.runtime.Path.ROOT, IDFUtil.getSystemEnv()); + org.eclipse.core.runtime.Path.ROOT, System.getenv()); if (idfToolsExportStatus != null && idfToolsExportStatus.isOK()) { String message = idfToolsExportStatus.getMessage(); diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/DownloadListener.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/DownloadListener.java new file mode 100644 index 000000000..959713f13 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/DownloadListener.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +/** + * Interface to use for the download listening this can be used in your own classes. + * Added specifically for {@link EimLoader} + * @author Ali Azam Rana + * + */ +public interface DownloadListener +{ + public void onProgress(int percent); + public void onCompleted(String filePath); + public void onError(String message, Exception e); + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimConstants.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimConstants.java new file mode 100644 index 000000000..9ad370299 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimConstants.java @@ -0,0 +1,31 @@ +package com.espressif.idf.core.tools; + +import java.io.File; +import java.nio.file.Paths; + +public interface EimConstants +{ + String EIM_JSON = "eim_idf.json"; //$NON-NLS-1$ + + String EIM_POSIX_DIR = System.getProperty("user.home").concat(File.separator + ".espressif" + File.separator + "tools" + File.separator); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + + String EIM_WIN_ESPRESSIF_DIR = "C:" + File.separator + "Espressif"; //$NON-NLS-1$ //$NON-NLS-2$ + + String EIM_WIN_DIR = EIM_WIN_ESPRESSIF_DIR + File.separator + "tools" + File.separator; //$NON-NLS-1$ + + String EIM_WIN_PATH = EIM_WIN_DIR + EIM_JSON; + + String EIM_URL = "https://dl.espressif.com/dl/eim/"; //$NON-NLS-1$ + + String EIM_POSIX_PATH = EIM_POSIX_DIR + EIM_JSON; + + String INSTALL_TOOLS_FLAG = "INSTALL_TOOLS_FLAG"; //$NON-NLS-1$ + + String TOOL_SET_CONFIG_LEGACY_CONFIG_FILE = "tool_set_config.json"; //$NON-NLS-1$ + + String OLD_CONFIG_EXPORTED_FLAG = "OLD_CONFIG_EXPORTED_FLAG"; //$NON-NLS-1$ + + String USER_EIM_DIR = Paths.get(System.getProperty("user.home"), ".espressif", "eim_gui").toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + String EIM_JSON_VALID_VERSION = "1.0"; //$NON-NLS-1$ +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java new file mode 100644 index 000000000..05e38d7e1 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimIdfConfiguratinParser.java @@ -0,0 +1,58 @@ +package com.espressif.idf.core.tools; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.eclipse.core.runtime.Platform; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class EimIdfConfiguratinParser +{ + private EimJson eimJson; + private Gson gson; + + public EimIdfConfiguratinParser() + { + gson = new GsonBuilder().setPrettyPrinting().enableComplexMapKeySerialization() + .excludeFieldsWithoutExposeAnnotation().create(); + } + + private void load() throws IOException, EimVersionMismatchException + { + String path = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH + : EimConstants.EIM_POSIX_PATH; + + File file = new File(path); + if (!file.exists()) + { + Logger.log("EIM config file not found: " + path); //$NON-NLS-1$ + return; + } + + try (FileReader fileReader = new FileReader(file)) + { + eimJson = gson.fromJson(fileReader, EimJson.class); + } + + if (!eimJson.getVersion().equals(EimConstants.EIM_JSON_VALID_VERSION)) + { + throw new EimVersionMismatchException(EimConstants.EIM_JSON_VALID_VERSION,eimJson.getVersion()); + } + } + + public EimJson getEimJson(boolean reload) throws IOException, EimVersionMismatchException + { + if (reload || eimJson == null) + { + load(); + } + + return eimJson; + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java new file mode 100644 index 000000000..4db1005c2 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java @@ -0,0 +1,552 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.console.MessageConsoleStream; + +import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.watcher.EimJsonWatchService; +import com.espressif.idf.core.util.StringUtil; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * This class is responsible for downloading and launching the EIM. + * The clients using this must take care of UI refreshes and pausing any listeners. + * @author Ali Azam Rana + * + */ +public class EimLoader +{ + private static final String URL_JSON = "https://dl.espressif.com/dl/eim/eim_unified_release.json"; //$NON-NLS-1$ + private static final Path DOWNLOAD_DIR = Paths.get(System.getProperty("java.io.tmpdir"), "eim_gui"); //$NON-NLS-1$ //$NON-NLS-2$ + + private String os; + private String arch; + private DownloadListener listener; + private MessageConsoleStream standardConsoleStream; + private MessageConsoleStream errorConsoleStream; + private Display display; + private long windowsPid; + + public EimLoader(DownloadListener listener, MessageConsoleStream standardConsoleStream, MessageConsoleStream errorConsoleStream, Display display) + { + os = Platform.getOS(); + arch = Platform.getOSArch(); + this.listener = listener; + this.standardConsoleStream = standardConsoleStream; + this.errorConsoleStream = errorConsoleStream; + this.display = display; + } + + private void logMessage(String message) + { + display.asyncExec(()->{ + try + { + standardConsoleStream.write(message); + } + catch (IOException e) + { + Logger.log(e); + logError(e.getMessage()); + } + }); + + Logger.log(message); + } + + private void logError(String message) + { + display.asyncExec(()->{ + try + { + errorConsoleStream.write(message); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + Logger.log(message); + } + + public Process launchEim(String eimPath) throws IOException + { + if (!Files.exists(Paths.get(eimPath))) + throw new FileNotFoundException("EIM path not found: " + eimPath); //$NON-NLS-1$ + + String os = Platform.getOS(); + List command; + + if (os.equals(Platform.OS_WIN32)) + { + String escapedPathForPowershell = eimPath.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ + String powershellCmd = String.format( + "Start-Process -FilePath '%s' -PassThru | " //$NON-NLS-1$ + + "Select-Object -ExpandProperty Id", //$NON-NLS-1$ + escapedPathForPowershell); + + command = List.of("powershell.exe", //$NON-NLS-1$ + "-Command", powershellCmd); //$NON-NLS-1$ + } + else if (os.equals(Platform.OS_MACOSX)) + { + command = List.of("open", "-W", "-a", eimPath); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } + else if (os.equals(Platform.OS_LINUX)) + { + command = List.of("bash", "-c", "\"" + eimPath + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + else + { + throw new UnsupportedOperationException("Unsupported OS: " + os); //$NON-NLS-1$ + } + + Process process = new ProcessBuilder(command).redirectErrorStream(true).start(); + if (os.equals(Platform.OS_WIN32)) + { + // store the PID returned by powershell query to a variable + storePid(process); + } + + logMessage("Launched EIM application: " + eimPath + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + + return process; + } + + private void storePid(Process powershellProcess) + { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(powershellProcess.getInputStream()))) + { + String line; + while ((line = reader.readLine()) != null) + { + line = line.trim(); + if (!line.isEmpty()) + { + try + { + windowsPid = Long.parseLong(line); + + } + catch (NumberFormatException ignored) + { + // skipping invalid lines + } + } + } + } + catch (IOException e) + { + Logger.log(e); + } + } + + public String installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException + { + logMessage("Mounting DMG…\n"); //$NON-NLS-1$ + Process mountProcess = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()) //$NON-NLS-1$ //$NON-NLS-2$ + .redirectErrorStream(true).start(); + + int mountExit = mountProcess.waitFor(); + if (mountExit != 0) + throw new IOException("hdiutil attach failed (exit " + mountExit + "): " //$NON-NLS-1$ //$NON-NLS-2$ + + readProcessOutput(mountProcess)); + + String volumePath = parseVolumePath(mountProcess.getInputStream()); + if (volumePath == null) + throw new IOException("Failed to mount DMG: volume path not found."); //$NON-NLS-1$ + + File[] apps = new File(volumePath).listFiles((dir, name) -> name.endsWith(".app")); //$NON-NLS-1$ + if (apps == null || apps.length == 0) + throw new FileNotFoundException("No .app found inside DMG."); //$NON-NLS-1$ + + File appBundle = apps[0]; + Path targetAppPath = Paths.get("/Applications", appBundle.getName()); //$NON-NLS-1$ + + logMessage("Copying app to /Applications…\n"); //$NON-NLS-1$ + Process copyProcess = new ProcessBuilder("cp", "-R", appBundle.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$ + targetAppPath.toString()).redirectErrorStream(true).start(); + + int copyExit = copyProcess.waitFor(); + if (copyExit != 0) + throw new IOException("Copy failed (exit " + copyExit + "): " //$NON-NLS-1$ //$NON-NLS-2$ + + readProcessOutput(copyProcess)); + + logMessage("Unmounting DMG…\n"); //$NON-NLS-1$ + Process detachProcess = new ProcessBuilder("hdiutil", "detach", volumePath) //$NON-NLS-1$ //$NON-NLS-2$ + .redirectErrorStream(true).start(); + + int detachExit = detachProcess.waitFor(); + if (detachExit != 0) + throw new IOException("hdiutil detach failed (exit " + detachExit + "): " //$NON-NLS-1$ //$NON-NLS-2$ + + readProcessOutput(detachProcess)); + + String eimPath = targetAppPath.resolve("Contents/MacOS/eim").toString(); //$NON-NLS-1$ + new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimPath); + return eimPath; + } + + private String readProcessOutput(Process p) throws IOException + { + try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) + { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) sb.append(line).append(System.lineSeparator()); + return sb.toString(); + } + } + + private String parseVolumePath(InputStream mountOut) throws IOException + { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(mountOut))) + { + String line; + while ((line = reader.readLine()) != null) + { + if (line.contains("/Volumes/")) //$NON-NLS-1$ + { + for (String part : line.split("\t")) //$NON-NLS-1$ + if (part.startsWith("/Volumes/")) return part.trim(); //$NON-NLS-1$ + } + } + } + return null; + } + + + public void downloadEim(IProgressMonitor monitor) + { + try + { + JsonObject root = fetchJson(); + JsonArray assets = root.getAsJsonArray("assets"); //$NON-NLS-1$ + Optional match = findMatchingAsset(assets); + + if (match.isEmpty()) + { + listener.onError("No suitable EIM GUI asset found.", null); //$NON-NLS-1$ + monitor.done(); + return; + } + + JsonObject asset = match.get(); + String name = asset.get("name").getAsString(); //$NON-NLS-1$ + String downloadUrl = asset.get("browser_download_url").getAsString(); //$NON-NLS-1$ + + Files.createDirectories(DOWNLOAD_DIR); + cleanupDownloadDirectory(); + Path downloadPath = DOWNLOAD_DIR.resolve(name); + + downloadFile(downloadUrl, downloadPath, listener, monitor); + Path eimPath = Paths.get(EimConstants.USER_EIM_DIR); + Files.createDirectories(eimPath); + + if (name.endsWith(".zip")) //$NON-NLS-1$ + { + Path extracted = unzip(downloadPath, eimPath); + listener.onCompleted(extracted.toAbsolutePath().toString()); + } + else if (name.endsWith(".exe")) //$NON-NLS-1$ + { + eimPath = Paths.get(eimPath.toString(), name); + Files.copy(downloadPath, eimPath, StandardCopyOption.REPLACE_EXISTING); + listener.onCompleted(eimPath.toString()); + } + else + { + listener.onCompleted(downloadPath.toAbsolutePath().toString()); + } + } + catch (IOException e) + { + listener.onError("Download failed", e); //$NON-NLS-1$ + } finally + { + monitor.done(); + } + + } + + private IStatus waitForProcessWindows() + { + while (isWindowsProcessAlive(windowsPid)) + { + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { + Logger.log(e); + } + } + + return Status.OK_STATUS; + } + + private boolean isWindowsProcessAlive(long pid) + { + try + { + Process check = new ProcessBuilder("cmd.exe", //$NON-NLS-1$ + "/c", //$NON-NLS-1$ + "tasklist", //$NON-NLS-1$ + "/FI", //$NON-NLS-1$ + "\"PID eq " + pid + "\"").redirectErrorStream(true).start(); //$NON-NLS-1$ //$NON-NLS-2$ + try (BufferedReader reader = new BufferedReader(new InputStreamReader(check.getInputStream()))) + { + String line; + while ((line = reader.readLine()) != null) + { + if (line.contains(String.valueOf(windowsPid))) + { + return true; + } + } + } + } + catch (IOException e) + { + Logger.log(e); + } + + return false; + } + + private IStatus waitForProcess(Process process) + { + try + { + process.waitFor(); + return Status.OK_STATUS; + } + catch (InterruptedException e) + { + return Status.CANCEL_STATUS; + } + catch (Exception e) + { + Logger.log(e); + return Status.error(e.getMessage()); + } + } + + public void waitForEimClosure(Process process, Runnable callback) + { + Job waitJob = new Job("Wait for EIM Closure") //$NON-NLS-1$ + { + @Override + protected IStatus run(IProgressMonitor monitor) + { + return os.equals(Platform.OS_WIN32) ? waitForProcessWindows() : waitForProcess(process); + } + }; + waitJob.setSystem(true); + + + waitJob.addJobChangeListener(new JobChangeAdapter() + { + @Override + public void aboutToRun(IJobChangeEvent event) + { + EimJsonWatchService.getInstance().pauseListeners(); + } + + @Override + public void done(IJobChangeEvent event) + { + Display.getDefault().asyncExec(() -> { + try + { + standardConsoleStream.write("EIM has been closed.\n"); //$NON-NLS-1$ + } + catch (IOException e) + { + Logger.log(e); + } + }); + + if (callback != null) + { + callback.run(); + } + + EimJsonWatchService.getInstance().unpauseListeners(); + } + }); + + waitJob.schedule(); + } + + private JsonObject fetchJson() throws IOException + { + URL url = new URL(URL_JSON); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("accept", "application/json"); //$NON-NLS-1$//$NON-NLS-2$ + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) + { + return JsonParser.parseReader(reader).getAsJsonObject(); + } + } + + private void cleanupDownloadDirectory() + { + try + { + Files.list(DOWNLOAD_DIR) + .filter(Files::isRegularFile) + .forEach(path -> { + try + { + Files.deleteIfExists(path); + } + catch (IOException e) + { + Logger.log("Failed to delete old download: " + path); //$NON-NLS-1$ + } + }); + } + catch (IOException e) + { + Logger.log("Failed to clean up download directory: " + e.getMessage()); //$NON-NLS-1$ + } + } + + private Optional findMatchingAsset(JsonArray assets) + { + String osToken = switch (os) + { + case Platform.OS_WIN32 -> "windows"; //$NON-NLS-1$ + case Platform.OS_MACOSX -> "macos"; //$NON-NLS-1$ + case Platform.OS_LINUX -> "linux"; //$NON-NLS-1$ + default -> StringUtil.EMPTY; + }; + + String archToken = switch (arch) + { + case Platform.ARCH_X86_64 -> "x64"; //$NON-NLS-1$ + case Platform.ARCH_AARCH64, "arm64" -> "aarch64"; //$NON-NLS-1$ //$NON-NLS-2$ + default -> StringUtil.EMPTY; + }; + + for (int i = 0; i < assets.size(); i++) + { + JsonObject asset = assets.get(i).getAsJsonObject(); + String name = asset.get("name").getAsString().toLowerCase(); //$NON-NLS-1$ + if (name.contains("eim-gui") && //$NON-NLS-1$ + name.contains(osToken) && name.contains(archToken) + && (name.endsWith(".exe") || name.endsWith(".dmg") || name.endsWith(".zip"))) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + { + return Optional.of(asset); + } + } + + return Optional.empty(); + } + + private void downloadFile(String fileURL, Path targetPath, DownloadListener listener, IProgressMonitor monitor) + throws IOException + { + URL url = new URL(fileURL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + int contentLength = connection.getContentLength(); + monitor.beginTask("Downloading " + targetPath.getFileName(), contentLength); //$NON-NLS-1$ + + try (InputStream in = connection.getInputStream(); OutputStream out = Files.newOutputStream(targetPath)) + { + + byte[] buffer = new byte[8192]; + int bytesRead; + long totalRead = 0; + int lastPercent = 0; + + while ((bytesRead = in.read(buffer)) != -1) + { + out.write(buffer, 0, bytesRead); + totalRead += bytesRead; + if (contentLength > 0) + { + int percent = (int) ((totalRead * 100) / contentLength); + if (percent != lastPercent) + { + listener.onProgress(percent); + lastPercent = percent; + monitor.worked(bytesRead); + } + } + } + } + } + + private Path unzip(Path zipPath, Path destDir) throws IOException + { + Files.createDirectories(destDir); + Path firstExecutable = null; + + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath.toFile()))) + { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) + { + Path newPath = destDir.resolve(entry.getName()); + if (entry.isDirectory()) + { + Files.createDirectories(newPath); + } + else + { + Files.createDirectories(newPath.getParent()); + Files.copy(zis, newPath, StandardCopyOption.REPLACE_EXISTING); + if (firstExecutable == null && Files.isRegularFile(newPath)) + { + newPath.toFile().setExecutable(true); + firstExecutable = newPath; + } + } + } + } + return firstExecutable != null ? firstExecutable : destDir; + } + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsInstallationWizardConstants.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsInstallationWizardConstants.java deleted file mode 100644 index e64cb5bc8..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsInstallationWizardConstants.java +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright 2022 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools; - -/** - * Interface to store the constants related to tools management wizard - * - * @author Ali Azam Rana - * - */ -public interface IToolsInstallationWizardConstants -{ - String PYTHON_PATH_NODE_KEY = "PYTHON_EXECUTABLE"; //$NON-NLS-1$ - - String GIT_PATH_NODE_KEY = "GIT_EXECUTABLE"; //$NON-NLS-1$ - - String ESPRESSIF_LOGO = "icons/tools/espressif-logo.png"; //$NON-NLS-1$ - - String INSTALL_TOOLS_FLAG = "INSTALL_TOOLS_FLAG"; //$NON-NLS-1$ - - String TOOL_SET_CONFIG_FILE = "tool_set_config.json"; //$NON-NLS-1$ -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsJsonKeys.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsJsonKeys.java deleted file mode 100644 index bf8bc42ea..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/IToolsJsonKeys.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.espressif.idf.core.tools; - -/** - * Keys in the tools.json file mentioned here for the better usage - * - * @author Ali Azam Rana - * - */ -public interface IToolsJsonKeys -{ - String URL_KEY = "url"; //$NON-NLS-1$ - - String SIZE_KEY = "size"; //$NON-NLS-1$ - - String SHA256_KEY = "sha256"; //$NON-NLS-1$ - - String STATUS_KEY = "status"; //$NON-NLS-1$ - - String VERSION_KEY = "version"; //$NON-NLS-1$ - - String VERSIONS_VO_KEY = "versions"; //$NON-NLS-1$ - - String VERSION_CMD_KEY = "version_cmd"; //$NON-NLS-1$ - - String VERSION_REGEX = "version_regex"; //$NON-NLS-1$ - - String SUPPORTED_TARGETS_KEY = "supported_targets"; //$NON-NLS-1$ - - String NAME_KEY = "name"; //$NON-NLS-1$ - - String LICENSE_KEY = "license"; //$NON-NLS-1$ - - String INSTALL_KEY = "install"; //$NON-NLS-1$ - - String INFO_URL_KEY = "info_url"; //$NON-NLS-1$ - - String EXPORT_VARS_KEY = "export_vars"; //$NON-NLS-1$ - - String EXPORT_PATHS_KEY = "export_paths"; //$NON-NLS-1$ - - String DESCRIPTION_KEY = "description"; //$NON-NLS-1$ - - String TOOLS_KEY = "tools"; //$NON-NLS-1$ - - String PLATFORM_OVERRIDES_KEY = "platform_overrides"; //$NON-NLS-1$ - - String PLATFORMS_KEY = "platforms"; //$NON-NLS-1$ -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/JsonKey.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/JsonKey.java deleted file mode 100644 index 0eca4e6ff..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/JsonKey.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.espressif.idf.core.tools; - -import static java.lang.annotation.ElementType.FIELD; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(FIELD) -@Retention(RetentionPolicy.RUNTIME) -/** - * Annotation to apply a json key to the vos - * @author Ali Azam Rana - * - */ -public @interface JsonKey -{ - /** - * the json key name associated with the field - * @return JSON Key name associated with the field - */ - String key_name(); -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/Messages.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/Messages.java new file mode 100644 index 000000000..2723f7fdc --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/Messages.java @@ -0,0 +1,30 @@ +package com.espressif.idf.core.tools; + +import org.eclipse.osgi.util.NLS; + + +public class Messages extends NLS +{ + private static final String BUNDLE_NAME = "com.espressif.idf.core.tools.messages"; //$NON-NLS-1$ + + public static String InstallToolsHandler_CopyingOpenOCDRules; + public static String InstallToolsHandler_OpenOCDRulesCopyWarning; + public static String InstallToolsHandler_OpenOCDRulesCopyWarningMessage; + public static String InstallToolsHandler_OpenOCDRulesNotCopied; + public static String InstallToolsHandler_OpenOCDRulesCopyPaths; + public static String InstallToolsHandler_OpenOCDRulesCopyError; + public static String InstallToolsHandler_OpenOCDRulesCopied; + + public static String EimVersionMismatchExceptionMessage; + public static String EimVersionMismatchExceptionMessageTitle; + + static + { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() + { + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/SetupToolsInIde.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/SetupToolsInIde.java new file mode 100644 index 000000000..a4b603a7d --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/SetupToolsInIde.java @@ -0,0 +1,474 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.ui.console.MessageConsoleStream; + +import com.espressif.idf.core.IDFConstants; +import com.espressif.idf.core.IDFCorePlugin; +import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.ProcessBuilderFactory; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.toolchain.ESPToolChainManager; +import com.espressif.idf.core.tools.util.ToolsUtility; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.core.tools.vo.IdfInstalled; +import com.espressif.idf.core.util.IDFUtil; +import com.espressif.idf.core.util.StringUtil; + +/** + * This job is responsible for setting up the esp-idf in the IDE + * @author Ali Azam Rana + * + */ +public class SetupToolsInIde extends Job +{ + private EimJson eimJson; + private IdfInstalled idfInstalled; + private MessageConsoleStream errorConsoleStream; + private MessageConsoleStream standardConsoleStream; + private Map envVarsFromActivationScriptMap; + private Map existingEnvVarsInIdeForRollback; + + public SetupToolsInIde(IdfInstalled idfInstalled, EimJson eimJson, MessageConsoleStream errorConsoleStream, MessageConsoleStream standardConsoleStream) + { + super("Tools Setup"); //$NON-NLS-1$ + this.idfInstalled = idfInstalled; + this.eimJson = eimJson; + this.errorConsoleStream = errorConsoleStream; + this.standardConsoleStream = standardConsoleStream; + } + + @Override + protected IStatus run(IProgressMonitor monitor) + { + return setupTools(monitor); + } + + public void rollback() + { + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + + for (Entry entry : existingEnvVarsInIdeForRollback.entrySet()) + { + idfEnvironmentVariables.addEnvVariable(entry.getKey(), entry.getValue()); + } + IDFUtil.updateEspressifPrefPageOpenocdPath(); + try + { + setUpToolChainsAndTargets(true); + } + catch (Exception e) + { + Logger.log(e); + } + } + + private IStatus setupTools(IProgressMonitor monitor) + { + monitor.beginTask("Setting up tools in IDE", 7); //$NON-NLS-1$ + monitor.worked(1); + List arguemnts = new ArrayList<>(); + Map env = new HashMap<>(System.getenv()); + addGitToEnvironment(env, eimJson.getGitPath()); + arguemnts = ToolsUtility.getExportScriptCommand(idfInstalled.getActivationScript()); + final ProcessBuilderFactory processBuilderFactory = new ProcessBuilderFactory(); + try + { + monitor.setTaskName("Running Activation Script"); //$NON-NLS-1$ + IStatus status = processBuilderFactory.runInBackground(arguemnts, Path.ROOT, System.getenv()); + if (status == null) + { + Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Status returned null from activation script process", null)); //$NON-NLS-1$ + return IDFCorePlugin.errorStatus("Status returned null from activation script process", null); //$NON-NLS-1$ + } + + if (status.getSeverity() == IStatus.ERROR) + { + log(status.getException() != null ? status.getException().getMessage() : status.getMessage(), IStatus.ERROR); + return status; + } + + // now setup in IDE + + String activationScriptOutput = status.getMessage(); + if (StringUtil.isEmpty(activationScriptOutput)) + { + log("Activation Script Output must not be empty", IStatus.ERROR); //$NON-NLS-1$ + return IDFCorePlugin.errorStatus("Activation Script Output must not be empty", null); //$NON-NLS-1$ + } + + monitor.worked(1); + + log(activationScriptOutput, IStatus.OK); + monitor.setTaskName("Processing output from activation script"); //$NON-NLS-1$ + log("Processing output from activation script", IStatus.INFO); //$NON-NLS-1$ + envVarsFromActivationScriptMap = parseEnvKeys(activationScriptOutput); + monitor.worked(1); + + monitor.setTaskName("Setting up IDE environment"); //$NON-NLS-1$ + log("Setting up IDE environment variables", IStatus.INFO); //$NON-NLS-1$ + setupEnvVarsInEclipse(); + monitor.worked(1); + + monitor.setTaskName("Setting up toolchains"); //$NON-NLS-1$ + log("Setting up toolchains", IStatus.INFO); //$NON-NLS-1$ + setUpToolChainsAndTargets(false); + monitor.worked(1); + + monitor.setTaskName("Copying OpenOCD Rules"); //$NON-NLS-1$ + log("Copying OpenOCD Rules", IStatus.INFO); //$NON-NLS-1$ + copyOpenOcdRules(); + monitor.worked(1); + + log("Tools Setup complete", IStatus.INFO); //$NON-NLS-1$ + + return Status.OK_STATUS; + } + catch (IOException e) + { + Logger.log(e); + return IDFCorePlugin.errorStatus(e.getMessage(), e); + } + } + + private void copyOpenOcdRules() + { + if (Platform.getOS().equals(Platform.OS_LINUX) + && !IDFUtil.getOpenOCDLocation().equalsIgnoreCase(StringUtil.EMPTY)) + { + log(Messages.InstallToolsHandler_CopyingOpenOCDRules, IStatus.OK); + // Copy the rules to the idf + StringBuilder pathToRules = new StringBuilder(); + pathToRules.append(IDFUtil.getOpenOCDLocation()); + pathToRules.append("/../share/openocd/contrib/60-openocd.rules"); //$NON-NLS-1$ + File rulesFile = new File(pathToRules.toString()); + if (rulesFile.exists()) + { + java.nio.file.Path source = Paths.get(pathToRules.toString()); + java.nio.file.Path target = Paths.get("/etc/udev/rules.d/60-openocd.rules"); //$NON-NLS-1$ + log(String.format(Messages.InstallToolsHandler_OpenOCDRulesCopyPaths, source.toString(), + target.toString()), IStatus.OK); + + Display.getDefault().syncExec(new Runnable() + { + @Override + public void run() + { + try + { + if (target.toFile().exists()) + { + MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), + SWT.ICON_WARNING | SWT.YES | SWT.NO); + messageBox.setText(Messages.InstallToolsHandler_OpenOCDRulesCopyWarning); + messageBox.setMessage(Messages.InstallToolsHandler_OpenOCDRulesCopyWarningMessage); + int response = messageBox.open(); + if (response == SWT.YES) + { + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + } + else + { + log(Messages.InstallToolsHandler_OpenOCDRulesNotCopied, IStatus.ERROR); + return; + } + } + else + { + Files.copy(source, target); + } + + log(Messages.InstallToolsHandler_OpenOCDRulesCopied, IStatus.OK); + } + catch (IOException e) + { + Logger.log(e); + log(Messages.InstallToolsHandler_OpenOCDRulesCopyError, IStatus.ERROR); + } + } + }); + } + } + } + + private String getUpdatedPathWithSystemPath() + { + // EIM is giving us SYSTEM_PATH variable as well so we can simply add it to the PATH here and remove it from ENV vars + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + + String systemPath = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.SYSTEM_PATH); + String path = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH) + File.pathSeparator + systemPath; + + // we can remove the system_path from build vars as we dont need it here + idfEnvironmentVariables.removeEnvVariable(IDFEnvironmentVariables.SYSTEM_PATH); + + return path; + } + + private IStatus loadTargetsAvailableFromIdfInCurrentToolSet(boolean rollback) + { + List arguments = new ArrayList(); + arguments.add(rollback + ? existingEnvVarsInIdeForRollback.get(IDFEnvironmentVariables.PYTHON_EXE_PATH) + : idfInstalled.getPython()); + arguments + .add(IDFUtil + .getIDFPythonScriptFile( + rollback ? existingEnvVarsInIdeForRollback.get(IDFEnvironmentVariables.IDF_PATH) + : envVarsFromActivationScriptMap.get(IDFEnvironmentVariables.IDF_PATH)) + .getAbsolutePath()); + arguments.add(IDFConstants.IDF_LIST_TARGETS_CMD); + log("Executing:" + arguments.toString(), IStatus.OK); //$NON-NLS-1$ + + Map env = new HashMap(System.getenv()); + prepEnvMap(env); + ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); + StringBuilder output = new StringBuilder(); + int waitCount = 10; + try + { + Process process = processRunner.run(arguments, org.eclipse.core.runtime.Path.ROOT, env); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) + { + output.append(line).append(System.lineSeparator()); + } + + while (process.isAlive() && waitCount > 0) + { + try + { + Thread.sleep(300); + } + catch (InterruptedException e) + { + Logger.log(e); + } + waitCount--; + } + + if (waitCount == 0) + { + log("Process possibly stuck", IStatus.ERROR); //$NON-NLS-1$ + return Status.CANCEL_STATUS; + } + + IStatus status = new Status(process.exitValue() == 0 ? IStatus.OK : IStatus.ERROR, IDFCorePlugin.PLUGIN_ID, + process.exitValue(), output.toString(), null); + if (status.getSeverity() == IStatus.ERROR) + { + log(status.getException() != null ? status.getException().getMessage() : status.getMessage(), IStatus.ERROR); + } + + log(status.getMessage(), IStatus.OK); + + return status; + } + catch (IOException e) + { + log(e.getMessage(), e); + return IDFCorePlugin.errorStatus(e.getMessage(), e); + } + } + + private void prepEnvMap(Map env) + { + env.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ + loadIdfPathWithSystemPath(env); + addGitToEnvironment(env, eimJson.getGitPath()); + } + + private void loadIdfPathWithSystemPath(Map systemEnv) + { + String idfExportPath = envVarsFromActivationScriptMap.get(IDFEnvironmentVariables.PATH); + String pathVar = "PATH"; // for Windows //$NON-NLS-1$ + String pathEntry = systemEnv.get(pathVar); // $NON-NLS-1$ + if (pathEntry == null) + { + pathVar = "Path"; //$NON-NLS-1$ + pathEntry = systemEnv.get(pathVar); + if (pathEntry == null) // no idea + { + Logger.log(new Exception("No PATH found in the system environment variables")); //$NON-NLS-1$ + } + } + + if (!StringUtil.isEmpty(pathEntry)) + { + idfExportPath = idfExportPath.replace("$PATH", pathEntry); // macOS //$NON-NLS-1$ + idfExportPath = idfExportPath.replace("%PATH%", pathEntry); // Windows //$NON-NLS-1$ + } + systemEnv.put(pathVar, idfExportPath); + for (Entry entry : envVarsFromActivationScriptMap.entrySet()) + { + if (entry.getKey().equals(IDFEnvironmentVariables.PATH)) + continue; + + systemEnv.put(entry.getKey(), entry.getValue()); + } + } + + private void setUpToolChainsAndTargets(boolean rollback) + { + IStatus status = loadTargetsAvailableFromIdfInCurrentToolSet(rollback); + if (status.getSeverity() == IStatus.ERROR) + { + Logger.log("Unable to get IDF targets from current toolset"); //$NON-NLS-1$ + return; + } + + List targets = extractTargets(status.getMessage()); + ESPToolChainManager espToolChainManager = new ESPToolChainManager(); + espToolChainManager.removeLaunchTargetsNotPresent(targets); + espToolChainManager.removeCmakeToolChains(); + espToolChainManager.removeStdToolChains(); + espToolChainManager.configureToolChain(targets); + } + + private List extractTargets(String input) + { + List targets = new ArrayList(); + Pattern pattern = Pattern.compile("^esp32.*", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(input); + while (matcher.find()) + { + targets.add(matcher.group()); + } + return targets; + } + + private void setupEnvVarsInEclipse() + { + createExistingBackup(); + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + for (Entry entry : envVarsFromActivationScriptMap.entrySet()) + { + idfEnvironmentVariables.addEnvVariable(entry.getKey(), entry.getValue()); + } + + String path = getUpdatedPathWithSystemPath(); + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PATH, path); + + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, "1"); //$NON-NLS-1$ + // IDF_MAINTAINER=1 to be able to build with the clang toolchain + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_MAINTAINER, "1"); //$NON-NLS-1$ + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.ESP_IDF_EIM_ID, idfInstalled.getId()); + + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PYTHON_EXE_PATH, idfInstalled.getPython()); + + + + IDFUtil.updateEspressifPrefPageOpenocdPath(); + } + + private void createExistingBackup() + { + if (existingEnvVarsInIdeForRollback == null) + { + existingEnvVarsInIdeForRollback = new HashMap<>(); + } + + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + existingEnvVarsInIdeForRollback.putAll(idfEnvironmentVariables.getEnvMap()); + } + + private Map parseEnvKeys(String activationScriptOutput) + { + return Arrays.stream(activationScriptOutput.split(System.lineSeparator())).map(String::trim) + .filter(line -> line.contains("=")) //$NON-NLS-1$ + .map(line -> line.split("=", 2)) //$NON-NLS-1$ + .filter(parts -> parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty()) + .collect(Collectors.toMap(parts -> parts[0].trim(), parts -> parts[1].trim())); + } + + private void log(final String message, final int severity) + { + Logger.log(message); + if (severity == IStatus.ERROR) + { + printToErrorConsole(message); + } + else + { + printToStandardConsole(message); + } + + } + + private void log(final String message, Exception e) + { + Logger.log(message); + Logger.log(e); + printToErrorConsole(message); + + } + + private void printToErrorConsole(String message) + { + if (errorConsoleStream != null) + { + errorConsoleStream.println(message); + } + } + + private void printToStandardConsole(String message) + { + if (standardConsoleStream != null) + { + standardConsoleStream.println(message); + } + } + + private void addGitToEnvironment(Map envMap, String executablePath) + { + IPath gitPath = new Path(executablePath); + if (gitPath.toFile().exists()) + { + String gitDir = gitPath.removeLastSegments(1).toOSString(); + String path1 = envMap.get("PATH"); //$NON-NLS-1$ + String path2 = envMap.get("Path"); //$NON-NLS-1$ + if (!StringUtil.isEmpty(path1) && !path1.contains(gitDir)) // Git not found on the PATH environment + { + path1 = gitDir.concat(";").concat(path1); //$NON-NLS-1$ + envMap.put("PATH", path1); //$NON-NLS-1$ + } + else if (!StringUtil.isEmpty(path2) && !path2.contains(gitDir)) // Git not found on the Path environment + { + path2 = gitDir.concat(";").concat(path2); //$NON-NLS-1$ + envMap.put("Path", path2); //$NON-NLS-1$ + } + } + } + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java new file mode 100644 index 000000000..b577bbc1c --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolInitializer.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.osgi.service.prefs.Preferences; + +import com.espressif.idf.core.IDFCorePlugin; +import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.ProcessBuilderFactory; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.core.util.StringUtil; + +/** + * Initializer class to be used on startup of eclipse and also + * to help with tools initialization + * @author Ali Azam Rana + * + */ +public class ToolInitializer +{ + private final Preferences preferences; + private final EimIdfConfiguratinParser parser; + private IDFEnvironmentVariables idfEnvironmentVariables; + + public ToolInitializer(Preferences preferences) + { + this.preferences = preferences; + this.parser = new EimIdfConfiguratinParser(); + idfEnvironmentVariables = new IDFEnvironmentVariables(); + } + + public boolean isEimInstalled() + { + String eimExePathEnv = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH); + boolean exists = !StringUtil.isEmpty(eimExePathEnv) && Files.exists(Paths.get(eimExePathEnv)); + if (!exists) + { + // Fallback: check in user home .espressif/eim_gui folder + Path defaultEimPath = getDefaultEimPath(); + if (defaultEimPath != null) + exists = Files.exists(defaultEimPath); + } + return exists; + } + + public boolean isEimIdfJsonPresent() + { + String path = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH + : EimConstants.EIM_POSIX_PATH; + return new File(path).exists(); + } + + public EimJson loadEimJson() throws EimVersionMismatchException + { + try + { + return parser.getEimJson(true); + } + catch (IOException e) + { + Logger.log(e); + return null; + } + } + + public boolean isOldEspIdfConfigPresent() + { + return getOldConfigFile().exists(); + } + + public IStatus exportOldConfig(Path eimPath) throws IOException + { + File oldConfig = getOldConfigFile(); + if (oldConfig.exists()) + { + // eim import pathToOldConfigJson + List commands = new ArrayList<>(); + String eimPathStr = StringUtil.EMPTY; + + if (eimPath != null && Files.exists(eimPath)) + { + eimPathStr = eimPath.toString(); + } + else + { + return new Status(IStatus.ERROR, IDFCorePlugin.getId(), -1, "Cannot Convert EIM is not installed", null); //$NON-NLS-1$ + } + + + commands.add(eimPathStr); + commands.add("import"); //$NON-NLS-1$ + commands.add(oldConfig.getAbsolutePath()); + Logger.log("Running: " + commands.toString()); //$NON-NLS-1$ + ProcessBuilderFactory processBuilderFactory = new ProcessBuilderFactory(); + IStatus status = processBuilderFactory.runInBackground(commands, org.eclipse.core.runtime.Path.ROOT, + System.getenv()); + + Logger.log(status.getMessage()); + return status; + } + + return new Status(IStatus.ERROR, IDFCorePlugin.getId(), -1, "Error in conversion", null); //$NON-NLS-1$ + } + + public boolean isOldConfigExported() + { + return preferences.getBoolean(EimConstants.OLD_CONFIG_EXPORTED_FLAG, false); + } + + private File getOldConfigFile() + { + IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation(); + return new File(path.toOSString(), EimConstants.TOOL_SET_CONFIG_LEGACY_CONFIG_FILE); + } + + public boolean isEspIdfSet() + { + return preferences.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false); + } + + public Path getDefaultEimPath() + { + String userHome = System.getProperty("user.home"); //$NON-NLS-1$ + Path defaultEimPath; + String os = Platform.getOS(); + if (os.equals(Platform.OS_WIN32)) + { + defaultEimPath = Paths.get(userHome, ".espressif", "eim_gui", //$NON-NLS-1$//$NON-NLS-2$ + "eim.exe"); //$NON-NLS-1$ + } + else if (os.equals(Platform.OS_MACOSX)) + { + defaultEimPath = Paths.get("/Applications", //$NON-NLS-1$ + "eim.app", "Contents", //$NON-NLS-1$//$NON-NLS-2$ + "MacOS", "eim"); //$NON-NLS-1$ //$NON-NLS-2$ + } + else + { + defaultEimPath = Paths.get(userHome, ".espressif", //$NON-NLS-1$ + "eim_gui", "eim"); //$NON-NLS-1$//$NON-NLS-2$ + } + + return defaultEimPath; + } + + public void findAndSetEimPath() + { + Path defaultEimPath = getDefaultEimPath(); + + if (defaultEimPath != null) + setEimPathInEnvVar(defaultEimPath.toString()); + } + + private void setEimPathInEnvVar(String eimPath) + { + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimPath); + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolSetConfigurationManager.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolSetConfigurationManager.java deleted file mode 100644 index e24d81ee1..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolSetConfigurationManager.java +++ /dev/null @@ -1,279 +0,0 @@ -/******************************************************************************* - * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.cdt.cmake.core.ICMakeToolChainFile; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.toolchain.ESPToolChainManager; -import com.espressif.idf.core.toolchain.ESPToolchain; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; - -/** - * The class is responsible for managing the idf tool sets - * export and import configuration params from json in workspace - * - * @author Ali Azam Rana - * - */ -public class ToolSetConfigurationManager -{ - private List idfToolSets; - private Gson gson; - private boolean reload; - - public ToolSetConfigurationManager() - { - gson = new GsonBuilder().setPrettyPrinting().enableComplexMapKeySerialization() - .excludeFieldsWithoutExposeAnnotation().create(); - } - - public void delete(IDFToolSet idfToolSet) - { - reload = true; - getIdfToolSets(false); - // cleanup the env and toolchains - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - idfEnvironmentVariables.removeAllEnvVariables(); - try - { - ESPToolChainManager espToolChainManager = new ESPToolChainManager(); - espToolChainManager.removeCmakeToolChains(); - espToolChainManager.removeStdToolChains(); - } - catch (Exception e) - { - Logger.log(e); - } - - // update the json now to remove the idf from it. - List idfToolSetsToExport = new ArrayList(); - for (IDFToolSet idfTool : idfToolSets) - { - if (idfTool.getIdfLocation().equals(idfToolSet.getIdfLocation())) - { - continue; - } - - idfToolSetsToExport.add(idfTool); - } - - try (FileWriter fileWriter = new FileWriter(toolSetConfigFilePath())) - { - gson.toJson(idfToolSetsToExport, fileWriter); - } - catch (IOException e) - { - Logger.log(e); - } - getIdfToolSets(false); - reload = false; - } - - public boolean isToolSetAlreadyPresent(String idfPath) - { - List idfToolSets = getIdfToolSets(false); - if (idfToolSets == null) - { - return false; - } - return idfToolSets.stream().filter(toolSet -> toolSet.getIdfLocation().equals(idfPath)).findAny().isPresent(); - } - - public List getIdfToolSets(boolean loadToolchains) - { - if (reload || idfToolSets == null || idfToolSets.isEmpty()) - { - idfToolSets = importToolSets(); - } - - if (loadToolchains && idfToolSets != null) - { - try - { - loadToolChainsInImportedToolSets(); - } - catch (CoreException e) - { - Logger.log(e); - } - } - return idfToolSets; - } - - private List importToolSets() - { - Type listType = new TypeToken>() - { - }.getType(); - List idfToolSets = new ArrayList<>(); - File toolSetFile = new File(toolSetConfigFilePath()); - if (!toolSetFile.exists()) - { - try - { - toolSetFile.createNewFile(); - } - catch (IOException e) - { - Logger.log(e); - } - } - - try (FileReader fileReader = new FileReader(toolSetConfigFilePath())) - { - idfToolSets = gson.fromJson(fileReader, listType); - } - catch (IOException e) - { - Logger.log(e); - } - - return idfToolSets; - } - - private void loadToolChainsInImportedToolSets() throws CoreException - { - ESPToolChainManager espToolChainManager = new ESPToolChainManager(); - for (IDFToolSet idfToolSet : idfToolSets) - { - String pathToLookForToolChains = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.PATH); - String idfPath = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.IDF_PATH); - Logger.log("Using: " + idfPath + " to find toolchains"); //$NON-NLS-1$//$NON-NLS-2$ - Logger.log("Env used: " + idfToolSet.getEnvVars()); //$NON-NLS-1$ - List espToolChains = espToolChainManager - .getStdToolChains(Arrays.asList(pathToLookForToolChains.split(File.pathSeparator)), idfPath); - idfToolSet.setEspStdToolChains(espToolChains); - List cMakeToolChainFiles = espToolChainManager.getCmakeToolChains(idfPath); - idfToolSet.setEspCmakeToolChainFiles(cMakeToolChainFiles); - } - } - - /** - * Looks for the existing idf tools from the given location if they are found it replaces the previous one - * - * @param idfToolSet IDFToolSet to add {@link IDFToolSet}@ - */ - public void export(IDFToolSet idfToolSet) - { - File toolSetConfigFile = new File(toolSetConfigFilePath()); - List idfToolSets = null; - Type listType = new TypeToken>() - { - }.getType(); - - if (toolSetConfigFile.exists()) - { - try (FileReader fileReader = new FileReader(toolSetConfigFile)) - { - idfToolSets = gson.fromJson(fileReader, listType); - } - catch (IOException e) - { - Logger.log(e); - return; - } - } - if (idfToolSets == null) - { - idfToolSets = new ArrayList<>(); - } - - // If the toolSet to be exported is active, set all others to inactive - if (idfToolSet.isActive()) - { - for (IDFToolSet toolSet : idfToolSets) - { - toolSet.setActive(false); // Set all to inactive - } - } - - boolean found = false; - for (int i = 0; i < idfToolSets.size(); i++) - { - IDFToolSet existingToolSet = idfToolSets.get(i); - if (existingToolSet.getId() == idfToolSet.getId()) - { - idfToolSets.set(i, idfToolSet); - found = true; - break; - } - } - - // If the toolSet was not found, add it to the list - if (!found) - { - idfToolSets.add(idfToolSet); - } - - try (FileWriter fileWriter = new FileWriter(toolSetConfigFile)) - { - gson.toJson(idfToolSets, fileWriter); - } - catch (IOException e) - { - Logger.log(e); - } - - } - - public void updateToolSetConfiguration(IDFToolSet idfToolSet) - { - reload = true; - getIdfToolSets(false); - List idfToolSetsToExport = new ArrayList(); - for (IDFToolSet existingIdfToolSet : idfToolSets) - { - if (idfToolSet.getId() == existingIdfToolSet.getId()) - { - idfToolSetsToExport.add(idfToolSet); - } - else - { - idfToolSetsToExport.add(existingIdfToolSet); - } - } - - try (FileWriter fileWriter = new FileWriter(toolSetConfigFilePath())) - { - gson.toJson(idfToolSets, fileWriter); - } - catch (IOException e) - { - Logger.log(e); - } - } - - private String toolSetConfigFilePath() - { - IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation(); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(path.toOSString()); - stringBuilder.append(File.separatorChar); - stringBuilder.append(IToolsInstallationWizardConstants.TOOL_SET_CONFIG_FILE); - return stringBuilder.toString(); - } - - public void setReload(boolean reload) - { - this.reload = reload; - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsJsonParser.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsJsonParser.java deleted file mode 100644 index bb35f5d14..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsJsonParser.java +++ /dev/null @@ -1,238 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.InputStreamReader; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.core.runtime.Platform; - -import com.espressif.idf.core.tools.vo.ToolsVO; -import com.espressif.idf.core.tools.vo.VersionDetailsVO; -import com.espressif.idf.core.tools.vo.VersionsVO; -import com.espressif.idf.core.util.IDFUtil; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.stream.JsonReader; - -/** - * Tools json parser. - * - * @author Ali Azam Rana - * - */ -public class ToolsJsonParser -{ - private Gson gson; - private List toolsList; - private List requiredToolsList; - private static final String[] REQUIRED_TOOLS = new String[] {"cmake", "dfu-util", "ninja"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - public ToolsJsonParser() - { - gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); - toolsList = new ArrayList<>(); - requiredToolsList = new ArrayList<>(); - } - - public void loadJson() throws Exception - { - toolsList.clear(); - JsonReader jsonReader = new JsonReader(new FileReader(IDFUtil.getIDFToolsJsonFileForInstallation())); - JsonObject jsonObject = gson.fromJson(jsonReader, JsonObject.class); - JsonArray jsonArray = jsonObject.get(IToolsJsonKeys.TOOLS_KEY).getAsJsonArray(); - List reqToolsNamesList = Arrays.asList(REQUIRED_TOOLS); - for (int i = 0; i < jsonArray.size(); i++) - { - JsonObject toolsJsonObject = jsonArray.get(i).getAsJsonObject(); - ToolsVO toolsVO = new ToolsVO(); - toolsVO.setDescription(toolsJsonObject.get(IToolsJsonKeys.DESCRIPTION_KEY).getAsString()); - if (toolsJsonObject.get(IToolsJsonKeys.EXPORT_PATHS_KEY).getAsJsonArray().size() > 0) - { - toolsVO.setExportPaths(getStringsListFromJsonArray( - toolsJsonObject.get(IToolsJsonKeys.EXPORT_PATHS_KEY).getAsJsonArray().get(0).getAsJsonArray())); - } - toolsVO.setExportVars( - getExportVarsMapFromJsonObject(toolsJsonObject.get(IToolsJsonKeys.EXPORT_VARS_KEY).getAsJsonObject())); - toolsVO.setInfoUrl(toolsJsonObject.get(IToolsJsonKeys.INFO_URL_KEY).getAsString()); - toolsVO.setInstallType(toolsJsonObject.get(IToolsJsonKeys.INSTALL_KEY).getAsString()); - toolsVO.setLicesnse(toolsJsonObject.get(IToolsJsonKeys.LICENSE_KEY).getAsString()); - toolsVO.setName(toolsJsonObject.get(IToolsJsonKeys.NAME_KEY).getAsString()); - if (toolsJsonObject.get(IToolsJsonKeys.SUPPORTED_TARGETS_KEY) != null) - { - toolsVO.setSupportedTargets( - getStringsListFromJsonArray(toolsJsonObject.get(IToolsJsonKeys.SUPPORTED_TARGETS_KEY).getAsJsonArray())); - } - toolsVO.setVersionCmd(getStringsListFromJsonArray(toolsJsonObject.get(IToolsJsonKeys.VERSION_CMD_KEY).getAsJsonArray())); - toolsVO.setVersionRegex(toolsJsonObject.get(IToolsJsonKeys.VERSION_REGEX).getAsString()); - toolsVO.setVersionVO(getVersions(toolsJsonObject.get(IToolsJsonKeys.VERSIONS_VO_KEY).getAsJsonArray())); - toolsVO.setVersion(jsonObject.get(IToolsJsonKeys.VERSION_KEY).getAsString()); - JsonElement jsonElement = toolsJsonObject.get(IToolsJsonKeys.PLATFORM_OVERRIDES_KEY); - if (jsonElement != null) - { - adjustPlatformOverrides(jsonElement.getAsJsonArray(), toolsVO); - } - - toolsList.add(toolsVO); - if (reqToolsNamesList.contains(toolsVO.getName())) - { - requiredToolsList.add(toolsVO); - } - } - } - - private void adjustPlatformOverrides(JsonArray jsonArray, ToolsVO toolsVO) throws Exception - { - String currentOS = Platform.getOS(); - if (currentOS.equals(Platform.OS_WIN32)) - { - currentOS = "win"; //$NON-NLS-1$ - } - - if (currentOS.contains(Platform.OS_MACOSX)) - { - Process p = Runtime.getRuntime().exec("uname -m"); //$NON-NLS-1$ - InputStreamReader inputStreamReader = new InputStreamReader(p.getInputStream()); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - String output = bufferedReader.readLine(); - if (!output.contains("arm64")) //$NON-NLS-1$ - { - currentOS = "macos"; //$NON-NLS-1$ - } - else - { - currentOS = "macos-".concat(output); //$NON-NLS-1$ - inputStreamReader.close(); - bufferedReader.close(); - } - } - - for (int i = 0; i < jsonArray.size(); i++) - { - JsonObject jsonObject = jsonArray.get(i).getAsJsonObject(); - JsonArray platformArray = jsonObject.get(IToolsJsonKeys.PLATFORMS_KEY).getAsJsonArray(); - for (int j = 0; j < platformArray.size(); j++) - { - String platform = platformArray.get(j).getAsString(); - if (platform.contains(currentOS)) - { - Set keys = jsonObject.keySet(); - keys.remove(IToolsJsonKeys.PLATFORMS_KEY); - for(String key : keys) - { - JsonElement element = jsonObject.get(key); - if (element.isJsonArray()) - { - List list = getStringsListFromJsonArray(element.getAsJsonArray().get(0).getAsJsonArray()); - injectOverride(toolsVO, key, list); - } - else - { - injectOverride(toolsVO, key, element.getAsString()); - } - } - } - } - } - } - - private void injectOverride(ToolsVO toolsVO, String key, Object val) throws Exception - { - Field[] allFields = ToolsVO.class.getDeclaredFields(); - for (Field field : allFields) - { - if (field.isAnnotationPresent(JsonKey.class)) - { - JsonKey ann = field.getAnnotation(JsonKey.class); - if (ann.key_name().equals(key)) - { - field.trySetAccessible(); - field.set(toolsVO, val); - return; - } - } - } - } - - private List getVersions(JsonArray jsonArray) - { - List versionsVOs = new ArrayList(); - for (int i = 0; i < jsonArray.size(); i++) - { - JsonObject jsonObject = jsonArray.get(i).getAsJsonObject(); - VersionsVO versionsVO = new VersionsVO(); - Map versionDetailMap = new HashMap<>(); - for (String key : jsonObject.keySet()) - { - if (key.equalsIgnoreCase(IToolsJsonKeys.NAME_KEY) || key.equalsIgnoreCase(IToolsJsonKeys.STATUS_KEY)) - { - continue; - } - - VersionDetailsVO versionDetailsVO = new VersionDetailsVO(); - JsonObject osVersionDetailsObject = jsonObject.get(key).getAsJsonObject(); - versionDetailsVO.setSha256(osVersionDetailsObject.get(IToolsJsonKeys.SHA256_KEY).getAsString()); - versionDetailsVO.setSize(osVersionDetailsObject.get(IToolsJsonKeys.SIZE_KEY).getAsDouble()); - versionDetailsVO.setUrl(osVersionDetailsObject.get(IToolsJsonKeys.URL_KEY).getAsString()); - versionDetailMap.put(key, versionDetailsVO); - } - - versionsVO.setName(jsonObject.get(IToolsJsonKeys.NAME_KEY).getAsString()); - versionsVO.setStatus(jsonObject.get(IToolsJsonKeys.STATUS_KEY).getAsString()); - versionsVO.setVersionOsMap(versionDetailMap); - versionsVOs.add(versionsVO); - - } - - return versionsVOs; - } - - private List getStringsListFromJsonArray(JsonArray jsonArray) - { - List stringList = new ArrayList(); - if (jsonArray == null) - { - return stringList; - } - - for (int i = 0; i < jsonArray.size(); i++) - { - stringList.add(jsonArray.get(i).getAsString()); - } - return stringList; - } - - private Map getExportVarsMapFromJsonObject(JsonObject exportVars) - { - Map exportVarMap = new HashMap<>(); - for (String key : exportVars.keySet()) - { - exportVarMap.put(key, exportVars.get(key).getAsString()); - } - return exportVarMap; - } - - public List getToolsList() - { - return toolsList; - } - - public List getRequiredToolsList() - { - return requiredToolsList; - - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsPlatformMapping.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsPlatformMapping.java deleted file mode 100644 index 853e4363f..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsPlatformMapping.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright 2022 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools; - -import java.util.Arrays; - -import org.eclipse.core.runtime.Platform; - -import com.espressif.idf.core.logging.Logger; - -/** - * Mapping /tools/tools.json os to Eclipse platform os & arch - * - * @author kondal kolipaka - * - */ -public enum ToolsPlatformMapping -{ - // @formatter:off - - WIN32("win32", Platform.OS_WIN32,Platform.ARCH_X86), //$NON-NLS-1$ - WIN64("win64", Platform.OS_WIN32, Platform.ARCH_X86_64), //$NON-NLS-1$ - MACOS("macos", Platform.OS_MACOSX, Platform.ARCH_X86_64), //$NON-NLS-1$ - MACOSARM64("macos-arm64", Platform.OS_MACOSX, Platform.ARCH_AARCH64), //$NON-NLS-1$ - LINUXAMD64("linux-amd64", Platform.OS_LINUX, Platform.ARCH_X86_64), //$NON-NLS-1$ - LINUXARM64("linux-arm64", Platform.OS_LINUX, "arm64"), //$NON-NLS-1$ //$NON-NLS-2$ - LINUXARMEL("linux-armel", Platform.OS_LINUX, "armel"), //$NON-NLS-1$ //$NON-NLS-2$ - LINUXARMHF("linux-armhf", Platform.OS_LINUX, "armhf"), //$NON-NLS-1$ //$NON-NLS-2$ - LINUXI686("linux-i686", Platform.OS_LINUX, "i686"); //$NON-NLS-1$ //$NON-NLS-2$ - - // @formatter:on - - private final String toolsOS; - private final String os; - private final String arch; - - ToolsPlatformMapping(String toolsOS, String os, String arch) - { - this.toolsOS = toolsOS; - this.os = os; - this.arch = arch; - } - - public String getToolsOS() - { - return toolsOS; - } - - public String getOS() - { - return os; - } - - public String getArch() - { - return arch; - } - - public static boolean isSupported(String toolsOS) - { - final String os = Platform.getOS(); - final String arch = Platform.getOSArch(); - Logger.log("toolsOS:" + toolsOS + " os:" + os + " arch:" + arch, true); - - return Arrays.stream(ToolsPlatformMapping.values()).filter( - entry -> entry.getToolsOS().equals(toolsOS) && entry.getArch().equals(arch) && entry.getOS().equals(os)) - .count() > 0; - } - -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java deleted file mode 100644 index 5ac2d9356..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright 2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools; - -import com.espressif.idf.core.SystemWrapper; - -/** - * Tools System wrapper to make sure to avoid the - * system path when verifying for validation after tools installation - * @author Ali Azam Rana - * - */ -public class ToolsSystemWrapper implements SystemWrapper -{ - private String path; - - public ToolsSystemWrapper(String path) - { - this.path = path; - } - - @Override - public String getPathEnv() - { - return path; - } - - @Override - public String getEnvExecutables() - { - return System.getenv(PATHEXT); - } - -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/exceptions/EimVersionMismatchException.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/exceptions/EimVersionMismatchException.java new file mode 100644 index 000000000..39ff8fbee --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/exceptions/EimVersionMismatchException.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.exceptions; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.Messages; + +/** + * Exception to be thrown when the EIM version found + * does not match the expected version + * @author Ali Azam Rana + * */ +public class EimVersionMismatchException extends Exception +{ + private static final long serialVersionUID = 4471390598613711666L; + private final String expectedVersion; + private final String foundVersion; + + public EimVersionMismatchException(String expectedVersion, String foundVersion) + { + super(String.format(Messages.EimVersionMismatchExceptionMessage, expectedVersion, foundVersion)); + Logger.log(String.format("Invalid eim_idf.json version. Expected: %s, but found: %s.", expectedVersion, foundVersion)); //$NON-NLS-1$ + this.expectedVersion = expectedVersion; + this.foundVersion = foundVersion; + } + + public String getExpectedVersion() + { + return expectedVersion; + } + + public String getFoundVersion() + { + return foundVersion; + } + + public String msgTitle() + { + return Messages.EimVersionMismatchExceptionMessageTitle; + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/messages.properties b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/messages.properties new file mode 100644 index 000000000..3e7e30171 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/messages.properties @@ -0,0 +1,10 @@ +InstallToolsHandler_CopyingOpenOCDRules=Copying OpenOCD Rules +InstallToolsHandler_OpenOCDRulesCopyPaths=Copying File: %s to destination: %s +InstallToolsHandler_OpenOCDRulesCopyWarning=Warning +InstallToolsHandler_OpenOCDRulesCopyWarningMessage=The rules file is already present in the /etc/udev/rules.d/ directory, Do you want to replace the file with the file from OpenOCD directory +InstallToolsHandler_OpenOCDRulesNotCopied=Rules Not Copied to system +InstallToolsHandler_OpenOCDRulesCopyError=Unable to copy rules for OpenOCD to system directory, try running the eclipse with sudo command +InstallToolsHandler_OpenOCDRulesCopied=Rules Copied to system + +EimVersionMismatchExceptionMessage=Invalid eim_idf.json version. Expected: %s, but found: %s.\nThe IDE may not function correctly. +EimVersionMismatchExceptionMessageTitle=EIM Version Mismatch \ No newline at end of file diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java index 843d430f0..637b85369 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java @@ -4,41 +4,17 @@ *******************************************************************************/ package com.espressif.idf.core.tools.util; -import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.security.MessageDigest; -import java.text.DecimalFormat; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; -import org.tukaani.xz.XZInputStream; import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.SystemExecutableFinder; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.ToolsSystemWrapper; -import com.espressif.idf.core.tools.vo.ToolsVO; -import com.espressif.idf.core.util.FileUtil; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.StringUtil; +import com.espressif.idf.core.tools.vo.IdfInstalled; /** * Utility class for Tools Management operations @@ -48,285 +24,78 @@ */ public class ToolsUtility { - private static final String SLASH = "\\"; //$NON-NLS-1$ - - private static final String FORWARD_SLASH = "/"; //$NON-NLS-1$ - - public static final String ESPRESSIF_HOME_DIR = System.getProperty("user.home").concat("/.espressif"); //$NON-NLS-1$ //$NON-NLS-2$ - - public static final String ESPRESSIF_HOME_TOOLS_DIR = ESPRESSIF_HOME_DIR.concat("/tools"); //$NON-NLS-1$ - - public static boolean isToolInstalled(String toolName, String versionsName) + public static String getIdfVersion(IdfInstalled idfInstalled, String gitPath) { - File homeDir = new File(ESPRESSIF_HOME_DIR); - if (!homeDir.exists()) - { - return false; - } + String activationScript = idfInstalled.getActivationScript(); + String espIdfVersion = null; - File toolDirectory = new File(ESPRESSIF_HOME_TOOLS_DIR.concat(FORWARD_SLASH).concat(toolName) - .concat(FORWARD_SLASH).concat(versionsName)); - if (toolDirectory.exists()) - { - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - String pathValue = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH); - String[] splittedPaths = pathValue.split(File.pathSeparator); - String directorySplittor = Platform.getOS().equals(Platform.OS_WIN32) ? SLASH : FORWARD_SLASH; - for (String splittedPath : splittedPaths) - { - if (splittedPath.contains(toolName.concat(directorySplittor).concat(versionsName))) - { - return true; - } - } - } - - return false; - } - - public static void removeToolDirectory(String toolName) throws IOException - { - File toolDirectory = new File(ESPRESSIF_HOME_TOOLS_DIR.concat(FORWARD_SLASH).concat(toolName)); - if (!toolDirectory.exists()) + try { - return; - } - FileUtil.deleteDirectory(toolDirectory); - } + // Determine the command to execute based on the OS + List args = getExportScriptCommand(activationScript); + String[] command = args.toArray(new String[args.size()]); + // Execute the script + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.directory(new File(activationScript).getParentFile()); + processBuilder.redirectErrorStream(true); - public static String getFileExtension(String filename) - { - return Optional.ofNullable(filename).filter(f -> f.contains(".")) //$NON-NLS-1$ - .map(f -> f.substring(filename.lastIndexOf(".") + 1)).get(); //$NON-NLS-1$ - } + Process process = processBuilder.start(); - public static void extractZip(String zipFilePath, String extractDirectory) - { - InputStream inputStream = null; - try - { - Path filePath = Paths.get(zipFilePath); - inputStream = Files.newInputStream(filePath); - ArchiveStreamFactory archiveStreamFactory = new ArchiveStreamFactory(); - ArchiveInputStream archiveInputStream = archiveStreamFactory - .createArchiveInputStream(ArchiveStreamFactory.ZIP, inputStream); - ArchiveEntry archiveEntry = null; - while ((archiveEntry = archiveInputStream.getNextEntry()) != null) + // Read the script output + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - Path path = Paths.get(extractDirectory, archiveEntry.getName()); - File file = path.toFile(); - if (archiveEntry.isDirectory()) - { - if (!file.isDirectory()) - { - file.mkdirs(); - } - } - else + String line; + while ((line = reader.readLine()) != null) { - File parent = file.getParentFile(); - if (!parent.isDirectory()) - { - parent.mkdirs(); - } - try (OutputStream outputStream = Files.newOutputStream(path)) + if (line.startsWith("ESP_IDF_VERSION=")) //$NON-NLS-1$ { - IOUtils.copy(archiveInputStream, outputStream); + espIdfVersion = line.split("=")[1]; //$NON-NLS-1$ + break; } } } - } - catch (Exception e) - { - Logger.log(e); - } - } - public static void extractTarGz(String tarFile, String outputDir) - { - Path pathInput = Paths.get(tarFile); - Path pathOutput = Paths.get(outputDir); - try - { - TarArchiveInputStream tararchiveinputstream = new TarArchiveInputStream( - new GzipCompressorInputStream(new BufferedInputStream(Files.newInputStream(pathInput)))); - - ArchiveEntry archiveentry = null; - while ((archiveentry = tararchiveinputstream.getNextEntry()) != null) - { - Path pathEntryOutput = pathOutput.resolve(archiveentry.getName()); - if (archiveentry.isDirectory()) - { - if (!Files.exists(pathEntryOutput)) - Files.createDirectories(pathEntryOutput); - } - else - { - Files.createDirectories(pathEntryOutput.getParent()); - Files.copy(tararchiveinputstream, pathEntryOutput, StandardCopyOption.REPLACE_EXISTING); - Runtime.getRuntime().exec("/bin/chmod 755 ".concat(pathEntryOutput.toString())); //$NON-NLS-1$ - } - - } - - tararchiveinputstream.close(); + process.waitFor(); } catch (Exception e) { Logger.log(e); } - } - - public static void extractTarXz(String tarFile, String outputDir) - { - Path pathOutput = Paths.get(outputDir); - Map symLinks = new HashMap<>(); - Map hardLinks = new HashMap<>(); - try - { - FileInputStream fileInputStream = new FileInputStream(tarFile); - BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); - XZInputStream xzInputStream = new XZInputStream(bufferedInputStream); - TarArchiveInputStream tararchiveinputstream = new TarArchiveInputStream(xzInputStream); - TarArchiveEntry archiveentry = null; - while ((archiveentry = tararchiveinputstream.getNextTarEntry()) != null) - { - Path pathEntryOutput = pathOutput.resolve(archiveentry.getName()); - if (archiveentry.isSymbolicLink()) - { - symLinks.put(pathEntryOutput, - pathOutput.resolve(archiveentry.getName()).getParent().resolve(archiveentry.getLinkName())); - continue; - } - else if (archiveentry.isLink()) - { - hardLinks.put(pathEntryOutput, - pathOutput.resolve(archiveentry.getLinkName())); - continue; - } - else if (archiveentry.isDirectory()) - { - if (!Files.exists(pathEntryOutput)) - Files.createDirectories(pathEntryOutput); - } - else - { - System.out.println(pathEntryOutput.toString() + " " + archiveentry.getSize()); //$NON-NLS-1$ - Files.copy(tararchiveinputstream, pathEntryOutput, StandardCopyOption.REPLACE_EXISTING); - Runtime.getRuntime().exec("/bin/chmod 755 ".concat(pathEntryOutput.toString())); //$NON-NLS-1$ - } - } - tararchiveinputstream.close(); - xzInputStream.close(); - fileInputStream.close(); - hardLinks.forEach(ToolsUtility::createHardLinks); - symLinks.forEach(ToolsUtility::createSymLinks); - } - catch (Exception e) - { - Logger.log(e); - } - } - - private static void createHardLinks(Path link, Path target) - { - try - { - Files.deleteIfExists(link); - Files.createLink(link, target); - } - catch (Exception e) - { - Logger.log(e); - } - } - - private static void createSymLinks(Path link, Path target) - { - try - { - Files.deleteIfExists(link); - Files.createSymbolicLink(link, target.toRealPath()); - } - catch (Exception e) - { - Logger.log(e); - } - } - public static String getReadableSizeMB(double size) - { - size /= 1024; // KB - size /= 1024; // MB - DecimalFormat df = new DecimalFormat("0.00"); //$NON-NLS-1$ - return String.valueOf(df.format(size)).concat(" MB"); //$NON-NLS-1$ + return espIdfVersion; } - - public static Map getAvailableToolVersions(ToolsVO toolsVo) + + public static List getExportScriptCommand(String activationScriptPath) { - Map availableVersions = new HashMap(); - File toolDirectory = new File( - ESPRESSIF_HOME_TOOLS_DIR.concat(FORWARD_SLASH).concat(toolsVo.getName()).concat(FORWARD_SLASH)); - if (toolDirectory.exists()) + List command = new ArrayList<>(); + if (Platform.getOS().equals(Platform.OS_WIN32)) { - for (File file : toolDirectory.listFiles()) - { - if (file.isDirectory()) - { - availableVersions.put(file.getName(), file.getAbsolutePath()); - } - } + command.add("powershell.exe"); //$NON-NLS-1$ + command.add("-ExecutionPolicy"); //$NON-NLS-1$ + command.add("Bypass"); //$NON-NLS-1$ + command.add("-File"); //$NON-NLS-1$ + command.add(activationScriptPath); + command.add("-e"); //$NON-NLS-1$ } - - return availableVersions; - } - - /** - * Gets the file checksum based on the provided message digest - * - * @param digest - * @param file - * @return - * @throws IOException - */ - public static String getFileChecksum(MessageDigest digest, File file) throws IOException - { - FileInputStream fis = new FileInputStream(file); - byte[] byteArray = new byte[1024]; - int bytesCount = 0; - while ((bytesCount = fis.read(byteArray)) != -1) + else if (Platform.getOS().equals(Platform.OS_LINUX)) { - digest.update(byteArray, 0, bytesCount); + command.add("/bin/bash"); //$NON-NLS-1$ + command.add(activationScriptPath); + command.add("-e"); //$NON-NLS-1$ } - ; - fis.close(); - byte[] bytes = digest.digest(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < bytes.length; i++) + else { - sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); + command.add("/bin/zsh"); //$NON-NLS-1$ + command.add(activationScriptPath); + command.add("-e"); //$NON-NLS-1$ } - return sb.toString(); + return command; } - /** - * Gets the absolute path for the tool from the given path - * @param toolName tool to find absolute path - * @param path the path to variable to look into, if null System.getenv() will be used - * @return absolute path to the tool - */ - public static IPath findAbsoluteToolPath(String toolName, String path) + public static boolean isIdfInstalledActive(IdfInstalled idfInstalled) { - if (StringUtil.isEmpty(path)) - { - Map env = IDFUtil.getSystemEnv(); - if (env.containsKey(IDFEnvironmentVariables.PATH)) - path = env.get(IDFEnvironmentVariables.PATH); - else - path = env.get("Path"); //$NON-NLS-1$ - } - - SystemExecutableFinder systemExecutableFinder = new SystemExecutableFinder(new ToolsSystemWrapper(path)); - return systemExecutableFinder.find(toolName); + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + String espIdfIdEim = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.ESP_IDF_EIM_ID); + return idfInstalled.getId().equals(espIdfIdEim); } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/EimJson.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/EimJson.java new file mode 100644 index 000000000..d3f3bbe10 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/EimJson.java @@ -0,0 +1,71 @@ +package com.espressif.idf.core.tools.vo; + +import java.util.Collections; +import java.util.List; + +import com.google.gson.annotations.Expose; + +public class EimJson +{ + @Expose + private String version; + @Expose + private String eimPath; + @Expose + private String gitPath; + @Expose + private String idfSelectedId; + @Expose + private List idfInstalled = Collections.emptyList(); + + public String getGitPath() + { + return gitPath; + } + + public void setGitPath(String gitPath) + { + this.gitPath = gitPath; + } + + public String getIdfSelectedId() + { + return idfSelectedId; + } + + public void setIdfSelectedId(String idfSelectedId) + { + this.idfSelectedId = idfSelectedId; + } + + public List getIdfInstalled() + { + return idfInstalled; + } + + public void setIdfInstalled(List idfInstalled) + { + this.idfInstalled = idfInstalled; + } + + public String getEimPath() + { + return eimPath; + } + + public void setEimPath(String eimPath) + { + this.eimPath = eimPath; + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IDFToolSet.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IDFToolSet.java deleted file mode 100644 index 50a750b54..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IDFToolSet.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools.vo; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.cmake.core.ICMakeToolChainFile; - -import com.espressif.idf.core.toolchain.ESPToolchain; -import com.google.gson.annotations.Expose; - -/** - * VO to hold the idf tools information that is read or exported to the configuration json - * - * @author Ali Azam Rana - * - */ -public class IDFToolSet implements Serializable -{ - private static final long serialVersionUID = -4899224940094139736L; - - @Expose - private int id; - - @Expose - private String idfLocation; - - @Expose - private String idfVersion; - - @Expose - private boolean active; - - @Expose - private String systemGitExecutablePath; - - @Expose - private String systemPythonExecutablePath; - - @Expose - private Map envVars; - - private List espStdToolChains; - private List espCmakeToolChainFiles; - private List launchTargets; - - public String getIdfLocation() - { - return idfLocation; - } - - public void setIdfLocation(String idfLocation) - { - this.idfLocation = idfLocation; - } - - public String getIdfVersion() - { - return idfVersion; - } - - public void setIdfVersion(String idfVersion) - { - this.idfVersion = idfVersion; - } - - public boolean isActive() - { - return active; - } - - public void setActive(boolean active) - { - this.active = active; - } - - public Map getEnvVars() - { - return envVars; - } - - public void setEnvVars(Map envVars) - { - this.envVars = envVars; - } - - public List getEspStdToolChains() - { - return espStdToolChains; - } - - public void setEspStdToolChains(List espStdToolChains) - { - this.espStdToolChains = espStdToolChains; - } - - public List getEspCmakeToolChainFiles() - { - return espCmakeToolChainFiles; - } - - public void setEspCmakeToolChainFiles(List espCmakeToolChainFiles) - { - this.espCmakeToolChainFiles = espCmakeToolChainFiles; - } - - public List getLaunchTargets() - { - return launchTargets; - } - - public void setLaunchTargets(List launchTargets) - { - this.launchTargets = launchTargets; - } - - public int getId() - { - return id; - } - - public void setId(int id) - { - this.id = id; - } - - @Override - public int hashCode() - { - return idfLocation.hashCode(); - } - - public String getSystemGitExecutablePath() - { - return systemGitExecutablePath; - } - - public void setSystemGitExecutablePath(String systemGitExecutablePath) - { - this.systemGitExecutablePath = systemGitExecutablePath; - } - - public String getSystemPythonExecutablePath() - { - return systemPythonExecutablePath; - } - - public void setSystemPythonExecutablePath(String systemPythonExecutablePath) - { - this.systemPythonExecutablePath = systemPythonExecutablePath; - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IdfInstalled.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IdfInstalled.java new file mode 100644 index 000000000..2e0d4ae9a --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/IdfInstalled.java @@ -0,0 +1,80 @@ +package com.espressif.idf.core.tools.vo; + +import com.google.gson.annotations.Expose; + +public class IdfInstalled +{ + @Expose + private String activationScript; + @Expose + private String id; + @Expose + private String idfToolsPath; + @Expose + private String name; + @Expose + private String path; + @Expose + private String python; + + public String getActivationScript() + { + return activationScript; + } + + public void setActivationScript(String activationScript) + { + this.activationScript = activationScript; + } + + public String getId() + { + return id; + } + + public void setId(String id) + { + this.id = id; + } + + public String getIdfToolsPath() + { + return idfToolsPath; + } + + public void setIdfToolsPath(String idfToolsPath) + { + this.idfToolsPath = idfToolsPath; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getPath() + { + return path; + } + + public void setPath(String path) + { + this.path = path; + } + + public String getPython() + { + return python; + } + + public void setPython(String python) + { + this.python = python; + } + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java deleted file mode 100644 index 92ab5bf9e..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java +++ /dev/null @@ -1,259 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools.vo; - -import java.text.DecimalFormat; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import org.eclipse.core.runtime.Platform; - -import com.espressif.idf.core.tools.IToolsJsonKeys; -import com.espressif.idf.core.tools.JsonKey; - -/** - * Bean class for tools information from json - * - * @author Ali Azam Rana - * - */ -public class ToolsVO -{ - @JsonKey(key_name = IToolsJsonKeys.DESCRIPTION_KEY) - private String description; - - @JsonKey(key_name = IToolsJsonKeys.EXPORT_PATHS_KEY) - private List exportPaths; - - @JsonKey(key_name = IToolsJsonKeys.EXPORT_VARS_KEY) - private Map exportVars; - - @JsonKey(key_name = IToolsJsonKeys.INFO_URL_KEY) - private String infoUrl; - - @JsonKey(key_name = IToolsJsonKeys.INSTALL_KEY) - private String installType; - - @JsonKey(key_name = IToolsJsonKeys.LICENSE_KEY) - private String licesnse; - - @JsonKey(key_name = IToolsJsonKeys.NAME_KEY) - private String name; - - @JsonKey(key_name = IToolsJsonKeys.SUPPORTED_TARGETS_KEY) - private List supportedTargets; - - @JsonKey(key_name = IToolsJsonKeys.VERSION_CMD_KEY) - private List versionCmd; - - @JsonKey(key_name = IToolsJsonKeys.VERSION_REGEX) - private String versionRegex; - - @JsonKey(key_name = IToolsJsonKeys.VERSIONS_VO_KEY) - private List versionVOs; - - @JsonKey(key_name = IToolsJsonKeys.VERSION_KEY) - private String version; - - private boolean installed; - - private static final String MAC_OS = "mac"; //$NON-NLS-1$ - private static final String LINUX_OS = "linux"; //$NON-NLS-1$ - private static final String WIN_OS = "win"; //$NON-NLS-1$ - - public String getDescription() - { - return description; - } - - public void setDescription(String description) - { - this.description = description; - } - - public List getExportPaths() - { - return exportPaths; - } - - public void setExportPaths(List exportPaths) - { - this.exportPaths = exportPaths; - } - - public String getInfoUrl() - { - return infoUrl; - } - - public void setInfoUrl(String infoUrl) - { - this.infoUrl = infoUrl; - } - - public Map getExportVars() - { - return exportVars; - } - - public void setExportVars(Map exportVars) - { - this.exportVars = exportVars; - } - - public String getInstallType() - { - return installType; - } - - public void setInstallType(String installType) - { - this.installType = installType; - } - - public String getLicesnse() - { - return licesnse; - } - - public void setLicesnse(String licesnse) - { - this.licesnse = licesnse; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public List getSupportedTargets() - { - return supportedTargets; - } - - public void setSupportedTargets(List supportedTargets) - { - this.supportedTargets = supportedTargets; - } - - public List getVersionCmd() - { - return versionCmd; - } - - public void setVersionCmd(List versionCmd) - { - this.versionCmd = versionCmd; - } - - public String getVersion() - { - return version; - } - - public void setVersion(String version) - { - this.version = version; - } - - public List getVersionVO() - { - return versionVOs; - } - - public void setVersionVO(List versionVO) - { - this.versionVOs = versionVO; - } - - public double getSize() - { - double totalSize = 0; - String key = null; - if (Platform.getOS().equals(Platform.OS_WIN32)) - { - key = WIN_OS; - } - else if (Platform.getOS().equals(Platform.OS_LINUX)) - { - key = LINUX_OS; - } - else if (Platform.getOS().equals(Platform.OS_MACOSX)) - { - key = MAC_OS; - } - - for (VersionsVO versionVO : versionVOs) - { - totalSize += versionVO.getVersionOsMap().get(key).getSize(); - } - - return totalSize; - } - - public String getReadableSize() - { - double totalSize = getSize(); - totalSize /= 1024; // KB - totalSize /= 1024; // MB - DecimalFormat df = new DecimalFormat("0"); //$NON-NLS-1$ - return String.valueOf(df.format(totalSize)).concat(" MB"); //$NON-NLS-1$ - } - - public boolean isInstalled() - { - return installed; - } - - public void setInstalled(boolean installed) - { - this.installed = installed; - } - - public String getVersionRegex() - { - return versionRegex; - } - - public void setVersionRegex(String versionRegex) - { - this.versionRegex = versionRegex; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - ToolsVO other = (ToolsVO) obj; - return Objects.equals(description, other.description) - && Objects.equals(exportPaths, other.exportPaths) - && Objects.equals(exportVars, other.exportVars) - && Objects.equals(infoUrl, other.infoUrl) - && Objects.equals(installType, other.installType) - && Objects.equals(licesnse, other.licesnse) - && Objects.equals(name, other.name) - && Objects.equals(supportedTargets, other.supportedTargets) - && Objects.equals(versionCmd, other.versionCmd) - && Objects.equals(versionRegex, other.versionRegex) - && Objects.equals(versionVOs, other.versionVOs) - && Objects.equals(version, other.version) - && installed == other.installed; - } - - @Override - public int hashCode() - { - return Objects.hash(description, exportPaths, exportVars, infoUrl, installType, licesnse, name, supportedTargets, versionCmd, versionRegex, versionVOs, version, installed); - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java deleted file mode 100644 index a9a2122b0..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools.vo; - -import java.text.DecimalFormat; -import java.util.Objects; - -/** - * Version details vo for the versions class - * - * @author Ali Azam Rana - * - */ -public class VersionDetailsVO -{ - private String sha256; - - private double size; - - private String url; - - private boolean selected; - - public String getSha256() - { - return sha256; - } - - public void setSha256(String sha256) - { - this.sha256 = sha256; - } - - public double getSize() - { - return size; - } - - public void setSize(double size) - { - this.size = size; - } - - public String getUrl() - { - return url; - } - - public void setUrl(String url) - { - this.url = url; - } - - public String getReadableSize() - { - double totalSize = getSize(); - totalSize /= 1024; // KB - totalSize /= 1024; // MB - DecimalFormat df = new DecimalFormat("0"); - return String.valueOf(df.format(totalSize)).concat(" MB"); - } - - public boolean isSelected() - { - return selected; - } - - public void setSelected(boolean selected) - { - this.selected = selected; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - VersionDetailsVO other = (VersionDetailsVO) obj; - return Double.compare(size, other.size) == 0 - && selected == other.selected - && Objects.equals(sha256, other.sha256) - && Objects.equals(url, other.url); - } - - @Override - public int hashCode() - { - return Objects.hash(sha256, size, url, selected); - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java deleted file mode 100644 index ac871a78a..000000000 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.core.tools.vo; - -import java.util.Map; -import java.util.Objects; - -/** - * Versions class for versions information in tools json - * - * @author Ali Azam Rana - * - */ -public class VersionsVO -{ - private String name; - - private String status; - - private Map versionOsMap; - - private boolean isAvailable; - - private String availablePath; - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getStatus() - { - return status; - } - - public void setStatus(String status) - { - this.status = status; - } - - public Map getVersionOsMap() - { - return versionOsMap; - } - - public void setVersionOsMap(Map versionOsMap) - { - this.versionOsMap = versionOsMap; - } - - public boolean isAvailable() - { - return isAvailable; - } - - public void setAvailable(boolean isAvailable) - { - this.isAvailable = isAvailable; - } - - public String getAvailablePath() - { - return availablePath; - } - - public void setAvailablePath(String availablePath) - { - this.availablePath = availablePath; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - VersionsVO other = (VersionsVO) obj; - return isAvailable == other.isAvailable - && Objects.equals(name, other.name) - && Objects.equals(status, other.status) - && Objects.equals(versionOsMap, other.versionOsMap) - && Objects.equals(availablePath, other.availablePath); - } - - @Override - public int hashCode() - { - return Objects.hash(name, status, versionOsMap, isAvailable, availablePath); - } -} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonChangeListener.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonChangeListener.java new file mode 100644 index 000000000..3a8810fac --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonChangeListener.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.watcher; + +import java.nio.file.Path; + +/** + * Classes that want to handle the eim_idf.json Changes must implement this listener + * @author Ali Azam Rana + * + */ +public interface EimJsonChangeListener +{ + void onJsonFileChanged(Path file, boolean paused); +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java new file mode 100644 index 000000000..44232e9eb --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonStateChecker.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.watcher; + +import java.io.File; + +import org.eclipse.core.runtime.Platform; +import org.osgi.service.prefs.Preferences; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimConstants; + +/** + * Checks if eim_idf.json was changed while Eclipse was not running. Stores and compares last seen timestamp to file + * system's last modified. + * + * @author Ali Azam Rana + * + */ +public class EimJsonStateChecker +{ + private static final String LAST_MODIFIED_PREF_KEY = "lastEimJsonModified"; //$NON-NLS-1$ + + private final Preferences preferences; + + public EimJsonStateChecker(Preferences preferences) + { + this.preferences = preferences; + } + + public boolean wasModifiedSinceLastRun() + { + File jsonFile = new File(getEimJsonPath()); + if (!jsonFile.exists()) + { + return false; + } + + long lastModified = jsonFile.lastModified(); + long lastSeen = preferences.getLong(LAST_MODIFIED_PREF_KEY, 0L); + + if (lastSeen == 0L) + { + // First run ever, don't treat as changed + Logger.log("eim_idf.json detected, but no last seen timestamp — assuming first run."); //$NON-NLS-1$ + return false; + } + + return lastModified > lastSeen; + } + + public void updateLastSeenTimestamp() + { + File jsonFile = new File(getEimJsonPath()); + if (jsonFile.exists()) + { + preferences.putLong(LAST_MODIFIED_PREF_KEY, jsonFile.lastModified()); + } + } + + private String getEimJsonPath() + { + return Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH : EimConstants.EIM_POSIX_PATH; + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java new file mode 100644 index 000000000..8c417a230 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonWatchService.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.watcher; + +import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.eclipse.core.runtime.Platform; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimConstants; + +/** + * eim_idf.json watch service. The service will only watch for changes. Any handling must be done by the listeners to + * this service. + * + * @author Ali Azam Rana + */ +public class EimJsonWatchService extends Thread +{ + private final WatchService watchService; + private final Path watchDirectoryPath; + private final List eimJsonChangeListeners = new CopyOnWriteArrayList<>(); + private volatile boolean running = true; + private volatile boolean paused = false; + private volatile Instant lastModifiedTime; + + private EimJsonWatchService() throws IOException + { + String directoryPathString = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_DIR + : EimConstants.EIM_POSIX_DIR; + + watchDirectoryPath = Paths.get(directoryPathString); + if (!Files.exists(watchDirectoryPath)) + { + Files.createDirectories(watchDirectoryPath); + } + watchService = FileSystems.getDefault().newWatchService(); + watchDirectoryPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, + StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); + + Logger.log("Watcher added to the directory: " + directoryPathString); //$NON-NLS-1$ + setName("EimJsonWatchService"); //$NON-NLS-1$ + setDaemon(true); + start(); + } + + private static class Holder + { + private static EimJsonWatchService INSTANCE; + + static + { + try + { + INSTANCE = new EimJsonWatchService(); + } + catch (IOException e) + { + Logger.log("Failed to initialize EimJsonWatchService"); //$NON-NLS-1$ + Logger.log(e); + } + } + } + + public static EimJsonWatchService getInstance() + { + return Holder.INSTANCE; + } + + public void addEimJsonChangeListener(EimJsonChangeListener listener) + { + if (listener != null) + { + eimJsonChangeListeners.add(listener); + } + } + + public void removeAllListeners() + { + eimJsonChangeListeners.clear(); + } + + public static void withPausedListeners(Runnable task) + { + EimJsonWatchService watchService = getInstance(); + boolean wasPaused = watchService.paused; + watchService.pauseListeners(); + + try + { + task.run(); + } + catch (Exception e) + { + Logger.log(e); + } finally + { + if (!wasPaused) + watchService.unpauseListeners(); + } + } + + public void pauseListeners() + { + Logger.log("Listeners are paused"); //$NON-NLS-1$ + paused = true; + } + + public void unpauseListeners() + { + Logger.log("Listeners are resumed"); //$NON-NLS-1$ + paused = false; + } + + @Override + public void run() + { + while (running) + { + WatchKey key; + try + { + key = watchService.take(); + } + catch (InterruptedException e) + { + Logger.log("Watch Service Interrupted"); //$NON-NLS-1$ + Thread.currentThread().interrupt(); + break; + } + catch (ClosedWatchServiceException cwse) + { + break; + } + + for (WatchEvent event : key.pollEvents()) + { + if (event.kind() == StandardWatchEventKinds.OVERFLOW) + { + continue; + } + + Object context = event.context(); + if (context instanceof Path path && path.toString().equals(EimConstants.EIM_JSON)) + { + Path fullPath = watchDirectoryPath.resolve(path); + try + { + Instant currentModified = Files.getLastModifiedTime(fullPath).toInstant() + .truncatedTo(ChronoUnit.SECONDS); + + if (lastModifiedTime != null && currentModified.compareTo(lastModifiedTime) <= 0) + { + continue; // skip duplicate or same-second event + } + + lastModifiedTime = currentModified; + + for (EimJsonChangeListener listener : eimJsonChangeListeners) + { + listener.onJsonFileChanged(fullPath, paused); + } + } + catch (IOException e) + { + Logger.log(e); + } + } + } + + boolean valid = key.reset(); + if (!valid) + { + break; + } + } + + // clean up + try + { + watchService.close(); + Logger.log("File Watch Service close"); //$NON-NLS-1$ + } + catch (IOException e) + { + Logger.log("Failed to close WatchService"); //$NON-NLS-1$ + Logger.log(e); + } + } + + @Override + public void interrupt() + { + running = false; + super.interrupt(); + } + + public void shutdown() + { + running = false; + interrupt(); + } +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/DfuCommandsUtil.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/DfuCommandsUtil.java index 033c9234d..63c31b0d9 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/DfuCommandsUtil.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/DfuCommandsUtil.java @@ -139,7 +139,7 @@ public static void flashDfuBins(ILaunchConfiguration configuration, IProject pro idfEnvMap.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ // Update with the CDT build environment variables - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); environment.putAll(idfEnvMap); Logger.log(environment.toString()); diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java index 1de306634..f37405169 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java @@ -26,7 +26,7 @@ public Process chipInformation(String port) throws Exception { destroyAnyChipInfoProcess(); ProcessBuilder processBuilder = new ProcessBuilder(getChipInfoCommand(port)); - processBuilder.environment().putAll(IDFUtil.getSystemEnv()); + processBuilder.environment().putAll(System.getenv()); chipInfoProcess = processBuilder.start(); return chipInfoProcess; } @@ -35,7 +35,7 @@ public Process eraseFlash(String port) throws Exception { destroyAnyChipInfoProcess(); ProcessBuilder processBuilder = new ProcessBuilder(getFlashEraseCommand(port)); - processBuilder.environment().putAll(IDFUtil.getSystemEnv()); + processBuilder.environment().putAll(System.getenv()); flashEraseProcess = processBuilder.start(); return flashEraseProcess; } @@ -44,7 +44,7 @@ public Process writeFlash(String port, String path, String offset) throws IOExce { destroyAnyChipInfoProcess(); ProcessBuilder processBuilder = new ProcessBuilder(getWriteFlashCommand(port, path, offset)); - processBuilder.environment().putAll(IDFUtil.getSystemEnv()); + processBuilder.environment().putAll(System.getenv()); writeFlashProcess = processBuilder.start(); return writeFlashProcess; } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java index 5a011a394..1b1eb82b4 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java @@ -43,7 +43,6 @@ import com.espressif.idf.core.IDFConstants; import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFCorePreferenceConstants; import com.espressif.idf.core.IDFEnvironmentVariables; import com.espressif.idf.core.LaunchBarTargetConstants; import com.espressif.idf.core.ProcessBuilderFactory; @@ -212,6 +211,30 @@ public static String getIDFPythonEnvPath() return findCommandFromBuildEnvPath(IDFConstants.PYTHON_CMD); } + + public static String getIDFPythonEnvPath(String idfPyEnvPath) + { + idfPyEnvPath = idfPyEnvPath.strip(); + if (!StringUtil.isEmpty(idfPyEnvPath)) + { + + if (Platform.getOS().equals(Platform.OS_WIN32)) + { + idfPyEnvPath = idfPyEnvPath + "/" + "Scripts"; //$NON-NLS-1$ //$NON-NLS-2$ + } + else + { + idfPyEnvPath = idfPyEnvPath + "/" + "bin"; //$NON-NLS-1$ //$NON-NLS-2$ + } + java.nio.file.Path commandPath = findCommand(IDFConstants.PYTHON_CMD, idfPyEnvPath); + if (commandPath != null) + { + return commandPath.toFile().getAbsolutePath(); + } + } + return findCommandFromBuildEnvPath(IDFConstants.PYTHON_CMD); + + } public static boolean checkIfIdfSupportsSpaces() { @@ -229,17 +252,8 @@ public static boolean checkIfIdfSupportsSpaces() public static String getPythonExecutable() { - IPath pythonPath = new SystemExecutableFinder().find(IDFConstants.PYTHON3_CMD); // look for python3 - if (pythonPath == null) - { - pythonPath = new SystemExecutableFinder().find(IDFConstants.PYTHON_CMD); // look for python - } - if (pythonPath != null) - { - return pythonPath.toOSString(); - } - - return IDFConstants.PYTHON_CMD; + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + return idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PYTHON_EXE_PATH); } /** @@ -822,7 +836,7 @@ public static String getGitExecutablePathFromSystem() arguments.add("whereis"); //$NON-NLS-1$ arguments.add("git"); //$NON-NLS-1$ - Map environment = new HashMap<>(getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); IStatus status = processRunner.runInBackground(arguments, org.eclipse.core.runtime.Path.ROOT, environment); @@ -895,10 +909,6 @@ public static Map getSystemEnv() { Map env = new HashMap<>(System.getenv()); - String idfToolsPath = Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.IDF_TOOLS_PATH, IDFCorePreferenceConstants.IDF_TOOLS_PATH_DEFAULT, null); - env.put(IDFCorePreferenceConstants.IDF_TOOLS_PATH, idfToolsPath); - // Merge Homebrew bin paths into PATH // Windows may use "Path" while Unix uses "PATH" String keyPath = env.containsKey("PATH") ? "PATH" : "Path"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -921,14 +931,7 @@ public static Map getSystemEnv() return env; } - - public static String getIDFToolsPathFromPreferences() - { - String idfToolsPath = Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.IDF_TOOLS_PATH, IDFCorePreferenceConstants.IDF_TOOLS_PATH_DEFAULT, null); - return idfToolsPath; - } - + public static void closeWelcomePage(IWorkbenchWindow activeww) { Display.getDefault().syncExec(() -> { diff --git a/bundles/com.espressif.idf.sdk.config.core/src/com/espressif/idf/sdk/config/core/server/JsonConfigServer.java b/bundles/com.espressif.idf.sdk.config.core/src/com/espressif/idf/sdk/config/core/server/JsonConfigServer.java index 4033fa16e..fa7f20468 100644 --- a/bundles/com.espressif.idf.sdk.config.core/src/com/espressif/idf/sdk/config/core/server/JsonConfigServer.java +++ b/bundles/com.espressif.idf.sdk.config.core/src/com/espressif/idf/sdk/config/core/server/JsonConfigServer.java @@ -10,10 +10,10 @@ import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -24,6 +24,7 @@ import com.espressif.idf.core.IDFConstants; import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.ProcessBuilderFactory; import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.StringUtil; @@ -92,69 +93,81 @@ public void removeListener(IMessageHandlerListener listener) public void start() throws IOException { IPath workingDir = project.getLocation(); - Map idfEnvMap = new IDFEnvironmentVariables().getSystemEnvMap(); - - // Disable buffering of output - idfEnvMap.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - + Map env = new HashMap(System.getenv()); + + prepEnvMap(env); + List arguments = new ArrayList<>(); File idfPythonScriptFile = IDFUtil.getIDFPythonScriptFile(); if (!idfPythonScriptFile.exists()) { throw new FileNotFoundException("File Not found:" + idfPythonScriptFile); //$NON-NLS-1$ } - String pythonPath = IDFUtil.getIDFPythonEnvPath(); - - List arguments = Collections.emptyList(); try { - arguments = new ArrayList(Arrays.asList(pythonPath, idfPythonScriptFile.getAbsolutePath(), "-B", //$NON-NLS-1$ - IDFUtil.getBuildDir(project), "-DSDKCONFIG=".concat(file.getName()), IDFConstants.CONF_SERVER_CMD)); //$NON-NLS-1$ + String pythonPath = IDFUtil.getIDFPythonEnvPath(); + arguments.add(pythonPath); + arguments.add(idfPythonScriptFile.getAbsolutePath()); + arguments.add("-B"); //$NON-NLS-1$ + arguments.add(IDFUtil.getBuildDir(project)); + arguments.add("-DSDKCONFIG=".concat(file.getName())); //$NON-NLS-1$ + arguments.add(IDFConstants.CONF_SERVER_CMD); + Logger.log(arguments.toString()); + + ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); + + String oldSdkconfigValue = StringUtil.EMPTY; + oldSdkconfigValue = getCmakeCacheSdkconfigValue(); + + + process = processRunner.run(arguments, workingDir, env); + runnable = new JsonConfigServerRunnable(process, this, project, oldSdkconfigValue); + Thread t = new Thread(runnable); + t.start(); } - catch (CoreException e) + catch (Exception e) { Logger.log(e); } - Logger.log(arguments.toString()); - - ProcessBuilder processBuilder = new ProcessBuilder(arguments); - if (workingDir != null) - { - processBuilder.directory(workingDir.toFile()); - } - Map environment = processBuilder.environment(); - environment.putAll(idfEnvMap); - environment.put("IDF_CCACHE_ENABLE", "false"); - - Logger.log(environment.toString()); + } - String idfPath = environment.get("PATH"); //$NON-NLS-1$ - String processPath = environment.get("Path"); //$NON-NLS-1$ - if (!StringUtil.isEmpty(idfPath) && !StringUtil.isEmpty(processPath)) // if both exist! + private void prepEnvMap(Map env) + { + env.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ + env.put("IDF_CCACHE_ENABLE", "false"); //$NON-NLS-1$ //$NON-NLS-2$ + loadIdfPathWithSystemPath(env); + } + + private void loadIdfPathWithSystemPath(Map systemEnv) + { + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + String idfExportPath = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH); + String pathVar = "PATH"; // for Windows //$NON-NLS-1$ + String pathEntry = systemEnv.get(pathVar); // $NON-NLS-1$ + if (pathEntry == null) { - idfPath = idfPath.concat(";").concat(processPath); //$NON-NLS-1$ - environment.put("PATH", idfPath); //$NON-NLS-1$ - environment.remove("Path");//$NON-NLS-1$ + pathVar = "Path"; //$NON-NLS-1$ + pathEntry = systemEnv.get(pathVar); + if (pathEntry == null) // no idea + { + Logger.log(new Exception("No PATH found in the system environment variables")); //$NON-NLS-1$ + } } - Logger.log(environment.toString()); - - // redirect error stream to input stream - processBuilder.redirectErrorStream(true); - String oldSdkconfigValue = StringUtil.EMPTY; - try + if (!StringUtil.isEmpty(pathEntry)) { - oldSdkconfigValue = getCmakeCacheSdkconfigValue(); + idfExportPath = idfExportPath.replace("$PATH", pathEntry); // macOS //$NON-NLS-1$ + idfExportPath = idfExportPath.replace("%PATH%", pathEntry); // Windows //$NON-NLS-1$ } - catch (CoreException e) + + systemEnv.put(pathVar, idfExportPath); + for (Entry entry : idfEnvironmentVariables.getEnvMap().entrySet()) { - Logger.log(e); - } - process = processBuilder.start(); - runnable = new JsonConfigServerRunnable(process, this, project, oldSdkconfigValue); - Thread t = new Thread(runnable); - t.start(); + if (entry.getKey().equals(IDFEnvironmentVariables.PATH)) + continue; + systemEnv.put(entry.getKey(), entry.getValue()); + } } private String getCmakeCacheSdkconfigValue() throws CoreException diff --git a/bundles/com.espressif.idf.serial.monitor/src/com/espressif/idf/serial/monitor/core/IDFMonitor.java b/bundles/com.espressif.idf.serial.monitor/src/com/espressif/idf/serial/monitor/core/IDFMonitor.java index 0e0c31c5b..6c63fd3b6 100644 --- a/bundles/com.espressif.idf.serial.monitor/src/com/espressif/idf/serial/monitor/core/IDFMonitor.java +++ b/bundles/com.espressif.idf.serial.monitor/src/com/espressif/idf/serial/monitor/core/IDFMonitor.java @@ -12,7 +12,6 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; @@ -20,14 +19,12 @@ import org.eclipse.embedcdt.debug.gdbjtag.core.DebugUtils; import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; import com.espressif.idf.core.IDFEnvironmentVariables; import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.util.GenericJsonReader; import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.SDKConfigJsonReader; import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.update.InstallToolsHandler; /** * @author Kondal Kolipaka @@ -153,10 +150,6 @@ private String getMonitorBaudRate() public Process start() throws Exception { - if (!dependenciesAreInstalled()) - { - throw new Exception("The WebSocket dependency is missing and cannot be installed automatically"); //$NON-NLS-1$ - } List arguments = commandArgsWithSocketServer(); // command to execute @@ -169,7 +162,7 @@ public Process start() throws Exception idfEnvMap.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ // Update with the CDT build environment variables - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); environment.putAll(idfEnvMap); Logger.log(environment.toString()); @@ -196,18 +189,4 @@ public Process start() throws Exception LocalTerminal localTerminal = new LocalTerminal(arguments, workingDir.toFile(), environment); return localTerminal.connect(); } - - public boolean dependenciesAreInstalled() - { - InstallToolsHandler installToolsHandler = new InstallToolsHandler(); - IStatus status = installToolsHandler.handleWebSocketClientInstall(); - if (status == null || status.getSeverity() == IStatus.ERROR) - { - Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - return false; - } - - Logger.log(status.getMessage()); - return true; - } } diff --git a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/IDFConsoleWizardConfigurationPanel.java b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/IDFConsoleWizardConfigurationPanel.java index 51615cef2..7dc28995c 100644 --- a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/IDFConsoleWizardConfigurationPanel.java +++ b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/IDFConsoleWizardConfigurationPanel.java @@ -13,32 +13,34 @@ package com.espressif.idf.terminal.connector.controls; import java.util.Map; +import java.util.Optional; -import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.IDialogSettings; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; -import org.eclipse.ui.ISelectionService; -import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchEncoding; -import org.osgi.framework.Bundle; + +import com.espressif.idf.core.IDFProjectNature; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.ui.EclipseUtil; /** * IDF console wizard configuration panel implementation. */ public class IDFConsoleWizardConfigurationPanel extends AbstractExtendedConfigurationPanel { - private Object resource; + private Combo projectCombo; /** * Constructor. @@ -55,6 +57,7 @@ public void setupPanel(Composite parent) { panel.setLayout(new GridLayout()); panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + createProjectCombo(panel); // Create the encoding selection combo createEncodingUI(panel, false); @@ -76,12 +79,40 @@ public void setupPanel(Composite parent) { layoutData.heightHint = 80; label.setLayoutData(layoutData); - Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { - resource = getSelectionResource(); + setControl(panel); + } + + private void createProjectCombo(Composite parent) { + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + Label projectLabel = new Label(panel, SWT.NONE); + projectLabel + .setText(Messages.IDFConsoleWizardConfigurationPanel_IDFConsoleWizardConfigurationPanel_ProjectLabel); + + projectCombo = new Combo(panel, SWT.READ_ONLY); + projectCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { + try { + if (project.hasNature(IDFProjectNature.ID)) { + projectCombo.add(project.getName()); + } + } catch (CoreException e) { + Logger.log(e); + } } - setControl(panel); + Optional optProject = Optional.ofNullable(EclipseUtil.getSelectedIDFProjectInExplorer()); + optProject.ifPresentOrElse(project -> projectCombo.setText(project.getName()), () -> { + if (projectCombo.getItemCount() > 0) + projectCombo.select(0); + }); } @Override @@ -96,19 +127,17 @@ public void setupData(Map data) { @Override public void extractData(Map data) { - // set the terminal connector id for local terminal + data.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, "com.espressif.idf.terminal.connector.espidfConnector"); //$NON-NLS-1$ - // Store the encoding data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); - Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { - // if we have a IResource selection use the location for working directory - if (resource instanceof org.eclipse.core.resources.IResource) { - String dir = ((org.eclipse.core.resources.IResource) resource).getProject().getLocation().toString(); - data.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, dir); + if (projectCombo != null && !projectCombo.isDisposed() && !projectCombo.getText().isEmpty()) { + IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(projectCombo.getText()); + if (p != null && p.exists() && p.getLocation() != null) { + data.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, p.getLocation().toOSString()); + data.put(ITerminalsConnectorConstants.PROP_TITLE, p.getName()); } } } @@ -147,25 +176,4 @@ protected String getHostFromSettings() { public boolean isWithHostList() { return false; } - - /** - * Returns the IResource from the current selection - * - * @return the IResource, or null. - */ - private org.eclipse.core.resources.IResource getSelectionResource() { - ISelectionService selectionService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); - ISelection selection = selectionService != null ? selectionService.getSelection() : StructuredSelection.EMPTY; - - if (selection instanceof IStructuredSelection && !selection.isEmpty()) { - Object element = ((IStructuredSelection) selection).getFirstElement(); - if (element instanceof org.eclipse.core.resources.IResource) { - return ((org.eclipse.core.resources.IResource) element); - } - if (element instanceof IAdaptable) { - return ((IAdaptable) element).getAdapter(org.eclipse.core.resources.IResource.class); - } - } - return null; - } } diff --git a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/Messages.java b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/Messages.java new file mode 100644 index 000000000..dacf27f4e --- /dev/null +++ b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/Messages.java @@ -0,0 +1,17 @@ +package com.espressif.idf.terminal.connector.controls; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = Messages.class.getPackageName() + ".messages"; //$NON-NLS-1$ + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + + public static String IDFConsoleWizardConfigurationPanel_MissingProjectErrorMsg; + public static String IDFConsoleWizardConfigurationPanel_IDFConsoleWizardConfigurationPanel_ProjectLabel; +} diff --git a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/messages.properties b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/messages.properties new file mode 100644 index 000000000..c8317b89b --- /dev/null +++ b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/controls/messages.properties @@ -0,0 +1,2 @@ +IDFConsoleWizardConfigurationPanel_MissingProjectErrorMsg=Please create and select an ESP-IDF Project first. +IDFConsoleWizardConfigurationPanel_IDFConsoleWizardConfigurationPanel_ProjectLabel=Project name: \ No newline at end of file diff --git a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFConsoleLauncherDelegate.java b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFConsoleLauncherDelegate.java index feff19293..73c65ca0f 100644 --- a/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFConsoleLauncherDelegate.java +++ b/bundles/com.espressif.idf.terminal.connector/src/com/espressif/idf/terminal/connector/launcher/IDFConsoleLauncherDelegate.java @@ -18,24 +18,19 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.cdt.utils.pty.PTY; -import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.URIUtil; import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.VariablesPlugin; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; @@ -51,8 +46,6 @@ import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; -import org.eclipse.ui.ISelectionService; -import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchEncoding; import org.osgi.framework.Bundle; @@ -61,7 +54,6 @@ import com.espressif.idf.core.util.StringUtil; import com.espressif.idf.terminal.connector.activator.UIPlugin; import com.espressif.idf.terminal.connector.controls.IDFConsoleWizardConfigurationPanel; -import com.espressif.idf.ui.EclipseUtil; /** * Serial launcher delegate implementation. @@ -87,16 +79,14 @@ public void execute(Map properties, ITerminalService.Done done) Assert.isNotNull(properties); // Set the terminal tab title - String terminalTitle = getTerminalTitle(); - if (terminalTitle != null) { - properties.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); - } + setTerminalTitle(properties); // If not configured, set the default encodings for the local terminal if (!properties.containsKey(ITerminalsConnectorConstants.PROP_ENCODING)) { String encoding = null; // Set the default encoding: - // Default UTF-8 on Mac or Windows for Local, Preferences:Platform encoding otherwise + // Default UTF-8 on Mac or Windows for Local, Preferences:Platform encoding + // otherwise if (Platform.OS_MACOSX.equals(Platform.getOS()) || Platform.OS_WIN32.equals(Platform.getOS())) { encoding = "UTF-8"; //$NON-NLS-1$ } else { @@ -112,112 +102,55 @@ public void execute(Map properties, ITerminalService.Done done) properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); } - // Initialize the local terminal working directory. + // Initialize the local terminal working directory if not already set by the panel. // By default, start the local terminal in the users home directory - String initialCwd = org.eclipse.tm.terminal.view.ui.activator.UIPlugin.getScopedPreferences() - .getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD); - String cwd = null; - if (initialCwd == null || IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME.equals(initialCwd) - || "".equals(initialCwd.trim())) { //$NON-NLS-1$ - cwd = System.getProperty("user.home"); //$NON-NLS-1$ - } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME.equals(initialCwd)) { - String eclipseHomeLocation = System.getProperty("eclipse.home.location"); //$NON-NLS-1$ - if (eclipseHomeLocation != null) { - try { - URI uri = URIUtil.fromString(eclipseHomeLocation); - File f = URIUtil.toFile(uri); - cwd = f.getAbsolutePath(); - } catch (URISyntaxException ex) { - /* ignored on purpose */ } - } - } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS.equals(initialCwd)) { - Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { - if (org.eclipse.core.resources.ResourcesPlugin.getWorkspace() != null - && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() != null - && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() != null) { - cwd = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() - .toOSString(); - } - } - } else { - try { - // Resolve possible dynamic variables - IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); - String resolved = vm.performStringSubstitution(initialCwd); - - IPath p = new Path(resolved); - if (p.toFile().canRead() && p.toFile().isDirectory()) { - cwd = p.toOSString(); + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR)) { + String initialCwd = org.eclipse.tm.terminal.view.ui.activator.UIPlugin.getScopedPreferences() + .getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD); + String cwd = null; + if (initialCwd == null || IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME.equals(initialCwd) + || "".equals(initialCwd.trim())) { //$NON-NLS-1$ + cwd = System.getProperty("user.home"); //$NON-NLS-1$ + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME.equals(initialCwd)) { + String eclipseHomeLocation = System.getProperty("eclipse.home.location"); //$NON-NLS-1$ + if (eclipseHomeLocation != null) { + try { + URI uri = URIUtil.fromString(eclipseHomeLocation); + File f = URIUtil.toFile(uri); + cwd = f.getAbsolutePath(); + } catch (URISyntaxException ex) { + /* ignored on purpose */ } } - } catch (CoreException ex) { - if (Platform.inDebugMode()) { - UIPlugin.getDefault().getLog().log(ex.getStatus()); + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS.equals(initialCwd)) { + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + if (org.eclipse.core.resources.ResourcesPlugin.getWorkspace() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() + .getLocation() != null) { + cwd = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() + .toOSString(); + } } - } - } - - if (cwd != null && !"".equals(cwd)) { //$NON-NLS-1$ - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, cwd); - } + } else { + try { + // Resolve possible dynamic variables + IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); + String resolved = vm.performStringSubstitution(initialCwd); - // If the current selection resolved to an folder, default the working directory - // to that folder and update the terminal title - ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); - if ((service != null && service.getSelection() != null) - || properties.containsKey(ITerminalsConnectorConstants.PROP_SELECTION)) { - ISelection selection = (ISelection) properties.get(ITerminalsConnectorConstants.PROP_SELECTION); - if (selection == null) - selection = service.getSelection(); - if (selection instanceof IStructuredSelection && !selection.isEmpty()) { - String dir = null; - Iterator iter = ((IStructuredSelection) selection).iterator(); - while (iter.hasNext()) { - Object element = iter.next(); - - Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED - && bundle.getState() != Bundle.STOPPING) { - // If the element is not an IResource, try to adapt to IResource - if (!(element instanceof org.eclipse.core.resources.IResource)) { - Object adapted = element instanceof IAdaptable - ? ((IAdaptable) element).getAdapter(org.eclipse.core.resources.IResource.class) - : null; - if (adapted == null) - adapted = Platform.getAdapterManager().getAdapter(element, - org.eclipse.core.resources.IResource.class); - if (adapted != null) - element = adapted; - } - - if (element instanceof org.eclipse.core.resources.IResource - && ((org.eclipse.core.resources.IResource) element).exists()) { - IPath location = ((org.eclipse.core.resources.IResource) element).getLocation(); - if (location == null) - continue; - if (location.toFile().isFile()) - location = location.removeLastSegments(1); - if (location.toFile().isDirectory() && location.toFile().canRead()) { - dir = location.toFile().getAbsolutePath(); - break; - } - } - - if (element instanceof IPath || element instanceof File) { - File f = element instanceof IPath ? ((IPath) element).toFile() : (File) element; - if (f.isDirectory() && f.canRead()) { - dir = f.getAbsolutePath(); - break; - } - } + IPath p = new Path(resolved); + if (p.toFile().canRead() && p.toFile().isDirectory()) { + cwd = p.toOSString(); + } + } catch (CoreException ex) { + if (Platform.inDebugMode()) { + UIPlugin.getDefault().getLog().log(ex.getStatus()); } } - if (dir != null) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, dir); + } - String basename = new Path(dir).lastSegment(); - properties.put(ITerminalsConnectorConstants.PROP_TITLE, basename + " (" + terminalTitle + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } + if (cwd != null && !"".equals(cwd)) { //$NON-NLS-1$ + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, cwd); } } @@ -230,13 +163,20 @@ public void execute(Map properties, ITerminalService.Done done) } /** - * Returns the terminal title string. + * Setting the terminal title. *

+ * @param properties * - * @return The terminal title string + * @return void */ - private String getTerminalTitle() { - return Messages.IDFConsoleLauncherDelegate_ESPIDFTerminal; + private void setTerminalTitle(Map properties) { + if (properties.containsKey(ITerminalsConnectorConstants.PROP_TITLE)) { + var projectName = properties.get(ITerminalsConnectorConstants.PROP_TITLE); + properties.put(ITerminalsConnectorConstants.PROP_TITLE, + String.format("%s (%s)", projectName, Messages.IDFConsoleLauncherDelegate_ESPIDFTerminal)); //$NON-NLS-1$ + } else { + properties.put(ITerminalsConnectorConstants.PROP_TITLE, Messages.IDFConsoleLauncherDelegate_ESPIDFTerminal); + } } @Override @@ -310,6 +250,13 @@ public ITerminalConnector createTerminalConnector(Map properties arguments = "--no-rcs --no-globalrcs"; //$NON-NLS-1$ } else if (image.contains("powershell")) { //$NON-NLS-1$ arguments = "-NoProfile"; //$NON-NLS-1$ + } else if (Platform.OS_WIN32.equals(Platform.getOS()) && image.contains("cmd.exe")) { //$NON-NLS-1$ + // This is the new part that rewrites the arguments for cmd.exe + String title = (String) properties.get(ITerminalsConnectorConstants.PROP_TITLE); + if (title != null && !title.isEmpty()) { + String safeTitle = title.replaceAll("[\\r\\n\"&|<>^]", " ").trim(); //$NON-NLS-1$ //$NON-NLS-2$ + arguments = "/c \"title " + safeTitle + " && cmd.exe\""; //$NON-NLS-1$ //$NON-NLS-2$ + } } // Determine if a PTY will be used @@ -408,11 +355,6 @@ public ITerminalConnector createTerminalConnector(Map properties Assert.isTrue(image != null || process != null); - String terminalWrkDir = getWorkingDir(); - if (StringUtil.isEmpty(terminalWrkDir)) { - terminalWrkDir = workingDir; - } - // Construct the terminal settings store ISettingsStore store = new SettingsStore(); @@ -426,7 +368,7 @@ public ITerminalConnector createTerminalConnector(Map properties processSettings.setLineSeparator(lineSeparator); processSettings.setStdOutListeners(stdoutListeners); processSettings.setStdErrListeners(stderrListeners); - processSettings.setWorkingDir(terminalWrkDir); + processSettings.setWorkingDir(workingDir); processSettings.setEnvironment(envp); if (properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT)) { @@ -449,17 +391,4 @@ public ITerminalConnector createTerminalConnector(Map properties return connector; } - protected String getWorkingDir() { - Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { - // if we have a IResource selection use the location for working directory - IResource resource = EclipseUtil.getSelectionResource(); - if (resource instanceof IResource) { - String dir = ((IResource) resource).getProject().getLocation().toString(); - return dir; - } - } - return IDFUtil.getIDFPath(); - } - } diff --git a/bundles/com.espressif.idf.ui/OSGI-INF/l10n/bundle.properties b/bundles/com.espressif.idf.ui/OSGI-INF/l10n/bundle.properties index 7be5c883b..00178f0e3 100644 --- a/bundles/com.espressif.idf.ui/OSGI-INF/l10n/bundle.properties +++ b/bundles/com.espressif.idf.ui/OSGI-INF/l10n/bundle.properties @@ -62,7 +62,6 @@ command.name.delete = Delete command.name.13 = DFU command.label.11 = DFU command.tooltip.2 = DFU -command.name.updateEspIdfMaster = Update ESP-IDF master command.name.15 = Tools Installation Wizard (Preview) command.label.PartitionTableEditor = Partition Table Editor diff --git a/bundles/com.espressif.idf.ui/icons/tools/delete.png b/bundles/com.espressif.idf.ui/icons/tools/delete.png deleted file mode 100644 index 14de8ec9e..000000000 Binary files a/bundles/com.espressif.idf.ui/icons/tools/delete.png and /dev/null differ diff --git a/bundles/com.espressif.idf.ui/plugin.xml b/bundles/com.espressif.idf.ui/plugin.xml index 2efd03d66..35b31e556 100644 --- a/bundles/com.espressif.idf.ui/plugin.xml +++ b/bundles/com.espressif.idf.ui/plugin.xml @@ -37,17 +37,6 @@ id="espidftoolsInstall" style="push"> - - - - - - @@ -423,11 +412,6 @@ id="com.espressif.idf.ui.command.eclipeguide" name="%command.name.9"> - - - - - + class="com.espressif.idf.ui.EspressifGeneralStartup"/> + + id="com.espressif.idf.ui.nvs.nvsEditor" + name="%command.name.nvsTableEditor"> diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/EspressifGeneralStartup.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/EspressifGeneralStartup.java new file mode 100644 index 000000000..82eaa6407 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/EspressifGeneralStartup.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui; + +import java.beans.PropertyChangeEvent; +import java.text.MessageFormat; +import java.util.List; + +import org.eclipse.cdt.cmake.core.internal.Activator; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.launchbar.core.ILaunchBarManager; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IStartup; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import com.espressif.idf.core.build.Messages; +import com.espressif.idf.core.build.ReHintPair; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.resources.OpenDialogListenerSupport; +import com.espressif.idf.core.resources.PopupDialog; +import com.espressif.idf.core.resources.ResourceChangeListener; +import com.espressif.idf.ui.dialogs.BuildView; +import com.espressif.idf.ui.dialogs.MessageLinkDialog; + +/** + * General Startup class for handling + * ui elements and registering any listeners + * @author Ali Azam Rana + * + */ +@SuppressWarnings("restriction") +public class EspressifGeneralStartup implements IStartup +{ + private static final String BUILDHINTS_ID = "com.espressif.idf.ui.views.buildhints"; + + private LaunchBarListener launchBarListener; + + @Override + public void earlyStartup() + { + hookDialogListeners(); + hookLaunchBarListeners(); + } + + private void hookDialogListeners() + { + OpenDialogListenerSupport.getSupport().addPropertyChangeListener(evt -> { + PopupDialog popupDialog = PopupDialog.valueOf(evt.getPropertyName()); + switch (popupDialog) + { + case LOW_PARTITION_SIZE: + openLowPartitionSizeDialog(evt); + break; + case AVAILABLE_HINTS: + openAvailableHintsDialog(evt); + break; + case DISABLE_LAUNCHABAR_EVENTS: + disableLaunchBarEvents(); + break; + case ENABLE_LAUNCHBAR_EVENTS: + enableLaunchBarEvents(); + break; + default: + break; + } + }); + } + + private void hookLaunchBarListeners() + { + launchBarListener = new LaunchBarListener(); + ResourcesPlugin.getWorkspace().addResourceChangeListener(new ResourceChangeListener(launchBarListener)); + + ILaunchBarManager launchBarManager = Activator.getService(ILaunchBarManager.class); + launchBarManager.addListener(launchBarListener); + } + + @SuppressWarnings("static-access") + private void disableLaunchBarEvents() + { + launchBarListener.setIgnoreTargetChange(true); + } + + @SuppressWarnings("static-access") + private void enableLaunchBarEvents() + { + launchBarListener.setIgnoreTargetChange(false); + } + + @SuppressWarnings("unchecked") + private void openAvailableHintsDialog(PropertyChangeEvent evt) + { + Display.getDefault().asyncExec(() -> { + List errorHintPairs = (List) evt.getNewValue(); + + if (errorHintPairs.isEmpty()) + { + updateBuildView(errorHintPairs); + return; + } + + try + { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(BUILDHINTS_ID); + } + catch (PartInitException e) + { + Logger.log(e); + } + + updateBuildView(errorHintPairs); + }); + } + + private void updateBuildView(List errorHintPairs) + { + BuildView view = (BuildView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() + .findView(BUILDHINTS_ID); + if (view != null) + { + view.updateReHintsPairs(errorHintPairs); + } + } + + private void openLowPartitionSizeDialog(PropertyChangeEvent evt) + { + Display.getDefault().asyncExec(() -> { + Shell shell = Display.getDefault().getActiveShell(); + MessageLinkDialog.openWarning(shell, + Messages.IncreasePartitionSizeTitle, + MessageFormat.format(Messages.IncreasePartitionSizeMessage, + evt.getNewValue(), + evt.getOldValue(), + "https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html?highlight=partitions%20csv#creating-custom-tables")); + }); + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/GlobalModalLock.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/GlobalModalLock.java new file mode 100644 index 000000000..b8eefd500 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/GlobalModalLock.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui; + +import java.util.concurrent.Semaphore; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.eclipse.swt.widgets.Display; + +public class GlobalModalLock +{ + private static final Semaphore lock = new Semaphore(1); + + private GlobalModalLock() + { + } + + public static void showModal(Supplier dialogSupplier, Consumer callback) + { + new Thread(() -> { + try + { + lock.acquire(); + Display.getDefault().syncExec(() -> { + try + { + T result = dialogSupplier.get(); + callback.accept(result); + } finally + { + lock.release(); + } + }); + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + } + }, "GlobalModalLock-DialogThread").start(); //$NON-NLS-1$ + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/InitializeToolsStartup.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/InitializeToolsStartup.java deleted file mode 100644 index a95f4793b..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/InitializeToolsStartup.java +++ /dev/null @@ -1,358 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui; - -import java.beans.PropertyChangeEvent; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.net.URL; -import java.text.MessageFormat; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.cmake.core.internal.Activator; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.launchbar.core.ILaunchBarManager; -import org.eclipse.osgi.service.datalocation.Location; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.MessageBox; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IStartup; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; - -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFCorePreferenceConstants; -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.build.Messages; -import com.espressif.idf.core.build.ReHintPair; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.resources.OpenDialogListenerSupport; -import com.espressif.idf.core.resources.PopupDialog; -import com.espressif.idf.core.resources.ResourceChangeListener; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.ui.dialogs.BuildView; -import com.espressif.idf.ui.dialogs.MessageLinkDialog; -import com.espressif.idf.ui.tools.ToolsActivationJob; -import com.espressif.idf.ui.tools.ToolsActivationJobListener; -import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; - -@SuppressWarnings("restriction") -public class InitializeToolsStartup implements IStartup -{ - - private static final String BUILDHINTS_ID = "com.espressif.idf.ui.views.buildhints"; //$NON-NLS-1$ - - /** - * esp-idf.json is file created by the installer - */ - public static final String ESP_IDF_JSON_FILE = "esp_idf.json"; //$NON-NLS-1$ - - // Variables defined in the esp-idf.json file - private static final String GIT_PATH = "gitPath"; //$NON-NLS-1$ - private static final String IDF_TOOLS_PATH_KEY = "idfToolsPath"; //$NON-NLS-1$ - private static final String IDF_VERSIONS_ID = "idfSelectedId"; //$NON-NLS-1$ - private static final String IDF_INSTALLED_LIST_KEY = "idfInstalled"; //$NON-NLS-1$ - private static final String PYTHON_PATH = "python"; //$NON-NLS-1$ - private static final String IDF_PATH = "path"; //$NON-NLS-1$ - private static final String IS_INSTALLER_CONFIG_SET = "isInstallerConfigSet"; //$NON-NLS-1$ - private static final String DOC_URL = "\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html?highlight=partitions%20csv#creating-custom-tables\""; //$NON-NLS-1$ - - private String newIdfPath; - private LaunchBarListener launchBarListener; - @Override - public void earlyStartup() - { - OpenDialogListenerSupport.getSupport().addPropertyChangeListener(evt -> { - PopupDialog popupDialog = PopupDialog.valueOf(evt.getPropertyName()); - switch (popupDialog) - { - case LOW_PARTITION_SIZE: - openLowPartitionSizeDialog(evt); - break; - case AVAILABLE_HINTS: - openAvailableHintsDialog(evt); - break; - case DISABLE_LAUNCHABAR_EVENTS: - disableLaunchBarEvents(evt); - break; - case ENABLE_LAUNCHBAR_EVENTS: - enableLaunchBarEvents(evt); - break; - default: - break; - } - }); - launchBarListener = new LaunchBarListener(); - ResourcesPlugin.getWorkspace().addResourceChangeListener(new ResourceChangeListener(launchBarListener)); - ILaunchBarManager launchBarManager = Activator.getService(ILaunchBarManager.class); - launchBarManager.addListener(launchBarListener); - - // Get the location of the eclipse root directory - Location installLocation = Platform.getInstallLocation(); - URL url = installLocation.getURL(); - Logger.log("Eclipse Install location::" + url); - File idf_json_file = new File(url.getPath() + File.separator + ESP_IDF_JSON_FILE); - if (!idf_json_file.exists()) - { - Logger.log(MessageFormat.format("esp-idf.json file doesn't exist at this location: '{0}'", url.getPath())); - return; - } - else if (isInstallerConfigSet()) - { - checkForUpdatedVersion(idf_json_file); - if (isInstallerConfigSet()) - { - Logger.log("Ignoring esp_idf.json settings as it was configured earilier and idf_path is similar."); - return; - } - - IDFEnvironmentVariables idfEnvMgr = new IDFEnvironmentVariables(); - Display.getDefault().syncExec(() -> { - Shell shell = new Shell(Display.getDefault()); - MessageBox messageBox = new MessageBox(shell, SWT.ICON_WARNING | SWT.YES | SWT.NO); - messageBox.setButtonLabels(Map.of(SWT.YES, Messages.ToolsInitializationDifferentPathMessageBoxOptionYes, - SWT.NO, Messages.ToolsInitializationDifferentPathMessageBoxOptionNo)); - messageBox.setText(Messages.ToolsInitializationDifferentPathMessageBoxTitle); - messageBox.setMessage(MessageFormat.format(Messages.ToolsInitializationDifferentPathMessageBoxMessage, - newIdfPath, idfEnvMgr.getEnvValue(IDFEnvironmentVariables.IDF_PATH))); - int response = messageBox.open(); - if (response == SWT.NO) - { - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - updateEspIdfJsonFile(idf_json_file, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.IDF_PATH)); - Preferences prefs = getPreferences(); - prefs.putBoolean(IS_INSTALLER_CONFIG_SET, true); - try - { - prefs.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - - return; - } - }); - } - - // read esp-idf.json file - JSONParser parser = new JSONParser(); - try - { - JSONObject jsonObj = (JSONObject) parser.parse(new FileReader(idf_json_file)); - String gitExecutablePath = (String) jsonObj.get(GIT_PATH); - String idfToolsPath = (String) jsonObj.get(IDF_TOOLS_PATH_KEY); - String idfVersionId = (String) jsonObj.get(IDF_VERSIONS_ID); - JSONObject list = (JSONObject) jsonObj.get(IDF_INSTALLED_LIST_KEY); - if (list != null) - { - // selected esp-idf version information - JSONObject selectedIDFInfo = (JSONObject) list.get(idfVersionId); - String idfPath = (String) selectedIDFInfo.get(IDF_PATH); - String pythonExecutablePath = (String) selectedIDFInfo.get(PYTHON_PATH); - IDFToolSet newToolSet = new IDFToolSet(); - newToolSet.setIdfLocation(idfPath); - newToolSet.setSystemGitExecutablePath(gitExecutablePath); - newToolSet.setSystemPythonExecutablePath(pythonExecutablePath); - newToolSet.setActive(true); - Preferences prefs = InstanceScope.INSTANCE.getNode(IDFCorePlugin.PLUGIN_ID); - prefs.put(IDFCorePreferenceConstants.IDF_TOOLS_PATH, idfToolsPath); - try - { - prefs.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - ToolsActivationJob toolsActivationJob = new ToolsActivationJob(newToolSet, pythonExecutablePath, gitExecutablePath); - ToolsActivationJobListener toolsActivationJobListener = new ToolsActivationJobListener(ESPIDFMainTablePage.getInstance()); - toolsActivationJob.addJobChangeListener(toolsActivationJobListener); - toolsActivationJob.schedule(); - } - - // save state - Preferences prefs = getPreferences(); - prefs.putBoolean(IS_INSTALLER_CONFIG_SET, true); - try - { - prefs.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - IDFUtil.updateEspressifPrefPageOpenocdPath(); - - } - catch ( - IOException - | ParseException e) - { - Logger.log(e); - } - } - - @SuppressWarnings("static-access") - private void disableLaunchBarEvents(PropertyChangeEvent evt) - { - launchBarListener.setIgnoreTargetChange(true); - } - - @SuppressWarnings("static-access") - private void enableLaunchBarEvents(PropertyChangeEvent evt) - { - launchBarListener.setIgnoreTargetChange(false); - } - - @SuppressWarnings("unchecked") - private void openAvailableHintsDialog(PropertyChangeEvent evt) - { - Display.getDefault().asyncExec(() -> { - List erroHintPairs = (List) evt.getNewValue(); - // if list is empty we don't want to change focus from the console output - if (erroHintPairs.isEmpty()) - { - updateValuesInBuildView(erroHintPairs); - return; - } - try - { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(BUILDHINTS_ID); - } - catch (PartInitException e) - { - Logger.log(e); - } - updateValuesInBuildView(erroHintPairs); - }); - - } - - private void updateValuesInBuildView(List erroHintPairs) - { - BuildView view = ((BuildView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() - .findView(BUILDHINTS_ID)); - if (view != null) - { - view.updateReHintsPairs(erroHintPairs); - } - } - - private void openLowPartitionSizeDialog(PropertyChangeEvent evt) - { - Display.getDefault() - .asyncExec(() -> MessageLinkDialog.openWarning(Display.getDefault().getActiveShell(), - Messages.IncreasePartitionSizeTitle, MessageFormat.format(Messages.IncreasePartitionSizeMessage, - evt.getNewValue(), evt.getOldValue(), DOC_URL))); - } - - @SuppressWarnings("unchecked") - private void updateEspIdfJsonFile(File idf_json_file, String newIdfPathToUpdate) - { - JSONParser parser = new JSONParser(); - JSONObject jsonObj = null; - try (FileReader reader = new FileReader(idf_json_file)) - { - jsonObj = (JSONObject) parser.parse(reader); - String idfVersionId = (String) jsonObj.get(IDF_VERSIONS_ID); - JSONObject list = (JSONObject) jsonObj.get(IDF_INSTALLED_LIST_KEY); - if (list == null) - { - return; - } - // selected esp-idf version information - JSONObject selectedIDFInfo = (JSONObject) list.get(idfVersionId); - selectedIDFInfo.put(IDF_PATH, newIdfPathToUpdate); - list.put(idfVersionId, selectedIDFInfo); - jsonObj.put(IDF_INSTALLED_LIST_KEY, list); - } - catch ( - IOException - | ParseException e) - { - Logger.log(e); - } - - if (jsonObj != null) - { - try (FileWriter fileWriter = new FileWriter(idf_json_file)) - { - fileWriter.write(jsonObj.toJSONString()); - fileWriter.flush(); - - } - catch (IOException e) - { - Logger.log(e); - } - } - - } - - private void checkForUpdatedVersion(File idf_json_file) - { - // read esp-idf.json file - JSONParser parser = new JSONParser(); - try (FileReader reader = new FileReader(idf_json_file)) - { - JSONObject jsonObj = (JSONObject) parser.parse(reader); - String idfVersionId = (String) jsonObj.get(IDF_VERSIONS_ID); - JSONObject list = (JSONObject) jsonObj.get(IDF_INSTALLED_LIST_KEY); - if (list == null) - { - return; - } - // selected esp-idf version information - JSONObject selectedIDFInfo = (JSONObject) list.get(idfVersionId); - String idfPath = (String) selectedIDFInfo.get(IDF_PATH); - IDFEnvironmentVariables idfEnvMgr = new IDFEnvironmentVariables(); - if (idfEnvMgr.getEnvValue(IDFEnvironmentVariables.IDF_PATH).equals(idfPath)) - return; - newIdfPath = idfPath; - Preferences prefs = getPreferences(); - prefs.putBoolean(IS_INSTALLER_CONFIG_SET, false); - try - { - prefs.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - } - catch ( - IOException - | ParseException e) - { - Logger.log(e); - } - - } - - private Preferences getPreferences() - { - return InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); - } - - private boolean isInstallerConfigSet() - { - return getPreferences().getBoolean(IS_INSTALLER_CONFIG_SET, false); - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java index 7ce84c6d3..be7f03ca1 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/LaunchBarListener.java @@ -140,15 +140,17 @@ private void update(String newTarget) // If both are not same if (currentTarget != null && !newTarget.equals(currentTarget)) { - - boolean isDelete = MessageDialog.openQuestion(EclipseUtil.getShell(), + GlobalModalLock.showModal(() -> MessageDialog.openQuestion(EclipseUtil.getShell(), Messages.LaunchBarListener_TargetChanged_Title, MessageFormat.format(Messages.LaunchBarListener_TargetChanged_Msg, - project.getName(), currentTarget, newTarget)); - if (isDelete) - { - deleteBuildFolder(project, buildLocation); - } + project.getName(), currentTarget, newTarget)), + isDelete -> { + if (isDelete) + { + deleteBuildFolder(project, buildLocation); + + } + }); } } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SbomCommandDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SbomCommandDialog.java index d7445e758..0a27a578f 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SbomCommandDialog.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/SbomCommandDialog.java @@ -283,7 +283,7 @@ private String buildProjectDescriptionPath() private void runEspIdfSbomCommand() { - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); List arguments = new ArrayList<>(); final String pythonEnvPath = IDFUtil.getIDFPythonEnvPath(); arguments.add(pythonEnvPath); @@ -435,7 +435,7 @@ private boolean checkIfFileIsNotWritable(java.nio.file.Path pathToFile) private void installEspIdfSbom() { - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); List arguments = new ArrayList<>(); final String pythonEnvPath = IDFUtil.getIDFPythonEnvPath(); arguments.add(pythonEnvPath); @@ -450,7 +450,7 @@ private void installEspIdfSbom() private boolean getEspIdfSbomInstalledStatus() { - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); List arguments = new ArrayList<>(); final String pythonEnvPath = IDFUtil.getIDFPythonEnvPath(); arguments.add(pythonEnvPath); diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/NewProjectHandlerUtil.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/NewProjectHandlerUtil.java index 40a958223..2d7e76f25 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/NewProjectHandlerUtil.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/NewProjectHandlerUtil.java @@ -16,11 +16,11 @@ import com.espressif.idf.core.IDFEnvironmentVariables; import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimConstants; import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.StringUtil; import com.espressif.idf.ui.UIPlugin; import com.espressif.idf.ui.tools.ManageEspIdfVersionsHandler; -import com.espressif.idf.ui.update.InstallToolsHandler; public class NewProjectHandlerUtil { @@ -35,7 +35,7 @@ public static boolean installToolsCheck() String path = Optional.ofNullable(pathEnv).map(o -> o.getValue()).orElse(null); Preferences scopedPreferenceStore = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); - boolean isToolsInstalled = scopedPreferenceStore.getBoolean(InstallToolsHandler.INSTALL_TOOLS_FLAG, false); + boolean isToolsInstalled = scopedPreferenceStore.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false); if (StringUtil.isEmpty(idfPath)) { diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/UpdateEspIdfHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/UpdateEspIdfHandler.java deleted file mode 100644 index ddb74e7de..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/UpdateEspIdfHandler.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright 2022 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.handlers; - -import java.io.File; -import java.io.IOException; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.SubmoduleInitCommand; -import org.eclipse.jgit.api.SubmoduleUpdateCommand; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.submodule.SubmoduleWalk; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; - -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.ui.install.GitProgressMonitor; -import com.espressif.idf.ui.update.InstallToolsHandler; - -public class UpdateEspIdfHandler extends AbstractHandler -{ - @Override - public Object execute(ExecutionEvent event) throws ExecutionException - { - - Job job = new Job(Messages.UpdateEspIdfCommand_JobMsg) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - GitProgressMonitor gitProgressMonitor = new GitProgressMonitor(monitor); - - try (Git git = Git.open(new File(IDFUtil.getIDFPath()))) - { - git.pull().setProgressMonitor(gitProgressMonitor).call(); - SubmoduleInitCommand initCommand = git.submoduleInit(); - SubmoduleUpdateCommand updateCommand = git.submoduleUpdate(); - addRecursivePaths(git.getRepository(), initCommand, updateCommand); - initCommand.call(); - updateCommand.setFetch(true); - updateCommand.setProgressMonitor(gitProgressMonitor).call(); - return Status.OK_STATUS; - } - catch ( - IOException - | GitAPIException e) - { - Logger.log(e); - return Status.error(e.getLocalizedMessage()); - } - } - - private void addRecursivePaths(Repository repo, SubmoduleInitCommand initCommand, - SubmoduleUpdateCommand updateCommand) throws IOException - { - if (repo == null) - return; - try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) - { - while (generator.next()) - { - // Add current submodule path - initCommand.addPath(generator.getPath()); - updateCommand.addPath(generator.getPath()); - - // Recursively add paths for each submodule repository - addRecursivePaths(generator.getRepository(), initCommand, updateCommand); - } - } - finally - { - repo.close(); - } - } - }; - - - MutexRule rule = new MutexRule(); - job.setUser(true); - - openProgressView(); - Job installToolsJob = new Job(Messages.UpdateEspIdfCommand_InstallToolsJobMsg) - { - - @Override - protected IStatus run(IProgressMonitor monitor) - { - suggestInstallTools(); - return Status.OK_STATUS; - } - - private void suggestInstallTools() - { - Display.getDefault().asyncExec(new Runnable() - { - @Override - public void run() - { - boolean isYes = MessageDialog.openQuestion(Display.getDefault().getActiveShell(), - Messages.UpdateEspIdfCommand_InstallToolsJobMsg, - Messages.UpdateEspIdfCommand_SuggestToOpenInstallToolsWizard); - if (isYes) - { - InstallToolsHandler installToolsHandler = new InstallToolsHandler(); - try - { - installToolsHandler.setCommandId("com.espressif.idf.ui.command.install"); //$NON-NLS-1$ - installToolsHandler.execute(null); - } - catch (ExecutionException e) - { - Logger.log(e); - } - } - } - }); - - } - - }; - job.setRule(rule); - installToolsJob.setRule(rule); - job.schedule(); - installToolsJob.schedule(); - return null; - } - - private void openProgressView() - { - try - { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() - .showView("org.eclipse.ui.views.ProgressView"); //$NON-NLS-1$ - } - catch (PartInitException e) - { - Logger.log(e); - } - - } - - public class MutexRule implements ISchedulingRule - { - @Override - public boolean isConflicting(ISchedulingRule rule) - { - return rule == this; - } - - @Override - public boolean contains(ISchedulingRule rule) - { - return rule == this; - } - } - -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/help/ProductInformationHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/help/ProductInformationHandler.java index e7e988e15..afed00087 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/help/ProductInformationHandler.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/help/ProductInformationHandler.java @@ -131,7 +131,7 @@ private String getPythonExeVersion(String pythonExePath) List commands = new ArrayList<>(); commands.add(pythonExePath); commands.add("--version"); //$NON-NLS-1$ - return pythonExePath != null ? runCommand(commands, IDFUtil.getSystemEnv()) : null; + return pythonExePath != null ? runCommand(commands, System.getenv()) : null; } private String runCommand(List arguments, Map env) diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/GitRepositoryBuilder.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/GitRepositoryBuilder.java deleted file mode 100644 index 074f2ed09..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/GitRepositoryBuilder.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.install; - -import java.io.File; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jgit.api.Git; - -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.ui.tools.GitWizardRepProgressMonitor; - -/** - * @author Kondal Kolipaka - * - */ -public class GitRepositoryBuilder -{ - - private File repositoryDirectory; - private String activeBranch; - private String uri; - private IProgressMonitor monitor; - private boolean fromWizard; - private GitWizardRepProgressMonitor gitWizardRepProgressMonitor; - - public GitRepositoryBuilder(boolean fromWizard, GitWizardRepProgressMonitor gitWizardRepProgressMonitor) - { - this.fromWizard = fromWizard; - this.gitWizardRepProgressMonitor = gitWizardRepProgressMonitor; - } - - /** - * Location of the repository, or where the repository should be cloned. - * - * @param directory the directory - */ - public void repositoryDirectory(final File directory) - { - this.repositoryDirectory = directory; - } - - /** - * Active branch to checkout and use. - * - * @param value the value - */ - public void activeBranch(final String value) - { - this.activeBranch = value; - } - - public void repositoryClone() throws Exception - { - - Collection branchesToClone = new ArrayList<>(); - branchesToClone.add(getBranchPath(this.activeBranch)); - - GitProgressMonitor gitProgressMonitor = new GitProgressMonitor(monitor); - - // @formatter:off - Git git = Git.cloneRepository() - .setProgressMonitor(fromWizard ? gitWizardRepProgressMonitor : gitProgressMonitor) - .setCloneSubmodules(true) - .setURI(this.uri) - .setDirectory(this.repositoryDirectory) - .setBranchesToClone(branchesToClone) - .setBranch(getBranchPath(this.activeBranch)) - .setTimeout(300) - .call(); - - // @formatter:on - Logger.log(String.format(Messages.GitRepositoryBuilder_gitClone, git.toString())); - - // To release the lock on the file system resource - git.getRepository().close(); - - Logger.log(MessageFormat.format("ESP-IDF {0} cloning completed!", this.activeBranch)); //$NON-NLS-1$ - } - - private String getBranchPath(final String branchName) - { - return "refs/heads/" + branchName; //$NON-NLS-1$ - } - - public void repositoryURI(String uri) - { - this.uri = uri; - } - - public void setProgressMonitor(IProgressMonitor monitor) - { - this.monitor = monitor; - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java deleted file mode 100644 index 085580162..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java +++ /dev/null @@ -1,703 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.install; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Link; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; - -import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFVersion; -import com.espressif.idf.core.IDFVersionsReader; -import com.espressif.idf.core.ProcessBuilderFactory; -import com.espressif.idf.core.SystemExecutableFinder; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.UIPlugin; - -/** - * @author Kondal Kolipaka - * - */ -public class IDFDownloadPage extends WizardPage -{ - private static final int GIT_TOOL = 0; - private static final int PYTHON_TOOL = 1; - - private Combo versionCombo; - private Map versionsMap; - private Text directoryTxt; - private Button fileSystemBtn; - private Text existingIdfDirTxt; - private Button browseBtn; - - private Text gitText; - private Text pythonText; - - private String pythonExecutablePath; - private String gitExecutablePath; - private SystemExecutableFinder systemExecutableFinder; - - protected IDFDownloadPage(String pageName) - { - super(pageName); - setImageDescriptor(UIPlugin.getImageDescriptor(Messages.IDFDownloadPage_0)); - getPythonExecutablePath(); - } - - @Override - public void createControl(Composite parent) - { - Composite composite = new Composite(parent, SWT.NULL); - - initializeDialogUnits(parent); - - composite.setLayout(new GridLayout()); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createExistingComposite(composite); - - createGitPythonComposite(composite); - - // esp-idf version selection group - Group versionGrp = new Group(composite, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.numColumns = 3; - versionGrp.setLayout(layout); - versionGrp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - versionGrp.setText(Messages.IDFDownloadPage_DownloadIDF); - versionGrp.setFont(parent.getFont()); - - Label versionLbl = new Label(versionGrp, SWT.NONE); - versionLbl.setText(Messages.IDFDownloadPage_ChooseIDFVersion); - - versionCombo = new Combo(versionGrp, SWT.DROP_DOWN | SWT.READ_ONLY); - GridData gridData = new GridData(SWT.NONE, SWT.NONE, false, false, 2, 1); - gridData.widthHint = 250; - versionCombo.setLayoutData(gridData); - versionCombo.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - validate(); - } - }); - - versionsMap = new IDFVersionsReader().getVersionsMap(); - Set keySet = versionsMap.keySet(); - versionCombo.setItems(keySet.toArray(new String[keySet.size()])); - if (keySet.size() > 0) - { - versionCombo.select(0); - } - - createDownloadComposite(versionGrp); - createLinkArea(versionGrp); - - Label noteLbl = new Label(composite, SWT.NONE); - noteLbl.setText(Messages.IDFDownloadPage_Note); - - gridData = new GridData(SWT.LEFT, SWT.NONE, true, false, 1, 1); - gridData.verticalIndent = 10; - noteLbl.setLayoutData(gridData); - - setControl(composite); - setPageComplete(false); - } - - private void createGitPythonComposite(Composite parent) - { - Group gitPyGroup = new Group(parent, SWT.SHADOW_ETCHED_IN); - gitPyGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - final int numColumns = 3; - GridLayout gridLayout = new GridLayout(numColumns, false); - gitPyGroup.setLayout(gridLayout); - - Label gitLabel = new Label(gitPyGroup, SWT.NONE); - gitLabel.setText(Messages.GitLabel); - - gitText = new Text(gitPyGroup, SWT.SINGLE | SWT.BORDER); - gitText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - gitExecutablePath = IDFUtil.getGitExecutablePathFromSystem(); - - gitText.setText(gitExecutablePath); - gitText.addModifyListener(new ModifyTextValidationListener(GIT_TOOL)); - - Button gitBrowseButton = new Button(gitPyGroup, SWT.PUSH); - gitBrowseButton.setText(Messages.BrowseButton); - gitBrowseButton.addSelectionListener(new BrowseButtonSelectionAdapter(gitText, GIT_TOOL)); - - if (StringUtil.isEmpty(pythonExecutablePath)) - { - pythonExecutablePath = getPythonExecutablePath(); - } - - Label pythonLabel = new Label(gitPyGroup, SWT.NONE); - pythonLabel.setText(Messages.PythonLabel); - pythonText = new Text(gitPyGroup, SWT.SINGLE | SWT.BORDER); - pythonText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - pythonText.setText(pythonExecutablePath); - pythonText.addModifyListener(new ModifyTextValidationListener(PYTHON_TOOL)); - Button pythonBrowseButton = new Button(gitPyGroup, SWT.PUSH); - pythonBrowseButton.setText(Messages.BrowseButton); - pythonBrowseButton.addSelectionListener(new BrowseButtonSelectionAdapter(pythonText, PYTHON_TOOL)); - } - - private void createExistingComposite(Composite parent) - { - // File system selection - fileSystemBtn = new Button(parent, SWT.CHECK); - fileSystemBtn.setText(Messages.IDFDownloadPage_ChooseAnExistingIDF); - GridData gridData2 = new GridData(SWT.NONE, SWT.NONE, false, false, 1, 1); - gridData2.verticalIndent = 10; - fileSystemBtn.setLayoutData(gridData2); - - Group composite = new Group(parent, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.numColumns = 3; - composite.setLayout(layout); - composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - composite.setFont(parent.getFont()); - - Label label = new Label(composite, SWT.NONE); - label.setText(Messages.IDFDownloadPage_ChooseDirIDF); - - existingIdfDirTxt = new Text(composite, SWT.BORDER); - existingIdfDirTxt.setEnabled(false); - GridData data = new GridData(); - data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); - existingIdfDirTxt.setLayoutData(data); - existingIdfDirTxt.addModifyListener(new ModifyListener() - { - @Override - public void modifyText(ModifyEvent e) - { - validate(); - } - }); - - Button existingBrowseBtn = new Button(composite, SWT.PUSH); - existingBrowseBtn.setText(Messages.IDFDownloadPage_BrowseBtn); - existingBrowseBtn.setEnabled(false); - existingBrowseBtn.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent event) - { - DirectoryDialog dlg = new DirectoryDialog(getShell()); - dlg.setFilterPath(existingIdfDirTxt.getText()); - dlg.setText(Messages.IDFDownloadPage_DirectoryDialogTxt); - dlg.setMessage(Messages.IDFDownloadPage_DirectoryDialogMsg); - - String dir = dlg.open(); - if (dir != null) - { - existingIdfDirTxt.setText(dir); - } - } - }); - - fileSystemBtn.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - if (fileSystemBtn.getSelection()) - { - existingIdfDirTxt.setEnabled(true); - existingBrowseBtn.setEnabled(true); - - versionCombo.setEnabled(false); - directoryTxt.setEnabled(false); - browseBtn.setEnabled(false); - - } - else - { - existingIdfDirTxt.setEnabled(false); - existingBrowseBtn.setEnabled(false); - - versionCombo.setEnabled(true); - directoryTxt.setEnabled(true); - browseBtn.setEnabled(true); - - } - validate(); - } - }); - - } - - private void createDownloadComposite(Composite composite) - { - Label descLbl = new Label(composite, SWT.NONE); - descLbl.setText(Messages.IDFDownloadPage_ChooseIDFDir); - - directoryTxt = new Text(composite, SWT.BORDER); - GridData data = new GridData(); - data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); - directoryTxt.setLayoutData(data); - directoryTxt.setFocus(); - directoryTxt.addModifyListener(new ModifyListener() - { - @Override - public void modifyText(ModifyEvent e) - { - validate(); - } - }); - - browseBtn = new Button(composite, SWT.PUSH); - browseBtn.setText(Messages.IDFDownloadPage_BrowseBtnTxt); - browseBtn.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent event) - { - DirectoryDialog dlg = new DirectoryDialog(getShell()); - dlg.setFilterPath(directoryTxt.getText()); - dlg.setText(Messages.IDFDownloadPage_DirectoryDialogText); - dlg.setMessage(Messages.IDFDownloadPage_DirectoryDialogMessage); - - String dir = dlg.open(); - if (dir != null) - { - directoryTxt.setText(dir); - } - } - }); - - } - - private String getPythonExecutablePath() - { - return IDFUtil.getPythonExecutable(); - } - - private void createLinkArea(Composite parent) - { - Link link = new Link(parent, SWT.NONE); - String message = Messages.IDFDownloadPage_VersionLinkMsg; - link.setText(message); - link.setSize(400, 100); - - GridData gridData = new GridData(SWT.NONE, SWT.NONE, false, false, 3, 1); - gridData.verticalIndent = 10; - link.setLayoutData(gridData); - - link.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - try - { - // Open default external browser - PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(e.text)); - } - catch (PartInitException ex) - { - ex.printStackTrace(); - } - catch (MalformedURLException ex) - { - ex.printStackTrace(); - } - } - }); - } - - private boolean validateGitAndPython() - { - if (systemExecutableFinder == null) - { - systemExecutableFinder = new SystemExecutableFinder(); - } - - if (StringUtil.isEmpty(pythonExecutablePath) || StringUtil.isEmpty(gitExecutablePath)) - { - setErrorMessage("Python & Git are Required"); - return false; - } - - - IPath pathGit = systemExecutableFinder.find(gitExecutablePath); - if (pathGit != null) - gitExecutablePath = pathGit.toOSString(); - - File file = new File(gitExecutablePath); - if (!file.exists() && !IDFUtil.isReparseTag(file)) - { - setErrorMessage("Git executable not found"); - return false; - } - - IPath pythonPath = systemExecutableFinder.find(pythonExecutablePath); - if (pythonPath != null) - { - pythonExecutablePath = pythonPath.toOSString(); - } - file = new File(pythonExecutablePath); - if (!file.exists() && !IDFUtil.isReparseTag(file)) - { - setErrorMessage("Python executable not found"); - return false; - } - - return true; - } - - private void validate() - { - if (fileSystemBtn.getSelection()) - { - String idfPath = existingIdfDirTxt.getText(); - if (StringUtil.isEmpty(idfPath)) - { - setPageComplete(false); - setErrorMessage("IDF Directory is Required"); - return; - } - - if (!new File(idfPath).exists()) - { - setErrorMessage(Messages.IDFDownloadPage_DirDoesnotExist+ idfPath); - setPageComplete(false); - return; - } - - String version = getIdfVersionUsingGit(idfPath); - - if (idfPath.contains(" ") && !StringUtil.isEmpty(version)) //$NON-NLS-1$ - { - boolean validVersion = isVersionGreaterOrEqual(version, "5.0.0"); //$NON-NLS-1$ - if (!validVersion) - { - setErrorMessage(Messages.IDFDownloadPage_VersionSpaceError); - setPageComplete(false); - return; - } - if (getErrorMessage() == null || getErrorMessage().equals(Messages.IDFDownloadPage_VersionSpaceError)) - { - setErrorMessage(null); - setPageComplete(true); - } - } - - String idfPyPath = idfPath + File.separator + IDFConstants.TOOLS_FOLDER + File.separator + IDFConstants.IDF_PYTHON_SCRIPT; - String idfToolsPyPth = idfPath + File.separator + IDFConstants.TOOLS_FOLDER + File.separator + IDFConstants.IDF_TOOLS_SCRIPT; - if (!new File (idfPyPath).exists() || !new File (idfToolsPyPth).exists()) - { - setErrorMessage(MessageFormat.format(Messages.IDFDownloadPage_CantfindProperEspIDFDirectory, idfPath)); - setPageComplete(false); - return; - } - if (validateGitAndPython()) - { - setPageComplete(true); - setErrorMessage(null); - setMessage(Messages.IDFDownloadPage_ClickOnFinish + idfPath); - } - else - { - setPageComplete(false); - } - } - else - { - setMessage(StringUtil.EMPTY); - setErrorMessage(null); - boolean supportSpaces = false; - if (versionCombo.getText().contentEquals("master")) //$NON-NLS-1$ - { - supportSpaces = true; - } - else - { - Pattern p = Pattern.compile("([0-9][.][0-9])"); //$NON-NLS-1$ - Matcher m = p.matcher(versionCombo.getText()); - supportSpaces = m.find() && Double.parseDouble(m.group(0)) >= 5.0; - } - if (StringUtil.isEmpty(directoryTxt.getText())) - { - setPageComplete(false); - return; - } - - if (!supportSpaces && directoryTxt.getText().contains(" ")) //$NON-NLS-1$ - { - setErrorMessage(Messages.IDFDownloadPage_VersionSpaceError); - setPageComplete(false); - return; - } - - if (validateGitAndPython()) - { - setPageComplete(true); - setErrorMessage(null); - setMessage(Messages.IDFDownloadPage_ClickFinishToDownload); - } - else - { - setPageComplete(false); - } - } - } - - private String getIdfVersionUsingGit(String idfPath) - { - if (!validateGitAndPython()) - return StringUtil.EMPTY; - - List commands = new ArrayList(); - commands.add(gitExecutablePath); - commands.add("describe"); //$NON-NLS-1$ - - ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - try - { - Logger.log("Executing commads: " + commands.toString()); - Map environment = new HashMap<>(System.getenv()); - IStatus status = processRunner.runInBackground(commands, Path.fromOSString(idfPath), environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), - IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - return StringUtil.EMPTY; - } - String cmdOutput = status.getMessage(); - String version = StringUtil.EMPTY; - String patternString = "\\d+\\.\\d+\\.\\d+"; //$NON-NLS-1$ - Pattern pattern = Pattern.compile(patternString); - Matcher matcher = pattern.matcher(cmdOutput); - if (matcher.find()) - { - version = matcher.group(0); - } - - if(StringUtil.isEmpty(version)) - { - return StringUtil.EMPTY; - } - - return version; - } - catch (Exception e) - { - Logger.log(e); - } - - return StringUtil.EMPTY; - } - - private boolean isVersionGreaterOrEqual(String version, String minVersion) - { - // Define the regex pattern to match version numbers - String pattern = "\\d+\\.\\d+\\.\\d+"; //$NON-NLS-1$ - Pattern r = Pattern.compile(pattern); - - // Now create matcher object. - Matcher m = r.matcher(version); - Matcher mMin = r.matcher(minVersion); - - if (m.find() && mMin.find()) - { - String[] currentVersionParts = m.group(0).split("\\."); //$NON-NLS-1$ - String[] minVersionParts = mMin.group(0).split("\\."); //$NON-NLS-1$ - - int currentMajor = Integer.parseInt(currentVersionParts[0]); - int currentMinor = Integer.parseInt(currentVersionParts[1]); - int currentPatch = Integer.parseInt(currentVersionParts[2]); - - int minMajor = Integer.parseInt(minVersionParts[0]); - int minMinor = Integer.parseInt(minVersionParts[1]); - int minPatch = Integer.parseInt(minVersionParts[2]); - - if (currentMajor > minMajor) - { - return true; - } - else if (currentMajor == minMajor) - { - if (currentMinor > minMinor) - { - return true; - } - else if (currentMinor == minMinor) - { - return currentPatch >= minPatch; - } - } - } - - return false; - } - - - protected IDFVersion Version() - { - String versionTxt = versionCombo.getText(); - IDFVersion version = versionsMap.get(versionTxt); - return version; - } - - public String getDestinationLocation() - { - return directoryTxt.getText().trim(); - } - - public String getExistingIDFLocation() - { - return existingIdfDirTxt.getText().trim(); - } - - public boolean isConfigureExistingEnabled() - { - return fileSystemBtn.getSelection(); - } - - public String getPythonExePath() - { - return pythonExecutablePath; - } - - public String getGitExecutablePath() - { - return gitExecutablePath; - } - - private class BrowseButtonSelectionAdapter extends SelectionAdapter - { - private Text linkedText; - private int dialog; - private static final String GIT_FILE = "git"; //$NON-NLS-1$ - private static final String PYTHON_FILE = "python*"; //$NON-NLS-1$ - private static final String PYTHON_FILTERS = "Python Executables"; //$NON-NLS-1$ - private static final String WINDOWS_EXTENSION = ".exe"; //$NON-NLS-1$ - - private BrowseButtonSelectionAdapter(Text text, int dialog) - { - this.linkedText = text; - this.dialog = dialog; - } - - @Override - public void widgetSelected(SelectionEvent selectionEvent) - { - FileDialog dlg = null; - if (dialog == GIT_TOOL) - { - dlg = gitDialog(); - } - else - { - dlg = pythonDialog(); - } - - dlg.setText(Messages.FileSelectionDialogTitle); - String dir = dlg.open(); - if (!StringUtil.isEmpty(dir)) - { - linkedText.setText(dir); - } - } - - private FileDialog pythonDialog() - { - FileDialog dialog = new FileDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell()); - if (Platform.getOS().equals(Platform.OS_WIN32)) - { - dialog.setFilterNames(new String[] { PYTHON_FILTERS }); - dialog.setFilterExtensions(new String[] { PYTHON_FILE.concat(WINDOWS_EXTENSION) }); - } - else - { - dialog.setFilterNames(new String[] { PYTHON_FILTERS }); - dialog.setFilterExtensions(new String[] { PYTHON_FILE }); - } - return dialog; - } - - private FileDialog gitDialog() - { - FileDialog dialog = new FileDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell()); - if (Platform.getOS().equals(Platform.OS_WIN32)) - { - dialog.setFilterNames(new String[] { GIT_FILE.concat(WINDOWS_EXTENSION) }); - dialog.setFilterExtensions(new String[] { GIT_FILE.concat(WINDOWS_EXTENSION) }); - } - else - { - dialog.setFilterNames(new String[] { GIT_FILE }); - dialog.setFilterExtensions(new String[] { GIT_FILE }); - } - - return dialog; - } - } - - private class ModifyTextValidationListener implements ModifyListener - { - private int tool; - - private ModifyTextValidationListener(int tool) - { - this.tool = tool; - } - - @Override - public void modifyText(ModifyEvent e) - { - switch (tool) - { - case GIT_TOOL: - gitExecutablePath = gitText.getText(); - break; - case PYTHON_TOOL: - pythonExecutablePath = pythonText.getText(); - default: - break; - } - - validate(); - } - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFNewToolsWizard.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFNewToolsWizard.java deleted file mode 100644 index 6295948f7..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFNewToolsWizard.java +++ /dev/null @@ -1,350 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.install; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.text.MessageFormat; -import java.util.List; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.IJobChangeEvent; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.jobs.JobChangeAdapter; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; - -import com.espressif.idf.core.IDFVersion; -import com.espressif.idf.core.ZipUtility; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.ToolSetConfigurationManager; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.tools.ToolsActivationJob; -import com.espressif.idf.ui.tools.ToolsActivationJobListener; -import com.espressif.idf.ui.tools.ToolsInstallationJob; -import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; - -/** - * @author Kondal Kolipaka , Ali Azam Rana - * - */ -public class IDFNewToolsWizard extends Wizard -{ - private static final int BUFFER_SIZE = 4096; // $NON-NLS-1$ - private IDFDownloadPage downloadPage; - private ESPIDFMainTablePage espidfMainTablePage; - private ToolSetConfigurationManager toolSetConfigurationManager; - private ToolsInstallationJob toolsInstallationJob; - private String pythonPath; - private String gitPath; - - public IDFNewToolsWizard() - { - } - - public IDFNewToolsWizard(ESPIDFMainTablePage espidfMainTablePage) - { - this.espidfMainTablePage = espidfMainTablePage; - toolSetConfigurationManager = new ToolSetConfigurationManager(); - } - - @Override - public boolean performFinish() - { - IDFVersion version = downloadPage.Version(); - String destinationLocation = downloadPage.getDestinationLocation(); - boolean configureExistingEnabled = downloadPage.isConfigureExistingEnabled(); - pythonPath = downloadPage.getPythonExePath(); - gitPath = downloadPage.getGitExecutablePath(); - - if (configureExistingEnabled) - { - String localIdfLocation = downloadPage.getExistingIDFLocation(); - - toolsInstallationJob = new ToolsInstallationJob(pythonPath, gitPath, localIdfLocation); - toolsInstallationJob.addJobChangeListener(new ToolsInstallationJobChangeListener()); - toolsInstallationJob.schedule(); - - } - else - { - new File(destinationLocation).mkdirs(); - String url = version.getUrl(); - if (version.getName().equals("master") || version.getName().startsWith("release/")) //$NON-NLS-1$ //$NON-NLS-2$ - { - Job job = new Job(MessageFormat.format(Messages.IDFDownloadWizard_CloningJobMsg, version.getName())) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - String localIdfLocation = repositoryClone(version.getName(), url, destinationLocation, monitor); - toolsInstallationJob = new ToolsInstallationJob(pythonPath, gitPath, localIdfLocation); - toolsInstallationJob.addJobChangeListener(new ToolsInstallationJobChangeListener()); - toolsInstallationJob.schedule(); - return Status.OK_STATUS; - } - }; - - job.setUser(true); - job.schedule(); - } - else - { - Job job = new Job(MessageFormat.format(Messages.IDFDownloadWizard_DownloadingJobMsg, version.getName())) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - String localIdfLocation = download(monitor, url, destinationLocation); - toolsInstallationJob = new ToolsInstallationJob(pythonPath, gitPath, localIdfLocation); - toolsInstallationJob.addJobChangeListener(new ToolsInstallationJobChangeListener()); - toolsInstallationJob.schedule(); - return Status.OK_STATUS; - } - }; - - job.setUser(true); - job.schedule(); - - } - - // Show the progress in Progress View - openProgressView(); - } - - return true; - } - - private void openProgressView() - { - try - { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() - .showView("org.eclipse.ui.views.ProgressView"); //$NON-NLS-1$ - } - catch (PartInitException e) - { - Logger.log(e); - } - - } - - protected String download(IProgressMonitor monitor, String url, String destinationLocation) - { - try - { - String downloadFile = downloadFile(url, destinationLocation, monitor); - if (downloadFile != null) - { - unZipFile(downloadFile, destinationLocation); - new File(downloadFile).delete(); - - // extracts file name from URL - String folderName = new File(url).getName().replace(".zip", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - return new File(destinationLocation, folderName).getAbsolutePath(); - } - } - catch (IOException e) - { - Logger.log(e); - showErrorMessage(e.getLocalizedMessage()); - } - - return StringUtil.EMPTY; - } - - protected String repositoryClone(String version, String url, String destinationLocation, IProgressMonitor monitor) - { - GitRepositoryBuilder gitBuilder = new GitRepositoryBuilder(false, null); - StringBuilder destinationLocationPath = new StringBuilder(); - destinationLocationPath.append(destinationLocation); - destinationLocationPath.append("/esp-idf-"); //$NON-NLS-1$ - if (version.startsWith("release/")) //$NON-NLS-1$ - { - destinationLocationPath.append(version.substring("release/".length())); //$NON-NLS-1$ - } - else - { - destinationLocationPath.append(version); - } - - gitBuilder.repositoryURI(url); - gitBuilder.repositoryDirectory(new File(destinationLocationPath.toString())); - gitBuilder.activeBranch(version); - gitBuilder.setProgressMonitor(monitor); - - try - { - gitBuilder.repositoryClone(); - return destinationLocationPath.toString(); - - } - catch (Exception e) - { - Logger.log(e); - showErrorMessage(e.getLocalizedMessage()); - } - - return StringUtil.EMPTY; - } - - private void unZipFile(String downloadFile, String destinationLocation) - { - new ZipUtility().decompress(new File(downloadFile), new File(destinationLocation)); - } - - private void showErrorMessage(String errorMessage) - { - Display.getDefault().asyncExec(new Runnable() - { - public void run() - { - MessageDialog.openError(Display.getDefault().getActiveShell(), Messages.IDFDownloadWizard_ErrorTitle, - errorMessage); - } - }); - } - - public void init(IWorkbench aWorkbench, IStructuredSelection currentSelection) - { - setNeedsProgressMonitor(true); - } - - @Override - public void addPages() - { - downloadPage = new IDFDownloadPage("Download page"); //$NON-NLS-1$ - addPage(downloadPage); - } - - protected String downloadFile(String fileURL, String saveDir, IProgressMonitor monitor) throws IOException - { - - String msg = MessageFormat.format(Messages.IDFDownloadWizard_DownloadingMessage, fileURL); - Logger.log(msg); - monitor.beginTask(msg, 100); - - URL url = new URL(fileURL); - HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); - int responseCode = httpConn.getResponseCode(); - - // always check HTTP response code first - if (responseCode == HttpURLConnection.HTTP_OK) - { - String fileName = ""; //$NON-NLS-1$ - String disposition = httpConn.getHeaderField("Content-Disposition"); //$NON-NLS-1$ - String contentType = httpConn.getContentType(); - int contentLength = httpConn.getContentLength(); - - if (disposition != null) - { - // extracts file name from header field - String identifier = "filename="; //$NON-NLS-1$ - int index = disposition.indexOf(identifier); - if (index > 0) - { - fileName = disposition.substring(index + identifier.length(), disposition.length()); - } - } - else - { - // extracts file name from URL - fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1, fileURL.length()); //$NON-NLS-1$ - } - - Logger.log("Content-Type = " + contentType); //$NON-NLS-1$ - Logger.log("Content-Disposition = " + disposition); //$NON-NLS-1$ - Logger.log("Content-Length = " + contentLength); //$NON-NLS-1$ - Logger.log("fileName = " + fileName); //$NON-NLS-1$ - - // opens input stream from the HTTP connection - InputStream inputStream = httpConn.getInputStream(); - String saveFilePath = saveDir + File.separator + fileName; - - // opens an output stream to save into file - FileOutputStream outputStream = new FileOutputStream(saveFilePath); - - float downloaded = 0f; - int bytesRead = -1; - int noOfUnitedUpdated = 0; - byte[] buffer = new byte[BUFFER_SIZE]; - while ((bytesRead = inputStream.read(buffer)) != -1) - { - outputStream.write(buffer, 0, bytesRead); - downloaded = downloaded + BUFFER_SIZE; - int unitsDownloadedSofar = (int) ((downloaded / contentLength) * 100); - if (unitsDownloadedSofar > noOfUnitedUpdated) - { - int needToBeUpdated = unitsDownloadedSofar - noOfUnitedUpdated; - noOfUnitedUpdated = noOfUnitedUpdated + needToBeUpdated; - String taskName = MessageFormat.format(msg + "({0}/{1})", convertToMB(downloaded), //$NON-NLS-1$ - convertToMB(contentLength)); - monitor.setTaskName(taskName); - monitor.worked(needToBeUpdated); - } - if (monitor.isCanceled()) - { - Logger.log("File download cancelled"); //$NON-NLS-1$ - saveFilePath = null; - break; - } - } - - outputStream.close(); - inputStream.close(); - - return saveFilePath; - } - else - { - Logger.log("No file to download. Server replied HTTP code: " + responseCode); //$NON-NLS-1$ - } - httpConn.disconnect(); - return null; - } - - protected String convertToMB(float value) - { - return String.format("%.2f", (value / (1024 * 1024))) + " MB"; //$NON-NLS-1$ //$NON-NLS-2$ - } - - - private class ToolsInstallationJobChangeListener extends JobChangeAdapter - { - @Override - public void done(IJobChangeEvent event) - { - List idfToolSets = toolSetConfigurationManager.getIdfToolSets(false); - Display.getDefault().asyncExec(() -> { - if (espidfMainTablePage != null) - { - espidfMainTablePage.refreshEditorUI(); - } - }); - - if (idfToolSets != null && idfToolSets.size() == 1) - { - ToolsActivationJob toolsActivationJob = new ToolsActivationJob(idfToolSets.get(0), pythonPath, gitPath); - ToolsActivationJobListener toolsActivationJobListener = new ToolsActivationJobListener(espidfMainTablePage); - toolsActivationJob.addJobChangeListener(toolsActivationJobListener); - toolsActivationJob.schedule(); - } - - } - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/Messages.java deleted file mode 100644 index cc53e5c79..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/Messages.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.espressif.idf.ui.install; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS -{ - private static final String BUNDLE_NAME = "com.espressif.idf.ui.install.messages"; //$NON-NLS-1$ - public static String GitRepositoryBuilder_gitClone; - public static String IDFDownloadPage_0; - public static String IDFDownloadPage_BrowseBtn; - public static String IDFDownloadPage_BrowseBtnTxt; - public static String IDFDownloadPage_CantfindProperEspIDFDirectory; - public static String IDFDownloadPage_CantFindRequirementsFile; - public static String IDFDownloadPage_ChooseAnExistingIDF; - public static String IDFDownloadPage_ChooseDirIDF; - public static String IDFDownloadPage_ChooseIDFDir; - public static String IDFDownloadPage_ChooseIDFVersion; - public static String IDFDownloadPage_ClickFinishToDownload; - public static String IDFDownloadPage_ClickOnFinish; - public static String IDFDownloadPage_DirDoesnotExist; - public static String IDFDownloadPage_DirectoryDialogMessage; - public static String IDFDownloadPage_DirectoryDialogMsg; - public static String IDFDownloadPage_DirectoryDialogText; - public static String IDFDownloadPage_DirectoryDialogTxt; - public static String IDFDownloadPage_VersionSpaceError; - public static String IDFDownloadPage_DownloadIDF; - public static String IDFDownloadPage_IDFBuildNotSupported; - public static String IDFDownloadPage_Note; - public static String IDFDownloadPage_VersionLinkMsg; - public static String IDFDownloadWizard_CloningCompletedMsg; - public static String IDFDownloadWizard_CloningJobMsg; - public static String IDFDownloadWizard_ConfigMessage; - public static String IDFDownloadWizard_DownloadCompleteMsg; - public static String IDFDownloadWizard_DownloadingJobMsg; - public static String IDFDownloadWizard_DownloadingMessage; - public static String IDFDownloadWizard_ErrorTitle; - public static String IDFDownloadWizard_MessageTitle; - public static String IDFDownloadWizard_AllowSpacesTitle; - public static String IDFDownloadWizard_AllowSpacesMsg; - - public static String BrowseButton; - public static String GitLabel; - public static String PythonLabel; - public static String FileSelectionDialogTitle; - static - { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() - { - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages.properties deleted file mode 100644 index 071dc26af..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages.properties +++ /dev/null @@ -1,35 +0,0 @@ -GitRepositoryBuilder_gitClone=git clone result: %s -IDFDownloadPage_0=icons/espressif_logo.png -IDFDownloadPage_BrowseBtn=Browse... -IDFDownloadPage_BrowseBtnTxt=Browse... -IDFDownloadPage_CantfindProperEspIDFDirectory=Can not find idf python scripts in {0} tools. Make sure to select valid ESP-IDF directory. -IDFDownloadPage_ChooseAnExistingIDF=Use an existing ESP-IDF directory from file system -IDFDownloadPage_ChooseDirIDF=Choose existing ESP-IDF directory: -IDFDownloadPage_ChooseIDFDir=Choose a directory to download ESP-IDF to: -IDFDownloadPage_ChooseIDFVersion=Please choose ESP-IDF version to download: -IDFDownloadPage_ClickFinishToDownload=Click on `Finish` to download -IDFDownloadPage_ClickOnFinish=Click on `Finish` to configure IDF_PATH with -IDFDownloadPage_DirDoesnotExist=Directory doesn''t exist: -IDFDownloadPage_VersionSpaceError=ESP-IDF build system support spaces in paths after v5.0. Please choose a different directory. -IDFDownloadPage_DirectoryDialogMessage=Choose Directory to download ESP-IDF -IDFDownloadPage_DirectoryDialogMsg=Select ESP-IDF Directory: -IDFDownloadPage_DirectoryDialogText=Choose Directory -IDFDownloadPage_DirectoryDialogTxt=ESP-IDF Directory: -IDFDownloadPage_DownloadIDF=Download ESP-IDF -IDFDownloadPage_IDFBuildNotSupported=ESP-IDF build system does not support spaces in paths. Please choose a different directory. -IDFDownloadPage_Note=Note: The newly configured ESP-IDF will set to IDF_PATH in the CDT Build environment (Preferences > C/C++ > Build > Environment) -IDFDownloadPage_VersionLinkMsg=For more information about ESP-IDF versions, see https://docs.espressif.com/projects/esp-idf/en/latest/versions.html -IDFDownloadWizard_CloningCompletedMsg=ESP-IDF {0} cloning completed\! This might require a new set of tools to be installed. Do you want to install them? -IDFDownloadWizard_CloningJobMsg=Cloning ESP-IDF {0}... -IDFDownloadWizard_ConfigMessage=IDF_PATH configured with {0}. This might require a new set of tools to be installed. Do you want to install them? -IDFDownloadWizard_DownloadCompleteMsg={0} download completed\! This might require a new set of tools to be installed. Do you want to install them? -IDFDownloadWizard_DownloadingJobMsg=Downloading ESP-IDF {0}... -IDFDownloadWizard_DownloadingMessage=Downloading {0}... -IDFDownloadWizard_ErrorTitle=Error -IDFDownloadWizard_MessageTitle=Message -IDFDownloadWizard_AllowSpacesTitle=Space detected! -IDFDownloadWizard_AllowSpacesMsg=Detected a whitespace character in path. Spaces in IDF_PATH and project paths are allowed in versions 5.0 and higher. By clicking "Yes", you confirm that your version supports spaces. -PythonLabel=Python: -BrowseButton=Browse -GitLabel=Git: -FileSelectionDialogTitle=Select tool executable file \ No newline at end of file diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages_zh.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages_zh.properties deleted file mode 100644 index 86fd023cb..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/messages_zh.properties +++ /dev/null @@ -1,32 +0,0 @@ -GitRepositoryBuilder_gitClone=git \u514b\u9686\u7ed3\u679c\uff1a%s -IDFDownloadPage_0=icons/espressif_logo.png -IDFDownloadPage_BrowseBtn=\u6d4f\u89c8... -IDFDownloadPage_BrowseBtnTxt=\u6d4f\u89c8... -IDFDownloadPage_CantfindIDFpy={0} \u5de5\u5177\u4e2d\u627e\u4e0d\u5230 idf.py -IDFDownloadPage_CantFindRequirementsFile={0} \u4e2d\u627e\u4e0d\u5230 requirements.txt \u6587\u4ef6 -IDFDownloadPage_ChooseAnExistingIDF=\u4f7f\u7528\u6587\u4ef6\u7cfb\u7edf\u4e2d\u73b0\u6709\u7684 ESP-IDF \u76ee\u5f55 -IDFDownloadPage_ChooseDirIDF=\u9009\u62e9\u73b0\u6709\u7684 ESP-IDF \u76ee\u5f55\uff1a -IDFDownloadPage_ChooseIDFDir=\u9009\u62e9 ESP-IDF \u7684\u4e0b\u8f7d\u76ee\u5f55\uff1a -IDFDownloadPage_ChooseIDFVersion=\u8bf7\u9009\u62e9\u9700\u8981\u4e0b\u8f7d\u7684 ESP-IDF \u7248\u672c\uff1a -IDFDownloadPage_ClickFinishToDownload=\u5355\u51fb `\u5b8c\u6210` \u5f00\u59cb\u4e0b\u8f7d -IDFDownloadPage_ClickOnFinish=\u5355\u51fb `\u5b8c\u6210` \u914d\u7f6e IDF_PATH -IDFDownloadPage_DirDoesnotExist=\u76ee\u5f55\u4e0d\u5b58\u5728\uff1a -IDFDownloadPage_DirectoryDialogMessage=\u9009\u62e9 ESP-IDF \u7684\u4e0b\u8f7d\u76ee\u5f55\uff1a -IDFDownloadPage_DirectoryDialogMsg=\u9009\u62e9 ESP-IDF \u76ee\u5f55\uff1a -IDFDownloadPage_DirectoryDialogText=\u9009\u62e9\u76ee\u5f55\uff1a -IDFDownloadPage_DirectoryDialogTxt=ESP-IDF \u76ee\u5f55\uff1a -IDFDownloadPage_DownloadIDF=\u4e0b\u8f7d ESP-IDF -IDFDownloadPage_IDFBuildNotSupported=ESP-IDF \u6784\u5efa\u7cfb\u7edf\u4e0d\u652f\u6301\u8def\u5f84\u4e2d\u6709\u7a7a\u683c\u3002\u8bf7\u9009\u62e9\u4e00\u4e2a\u5176\u4ed6\u76ee\u5f55\u3002 -IDFDownloadPage_Note=\u6ce8\u610f\uff1a\u65b0\u914d\u7f6e\u7684 ESP-IDF \u5c06\u8bbe\u7f6e\u4e3a CDT \u6784\u5efa\u73af\u5883\u4e2d\u7684 IDF_PATH\uff08\u504f\u597d\u8bbe\u7f6e > C/C++ > \u6784\u5efa > \u73af\u5883\uff09 -IDFDownloadPage_VersionLinkMsg=\u6709\u5173 ESP-IDF \u7248\u672c\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html -IDFDownloadWizard_CloningCompletedMsg=ESP-IDF {0} \u514b\u9686\u5b8c\u6210\uff01\u8fd9\u53ef\u80fd\u9700\u8981\u5b89\u88c5\u4e00\u7ec4\u65b0\u7684\u5de5\u5177\u3002\u662f\u5426\u8981\u5b89\u88c5\u8fd9\u4e9b\u5de5\u5177\uff1f -IDFDownloadWizard_CloningJobMsg=\u514b\u9686 ESP-IDF {0}... -IDFDownloadWizard_ConfigMessage=IDF_PATH \u914d\u7f6e\u4e3a {0}\u3002\u8fd9\u53ef\u80fd\u9700\u8981\u5b89\u88c5\u4e00\u7ec4\u65b0\u7684\u5de5\u5177\u3002\u662f\u5426\u8981\u5b89\u88c5\u8fd9\u4e9b\u5de5\u5177\uff1f -IDFDownloadWizard_DownloadCompleteMsg={0} \u4e0b\u8f7d\u5b8c\u6210\uff01\u8fd9\u53ef\u80fd\u9700\u8981\u5b89\u88c5\u4e00\u7ec4\u65b0\u7684\u5de5\u5177\u3002\u662f\u5426\u8981\u5b89\u88c5\u8fd9\u4e9b\u5de5\u5177\uff1f -IDFDownloadWizard_DownloadingJobMsg=\u4e0b\u8f7d ESP-IDF {0}... -IDFDownloadWizard_DownloadingMessage=\u4e0b\u8f7d {0}... -IDFDownloadWizard_ErrorTitle=\u9519\u8bef -IDFDownloadWizard_MessageTitle=\u6d88\u606f -IDFDownloadWizard_AllowSpacesTitle=\u68c0\u6d4b\u5230\u7a7a\u683c\uff01 -IDFDownloadWizard_AllowSpacesMsg=\u68c0\u6d4b\u5230\u8def\u5f84\u4e2d\u5b58\u5728\u7a7a\u683c\u5b57\u7b26\u30025.0 \u53ca\u4ee5\u4e0a\u7248\u672c\u5141\u8bb8 IDF_PATH \u548c\u9879\u76ee\u8def\u5f84\u4e2d\u5b58\u5728\u7a7a\u683c\u3002\u5982\u5df2\u786e\u5b9a\u60a8\u7684\u7248\u672c\u53ef\u652f\u6301\u7a7a\u683c\uff0c\u8bf7\u5355\u51fb\u201c\u662f\u201d\u3002 - diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsColumn.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsColumn.java new file mode 100644 index 000000000..dd7dbe650 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsColumn.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui.nvs.dialog; + +import java.util.stream.Stream; + +/** + * Represents the columns in the NVS TableViewer. This enum provides a type-safe way to manage column properties, + * replacing "magic numbers" and string arrays. + */ +public enum NvsColumn +{ + + KEY("Key", 100), TYPE("Type", 100), ENCODING("Encoding", 100), VALUE("Value", 150); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + + private final String displayName; + private final int defaultWidth; + + NvsColumn(String displayName, int defaultWidth) + { + this.displayName = displayName; + this.defaultWidth = defaultWidth; + } + + /** + * @return The human-readable name for the table header. + */ + public String getDisplayName() + { + return displayName; + } + + /** + * @return The default pixel width for the column. + */ + public int getDefaultWidth() + { + return defaultWidth; + } + + /** + * @return The integer index (position) of this column. + */ + public int getIndex() + { + return this.ordinal(); + } + + /** + * A static helper to get an array of all display names for JFace APIs like {@code setColumnProperties}. + * + * @return ["Key", "Type", "Encoding", "Value"] + */ + public static String[] getColumnProperties() + { + return Stream.of(values()).map(NvsColumn::getDisplayName).toArray(String[]::new); + } + + /** + * A static helper to get the enum constant from its index. + * + * @param index The column index. + * @return The matching NvsColumn (e.g., KEY for index 0). + */ + public static NvsColumn fromIndex(int index) + { + if (index >= 0 && index < values().length) + { + return values()[index]; + } + // This should ideally not be reachable if validation is correct + throw new IndexOutOfBoundsException("Invalid column index: " + index); //$NON-NLS-1$ + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsCsvEditorPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsCsvEditorPage.java new file mode 100644 index 000000000..d49a8f542 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsCsvEditorPage.java @@ -0,0 +1,744 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ + +package com.espressif.idf.ui.nvs.dialog; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.ComboBoxCellEditor; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; + +import com.espressif.idf.core.build.NvsTableBean; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.util.NvsBeanValidator; +import com.espressif.idf.core.util.NvsPartitionGenerator; +import com.espressif.idf.core.util.NvsTableDataService; +import com.espressif.idf.core.util.StringUtil; + +/** + * Manages the UI controls and logic for the NVS CSV Editor. This class is instantiated by NvsEditor and contains the UI + * previously held in NvsEditorDialog. + */ +public class NvsCsvEditorPage +{ + private Composite mainControl; + private IFile csvFile; + private Consumer dirtyStateListener; + + private Text statusText; + private Table csvTable; + private TableViewer tableViewer; + + private Text sizeText; + private Composite encryptionComposite; + private Text encryptionKeyText; + private Button generateEncryptionKeyCheckBox; + private Button encryptAction; + private Button generateButton; + private String saveErrorMsg; + + enum GeneratePartitionValidationError + { + SIZE_ERROR, ENCRYPTION_PATH_ERROR; + } + + private final EnumMap validationErrors = new EnumMap<>( + GeneratePartitionValidationError.class); + + private final EnumMap cellEditors = new EnumMap<>(NvsColumn.class); + + private NvsEditorPreferenceService preferenceService; + + public NvsCsvEditorPage(Composite parent, IFile csvFile, Consumer dirtyStateListener) + { + this.csvFile = csvFile; + this.dirtyStateListener = dirtyStateListener; + + mainControl = new Composite(parent, SWT.NONE); + mainControl.setLayout(new GridLayout(1, false)); + + // Initialize the preference service + this.preferenceService = new NvsEditorPreferenceService(csvFile.getProject()); + } + + /** + * Creates the main UI controls for the editor page. + */ + public void createControl() + { + + // Framed Text widget for status messages + statusText = new Text(mainControl, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL); + GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); + gd.heightHint = 60; // Approx 3-4 lines + statusText.setLayoutData(gd); + statusText.setBackground(mainControl.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + + createEncryptionLabel(mainControl); + createSizeOfPartitionLabel(mainControl); + + Group group = new Group(mainControl, SWT.NONE); + group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + group.setLayout(new GridLayout(2, false)); + + createTable(group); + createToolButtonBar(group); + createTableViewer(); + + // Load saved preferences using the new service + loadSettingsToUi(); + + // Initial setup + setMessage(Messages.NvsEditorDialog_DefaultMessage, IMessageProvider.INFORMATION); + encryptAction.notifyListeners(SWT.Selection, new Event()); + validateGenerationState(); // Set initial button state + } + + /** + * Runs all validation checks for the "Generate Partition" action, updates the error map, and sets the button and + * error message status. + */ + private void validateGenerationState() + { + // 1. Start with a clean slate + validationErrors.clear(); + + // 2. Run all individual validation checks + String sizeError = validateSize(); + if (!sizeError.isBlank()) + { + validationErrors.put(GeneratePartitionValidationError.SIZE_ERROR, sizeError); + } + + String encKeyError = validateEncKeyPath(); + if (!encKeyError.isBlank()) + { + validationErrors.put(GeneratePartitionValidationError.ENCRYPTION_PATH_ERROR, encKeyError); + } + + // 3. Update all dependent UI from one single place + setGenerationButtonStatus(); + updateErrorMessage(); + } + + /** + * Sets the status message in the top Text widget. + */ + private void setMessage(String message, int messageType) + { + if (statusText != null && !statusText.isDisposed()) + { + statusText.setText(message != null ? message : ""); //$NON-NLS-1$ + + Display display = statusText.getDisplay(); + Color foreground; + + switch (messageType) + { + case IMessageProvider.ERROR: + foreground = display.getSystemColor(SWT.COLOR_RED); + break; + case IMessageProvider.WARNING: + foreground = display.getSystemColor(SWT.COLOR_DARK_YELLOW); + break; + case IMessageProvider.INFORMATION: + default: + foreground = display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); + break; + } + statusText.setForeground(foreground); + } + } + + /** + * Helper to set an error message or clear it. + */ + private void setErrorMessage(String message) + { + if (message == null) + { + setMessage(Messages.NvsEditorDialog_DefaultMessage, IMessageProvider.INFORMATION); + } + else + { + setMessage(message, IMessageProvider.ERROR); + } + } + + public void setFocus() + { + if (csvTable != null && !csvTable.isDisposed()) + { + csvTable.setFocus(); + } + else if (mainControl != null && !mainControl.isDisposed()) + { + mainControl.setFocus(); + } + } + + /** + * Called by NvsEditor's doSave() to perform the save logic. * @return true if save was successful, false otherwise. + */ + public boolean getSaveAction() + { + boolean isPageValid; + @SuppressWarnings("unchecked") + List beansToSave = (List) tableViewer.getInput(); + isPageValid = validateBeansBeforeSaving(beansToSave); + updateErrorMessage(); + if (!isPageValid) + { + return false; // Save failed validation + } + + new NvsTableDataService().saveCsv(csvFile, beansToSave); + + String baseMessage = Messages.NvsTableEditorDialog_SaveInfoMsg; + String status = statusText.getText(); + + if (status != null && !status.isBlank()) + { + baseMessage = baseMessage + StringUtil.LINE_SEPARATOR + status; + } + + setMessage(baseMessage, IMessageProvider.INFORMATION); + Logger.log(Messages.NvsTableEditorDialog_SaveInfoMsg); + try + { + csvFile.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); + } + catch (CoreException e) + { + Logger.log(e); + } + dirtyStateListener.accept(false); + + // Save preferences using the new service + saveSettingsFromUi(); + return true; + } + + /** + * Notifies the editor that the content is dirty. + */ + public void markDirty() + { + @SuppressWarnings("unchecked") + List beansToSave = (List) tableViewer.getInput(); + validateBeansBeforeSaving(beansToSave); + updateErrorMessage(); + dirtyStateListener.accept(true); + } + + /** + * Updates the status message label based on validation state. + */ + public void updateErrorMessage() + { + String newErrorMessage = StringUtil.EMPTY; + + if (saveErrorMsg == null) + { + saveErrorMsg = StringUtil.EMPTY; + } + + if (saveErrorMsg != null && !saveErrorMsg.isBlank()) + { + newErrorMessage = String.format(Messages.NvsEditorDialog_ComplexSaveErrorMsg, saveErrorMsg); + } + if (!validationErrors.isEmpty()) + { + if (newErrorMessage != null && !newErrorMessage.isBlank()) + newErrorMessage = newErrorMessage.concat(StringUtil.LINE_SEPARATOR).concat(" "); //$NON-NLS-1$ + + List valuesArr = new ArrayList<>(); + for (Entry errorEntry : validationErrors.entrySet()) + { + valuesArr.add(errorEntry.getValue()); + } + newErrorMessage += String.format(Messages.NvsEditorDialog_GenerateButtonComplexErrorMsg, + String.join("; ", valuesArr)); //$NON-NLS-1$ + + } + + setErrorMessage(newErrorMessage); + } + + // ======================================================================== + // UI Creation and Logic Methods (from NvsEditorDialog) + // ======================================================================== + + private void createToolButtonBar(Composite parent) + { + Composite userButtonComp = new Composite(parent, SWT.NONE); + userButtonComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); + userButtonComp.setLayout(new GridLayout()); + + encryptAction = new Button(userButtonComp, SWT.CHECK); + encryptAction.setText(Messages.NvsTableEditorIsEncryptedActionMsg); + encryptAction.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); + encryptAction.addSelectionListener(new SelectionAdapter() + { + + @Override + public void widgetSelected(SelectionEvent e) + { + Stream.of(encryptionComposite.getChildren()).forEach(t -> t.setEnabled(encryptAction.getSelection())); + if (encryptAction.getSelection()) + { + generateEncryptionKeyCheckBox.notifyListeners(SWT.Selection, new Event()); + } + markDirty(); + validateGenerationState(); + } + + }); + + Button addButton = new Button(userButtonComp, SWT.PUSH); + addButton.setText(Messages.NvsTableEditorDialog_AddRowAction); + addButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); + addButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getAddRowAction())); + + Button deleteRowButton = new Button(userButtonComp, SWT.PUSH); + deleteRowButton.setText(Messages.NvsTableEditorDialog_DeleteSelectedAction); + deleteRowButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); + deleteRowButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getDeleteRowAction())); + + Button saveButton = new Button(userButtonComp, SWT.PUSH); + saveButton.setText(Messages.NvsTableEditorDialog_SaveAction); + saveButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); + saveButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getSaveAction())); + + generateButton = new Button(userButtonComp, SWT.PUSH); + generateButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); + generateButton.setText(Messages.NvsTableEditorGeneratePartitionActionMsg); + generateButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getGeneratePartitionAction())); + } + + private void createEncryptionLabel(Composite parent) + { + encryptionComposite = encryptionComposite == null ? new Composite(parent, SWT.NONE) : encryptionComposite; + if (parent.getLayout() instanceof GridLayout) + { + encryptionComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + + encryptionComposite.setLayout(new GridLayout(4, false)); + + generateEncryptionKeyCheckBox = new Button(encryptionComposite, SWT.CHECK); + generateEncryptionKeyCheckBox.setText(Messages.NvsEditorDialog_GenEncKeyCheckBoxTxt); + generateEncryptionKeyCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1)); + + List canBeDisposedList = new ArrayList<>(); + + // --- Column 1: Label --- + Label encyptionKeyLbl = new Label(encryptionComposite, SWT.NONE); + encyptionKeyLbl.setText(Messages.NvsEditorDialog_PathToEncrKeyLbl); + // Don't grab horizontal space + encyptionKeyLbl.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + + // --- Column 2: Text --- + encryptionKeyText = new Text(encryptionComposite, SWT.BORDER); + encryptionKeyText.setMessage(Messages.NvsEditorDialog_PathToKeysTxt); + GridData textData = new GridData(SWT.FILL, SWT.CENTER, true, false); + textData.minimumWidth = IDialogConstants.ENTRY_FIELD_WIDTH; + encryptionKeyText.setLayoutData(textData); + + // --- Column 3: Error Icon Label (Manual) --- + Image image = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR) + .getImage(); + Label errorIconLabel = new Label(encryptionComposite, SWT.NONE); + + errorIconLabel.setImage(image); + errorIconLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + + // --- Column 4: Button --- + Button encyptionKeyBrowseButton = new Button(encryptionComposite, SWT.PUSH); + encyptionKeyBrowseButton.setText(Messages.NvsEditorDialog_EncKeyBrowseTxt); + encyptionKeyBrowseButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + + // --- Listener for Text (controls the icon label) --- + encryptionKeyText.addModifyListener(e -> { + String errMsg = validateEncKeyPath(); + if (errMsg.isBlank()) + { + errorIconLabel.setImage(null); + errorIconLabel.setToolTipText(null); + } + else + { + errorIconLabel.setImage(image); + errorIconLabel.setToolTipText(errMsg); + } + markDirty(); + validateGenerationState(); + }); + + encyptionKeyBrowseButton.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent event) + { + FileDialog dlg = new FileDialog(mainControl.getShell(), SWT.OPEN); + dlg.setFilterPath(csvFile.getProject().getLocation().toString()); + dlg.setFilterExtensions(new String[] { "*.bin", "*" }); //$NON-NLS-1$ //$NON-NLS-2$ + dlg.setText(Messages.NvsEditorDialog_EncrPartitionKeyDlgTxt); + String dir = dlg.open(); + if (dir != null) + { + encryptionKeyText.setText(dir); + encryptionKeyText.getParent().pack(); + } + } + }); + + canBeDisposedList.add(encyptionKeyLbl); + canBeDisposedList.add(encryptionKeyText); + canBeDisposedList.add(errorIconLabel); // Add the icon label to the list + canBeDisposedList.add(encyptionKeyBrowseButton); + + generateEncryptionKeyCheckBox.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + if (generateEncryptionKeyCheckBox.getSelection()) + { + canBeDisposedList.forEach(t -> t.setEnabled(false)); + errorIconLabel.setImage(null); // Hide error when disabled + errorIconLabel.setToolTipText(null); + } + else + { + canBeDisposedList.forEach(t -> t.setEnabled(true)); + encryptionKeyText.notifyListeners(SWT.Modify, new Event()); + } + markDirty(); + validateGenerationState(); + } + }); + } + + private void createSizeOfPartitionLabel(Composite parent) + { + Composite sizeComposite = new Composite(parent, SWT.NONE); + if (parent.getLayout() instanceof GridLayout) + { + sizeComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + sizeComposite.setLayout(new GridLayout(2, false)); + + Label sizeOfPartitionLbl = new Label(sizeComposite, SWT.NONE); + sizeOfPartitionLbl.setText(Messages.NvsTableEditorSizeOfPartitionLblMsg); + sizeOfPartitionLbl.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + sizeText = new Text(sizeComposite, SWT.BORDER); + sizeText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + sizeText.setMessage(Messages.NvsEditorDialog_DefaultSizeMsg); + ControlDecoration deco = new ControlDecoration(sizeText, SWT.RIGHT); + Image image = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR) + .getImage(); + sizeText.addModifyListener(e -> { + String errMsg = validateSize(); + if (errMsg.isBlank()) + { + deco.setImage(null); + deco.setDescriptionText(null); + } + else + { + deco.setImage(image); + deco.setDescriptionText(errMsg); + } + markDirty(); + validateGenerationState(); + }); + + } + + private void createTableViewer() + { + NvsEditorSupportFactory supportFactory; + tableViewer = new TableViewer(csvTable); + tableViewer.setContentProvider(ArrayContentProvider.getInstance()); + ColumnViewerToolTipSupport.enableFor(tableViewer); + + // Use the NvsColumn enum to get column properties + tableViewer.setColumnProperties(NvsColumn.getColumnProperties()); + + // Populate the EnumMap with cell editors + cellEditors.put(NvsColumn.KEY, new TextCellEditor(csvTable)); + cellEditors.put(NvsColumn.TYPE, + new ComboBoxCellEditor(csvTable, NvsTableDataService.getTypes(), SWT.READ_ONLY)); + cellEditors.put(NvsColumn.ENCODING, + new ComboBoxCellEditor(csvTable, NvsTableDataService.getEncodings(StringUtil.EMPTY), SWT.READ_ONLY)); + cellEditors.put(NvsColumn.VALUE, new TextCellEditor(csvTable)); + + // Initialize the factory, passing it the state it needs + supportFactory = new NvsEditorSupportFactory(tableViewer, cellEditors, this::markDirty); + + // Loop through the enum values to create columns + for (NvsColumn column : NvsColumn.values()) + { + TableViewerColumn tvColumn = new TableViewerColumn(tableViewer, SWT.NONE); + tvColumn.getColumn().setText(column.getDisplayName()); + tvColumn.getColumn().setWidth(column.getDefaultWidth()); + + // Use the factory to create the providers + tvColumn.setLabelProvider(supportFactory.createLabelProvider(column)); + tvColumn.setEditingSupport(supportFactory.createEditingSupport(column)); + } + + try + { + List list = new NvsTableDataService().parseCsv(Paths.get(csvFile.getLocationURI())); + tableViewer.setInput(list); + } + catch (IOException e) + { + Logger.log(e); + } + } + + private void createTable(Composite parent) + { + csvTable = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL); + csvTable.setHeaderVisible(true); + csvTable.setLinesVisible(true); + csvTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + ((GridData) csvTable.getLayoutData()).widthHint = 1000; // Keep hint as a minimum + } + + private void getGeneratePartitionAction() + { + validateGenerationState(); + + if (validationErrors.isEmpty()) + { + String infoMsg = NvsPartitionGenerator.generateNvsPartititon(encryptAction.getSelection(), getEncKeyPath(), + sizeText.getText(), csvFile); + + String status = statusText != null ? statusText.getText() : null; + if (status != null && !status.isBlank()) + { + infoMsg = infoMsg + StringUtil.LINE_SEPARATOR + status.trim(); + } + + setMessage(infoMsg, IMessageProvider.INFORMATION); + Logger.log(infoMsg); + } + else + { + Logger.log("NVS Partition Generation failed validation."); //$NON-NLS-1$ + } + + try + { + csvFile.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); + } + catch (CoreException e) + { + Logger.log(e); + } + } + + public void setGenerationButtonStatus() + { + if (generateButton != null) + generateButton.setEnabled(validationErrors.isEmpty()); + } + + private String validateEncKeyPath() + { + String encKeyPath = getEncKeyPath().orElseGet(() -> StringUtil.EMPTY); + + if (encryptAction.getSelection() && !generateEncryptionKeyCheckBox.getSelection() + && !new File(encKeyPath).canRead()) + { + return Messages.NvsEditorDialog_EncKeyCantBeReadErrMsg; + } + + return StringUtil.EMPTY; + } + + private String validateSize() + { + Long decodedSize = 0L; + try + { + decodedSize = Long.decode(sizeText.getText()); + } + catch (NumberFormatException e) + { + return Messages.NvsEditorDialog_SizeValidationDecodedErr + e.getMessage(); + } + if (decodedSize < 4096 || decodedSize % 4096 != 0) + { + return Messages.NvsEditorDialog_WrongSizeFormatErrMsg; + } + return StringUtil.EMPTY; + } + + private Optional getEncKeyPath() + { + if (encryptionKeyText == null || !encryptionKeyText.isEnabled()) + { + return Optional.empty(); + } + + return Optional.of(encryptionKeyText.getText()); + } + + private boolean validateBeansBeforeSaving(List beansToSave) + { + String errorMsg; + if (beansToSave.isEmpty()) + { + saveErrorMsg = Messages.NvsEditorDialog_EmptyTableErrorMsg; + return false; + } + if (!validateFirstBean(beansToSave.get(0))) + { + return false; + } + + for (NvsTableBean bean : beansToSave) + { + // Loop through the enum, passing the type-safe index to the validator. + for (NvsColumn column : NvsColumn.values()) + { + errorMsg = new NvsBeanValidator().validateBean(bean, column.getIndex()); + if (!errorMsg.isBlank()) + { + saveErrorMsg = errorMsg; + return false; + } + } + } + saveErrorMsg = StringUtil.EMPTY; + return true; + } + + private boolean validateFirstBean(NvsTableBean nvsTableBean) + { + String errorMsg = new NvsBeanValidator().validateFirstBean(nvsTableBean); + if (!errorMsg.isBlank()) + { + saveErrorMsg = errorMsg; + return false; + } + return true; + } + + private void getDeleteRowAction() + { + @SuppressWarnings("unchecked") + List beansToSave = (List) tableViewer.getInput(); + NvsTableBean selectedElement = (NvsTableBean) tableViewer.getElementAt(csvTable.getSelectionIndex()); + if (selectedElement == null) + { + return; + } + + if (selectedElement.equals(tableViewer.getElementAt(0))) + { + setMessage(Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg, IMessageProvider.INFORMATION); + return; + } + boolean confirmDelete = MessageDialog.openConfirm(mainControl.getShell(), + Messages.NvsTableEditorDialog_DeleteSelectedAction, Messages.NvsEditorDialog_ConfirmDeleteMsg); + if (!confirmDelete) + { + return; + } + beansToSave.remove(selectedElement); + tableViewer.setInput(beansToSave); + tableViewer.refresh(); + markDirty(); + } + + private void getAddRowAction() + { + @SuppressWarnings("unchecked") + List beansToSave = (List) tableViewer.getInput(); + beansToSave.add(new NvsTableBean()); + tableViewer.setInput(beansToSave); + tableViewer.refresh(); + csvTable.select(csvTable.getItemCount() - 1); + tableViewer.refresh(); + markDirty(); + } + + /** + * Loads settings from the service and applies them to the UI widgets. + */ + private void loadSettingsToUi() + { + NvsEditorSettings settings = preferenceService.loadSettings(); + + sizeText.setText(settings.partitionSize()); + encryptAction.setSelection(settings.encryptEnabled()); + generateEncryptionKeyCheckBox.setSelection(settings.generateKeyEnabled()); + encryptionKeyText.setText(settings.encryptionKeyPath()); + } + + /** + * Reads the current state of the UI widgets and saves it using the service. + */ + private void saveSettingsFromUi() + { + // Read all values from the UI first + String partitionSize = sizeText.getText(); + boolean encryptEnabled = encryptAction.getSelection(); + boolean generateKeyEnabled = generateEncryptionKeyCheckBox.getSelection(); + String encryptionKeyPath = encryptionKeyText.getText(); + + NvsEditorSettings settings = new NvsEditorSettings(partitionSize, encryptEnabled, generateKeyEnabled, + encryptionKeyPath); + + preferenceService.saveSettings(settings); + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditor.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditor.java index 765c20a76..d0eb174ac 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditor.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditor.java @@ -1,55 +1,104 @@ package com.espressif.idf.ui.nvs.dialog; -import org.eclipse.core.commands.ExecutionException; +import java.util.function.Consumer; + +import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.MultiPageEditorPart; - -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.ui.nvs.handlers.NvsEditorHandler; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.ide.ResourceUtil; +import org.eclipse.ui.part.EditorPart; -public class NvsEditor extends MultiPageEditorPart +public class NvsEditor extends EditorPart { - public NvsEditor() - { - PlatformUI.getWorkbench().getDisplay().asyncExec(() -> { - try - { - new NvsEditorHandler().execute(null); - } - catch (ExecutionException e) - { - Logger.log(e); - } - }); + // Unique ID for the editor, used in plugin.xml and the Handler + public static final String ID = "com.espressif.idf.ui.nvs.nvsEditor"; //$NON-NLS-1$ - } + private NvsCsvEditorPage editorPage; + private IFile csvFile; + private boolean isDirty = false; - protected void createPages() + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { - Composite emptyPage = new Composite(getContainer(), SWT.NONE); + // 1. Set Site and Input + setSite(site); + setInput(input); + + // 2. Validate and retrieve the IFile resource + csvFile = ResourceUtil.getFile(input); + if (csvFile == null) + { + throw new PartInitException("Editor input must be a file resource."); //$NON-NLS-1$ + } - int index = addPage(emptyPage); - setPageText(index, "Empty Page"); //$NON-NLS-1$ - getSite().getShell().getDisplay().asyncExec(() -> getSite().getPage().closeEditor(this, false)); + // 3. Set the editor's title + setPartName(csvFile.getName()); + setTitleToolTip(csvFile.getFullPath().toString()); + } + @Override + public void createPartControl(Composite parent) + { + // Pass a callback to the page so it can notify the editor when it becomes dirty. + Consumer dirtyStateListener = this::setDirty; + editorPage = new NvsCsvEditorPage(parent, csvFile, dirtyStateListener); + editorPage.createControl(); // The page creates its UI elements } + @Override public void doSave(IProgressMonitor monitor) { - // Nothing to do + monitor.beginTask("Saving NVS table...", IProgressMonitor.UNKNOWN); //$NON-NLS-1$ + + boolean saveSuccessful = editorPage.getSaveAction(); + if (saveSuccessful) + { + setDirty(false); // Only clear dirty state if save was successful + } + + monitor.done(); } + @Override public void doSaveAs() { // Nothing to do } + @Override public boolean isSaveAsAllowed() { return false; } + @Override + public boolean isDirty() + { + return isDirty; + } + + private void setDirty(boolean dirty) + { + if (this.isDirty != dirty) + { + this.isDirty = dirty; + firePropertyChange(PROP_DIRTY); + if (editorPage != null) + { + editorPage.updateErrorMessage(); + } + } + } + + @Override + public void setFocus() + { + if (editorPage != null) + { + editorPage.setFocus(); + } + } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorDialog.java index ee52a8dba..7b459aff2 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorDialog.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorDialog.java @@ -91,7 +91,7 @@ enum GeneratePartitionValidationError private enum ErrorListenerMap { INSTANCE; - + private EnumMap validationErrors = new EnumMap<>( GeneratePartitionValidationError.class); private NvsEditorDialog dialog; @@ -116,8 +116,6 @@ public void remove(GeneratePartitionValidationError key) } } - - public NvsEditorDialog(Shell parentShell) { super(parentShell); @@ -168,7 +166,7 @@ private void createToolButtonBar(Composite parent) encryptAction.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); encryptAction.addSelectionListener(new SelectionAdapter() { - + @Override public void widgetSelected(SelectionEvent e) { @@ -193,8 +191,7 @@ public void widgetSelected(SelectionEvent e) Button deleteRowButton = new Button(userButtonComp, SWT.PUSH); deleteRowButton.setText(Messages.NvsTableEditorDialog_DeleteSelectedAction); deleteRowButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); - deleteRowButton - .addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getDeleteRowAction())); + deleteRowButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getDeleteRowAction())); Button saveButton = new Button(userButtonComp, SWT.PUSH); saveButton.setText(Messages.NvsTableEditorDialog_SaveAction); @@ -204,8 +201,7 @@ public void widgetSelected(SelectionEvent e) generateButton = new Button(userButtonComp, SWT.PUSH); generateButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false)); generateButton.setText(Messages.NvsTableEditorGeneratePartitionActionMsg); - generateButton.addSelectionListener( - SelectionListener.widgetSelectedAdapter(t -> getGeneratePartitionAction())); + generateButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(t -> getGeneratePartitionAction())); encryptAction.notifyListeners(SWT.Selection, null); generateButton.setEnabled(false); setErrorMessage(null); @@ -291,7 +287,6 @@ private void createSizeOfPartitionLable(Composite parent) Composite sizeComposite = new Composite(parent, SWT.NONE); sizeComposite.setLayout(new GridLayout(2, false)); - Label sizeOfPartitionLbl = new Label(sizeComposite, SWT.NONE); sizeOfPartitionLbl.setText(Messages.NvsTableEditorSizeOfPartitionLblMsg); sizeOfPartitionLbl.setLayoutData(new GridData(GridData.FILL_BOTH)); @@ -324,7 +319,7 @@ private void createTableViewer() List list = (List) input; return list.toArray(); }); - + try { List list = new NvsTableDataService().parseCsv(Paths.get(csvFile.getLocationURI())); @@ -335,7 +330,7 @@ private void createTableViewer() { Logger.log(e); } - tableViewer.setLabelProvider(new NvsTableEditorLabelProvider()); + // tableViewer.setLabelProvider(new NvsTableEditorLabelProvider()); // Set cell editors tableViewer.setColumnProperties(columnNames); @@ -385,8 +380,7 @@ public void modify(Object element, String property, Object value) break; } bean.setType(newType); - ((ComboBoxCellEditor) cellEditors[2]) - .setItems(NvsTableDataService.getEncodings(bean.getType())); + ((ComboBoxCellEditor) cellEditors[2]).setItems(NvsTableDataService.getEncodings(bean.getType())); tableViewer.getCellModifier().modify(element, columnNames[2], 0); break; case 2: @@ -455,7 +449,7 @@ public boolean canModify(Object element, String property) if (tableViewer.getElementAt(0).equals(element)) { if (!property.contentEquals(columnNames[0])) - setMessage(Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg, IMessageProvider.INFORMATION); + setMessage(Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg, IMessageProvider.INFORMATION); return property.contentEquals(columnNames[0]); } NvsTableBean bean = (NvsTableBean) element; @@ -467,7 +461,6 @@ public boolean canModify(Object element, String property) } }); - } private void createColumns() @@ -575,7 +568,6 @@ private String validateEncKeyPath() return StringUtil.EMPTY; } - private String validateSize() { Long decodedSize = 0l; @@ -687,8 +679,7 @@ private void getDeleteRowAction() if (selectedElement.equals(tableViewer.getElementAt(0))) { - setMessage(Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg, - IMessageProvider.INFORMATION); + setMessage(Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg, IMessageProvider.INFORMATION); return; } boolean confirmDelete = MessageDialog.openConfirm(getShell(), @@ -712,7 +703,7 @@ private void getAddRowAction() csvTable.select(csvTable.getItemCount() - 1); tableViewer.refresh(); } - + @Override protected void createButtonsForButtonBar(Composite parent) { diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorPreferenceService.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorPreferenceService.java new file mode 100644 index 000000000..40cf53f8b --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorPreferenceService.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ + +package com.espressif.idf.ui.nvs.dialog; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ProjectScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.osgi.service.prefs.BackingStoreException; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.util.StringUtil; + +/** + * Manages loading and saving NvsEditorSettings to and from the Eclipse preference store for a specific project. + */ +public class NvsEditorPreferenceService +{ + private static final String PLUGIN_ID = "com.espressif.idf.core"; //$NON-NLS-1$ + private static final String PREF_PARTITION_SIZE = "nvsPartitionSize"; //$NON-NLS-1$ + private static final String PREF_ENCRYPT_ENABLED = "nvsEncryptEnabled"; //$NON-NLS-1$ + private static final String PREF_GENERATE_KEY_ENABLED = "nvsGenerateKeyEnabled"; //$NON-NLS-1$ + private static final String PREF_ENCRYPTION_KEY_PATH = "nvsEncryptionKeyPath"; //$NON-NLS-1$ + + private IEclipsePreferences preferences; + + public NvsEditorPreferenceService(IProject project) + { + IScopeContext projectScope = new ProjectScope(project); + this.preferences = projectScope.getNode(PLUGIN_ID); + } + + /** + * Loads settings from the service and applies them to the UI. + */ + public NvsEditorSettings loadSettings() + { + // Read all values from the preference store first + String partitionSize = preferences.get(PREF_PARTITION_SIZE, NvsEditorSettings.DEFAULT_PARTITION_SIZE); + boolean encryptEnabled = preferences.getBoolean(PREF_ENCRYPT_ENABLED, false); + boolean generateKeyEnabled = preferences.getBoolean(PREF_GENERATE_KEY_ENABLED, true); + String encryptionKeyPath = preferences.get(PREF_ENCRYPTION_KEY_PATH, StringUtil.EMPTY); + + // Create the immutable record in one call + return new NvsEditorSettings(partitionSize, encryptEnabled, generateKeyEnabled, encryptionKeyPath); + } + + /** + * Saves the given settings to the project's preferences. + */ + public void saveSettings(NvsEditorSettings settings) + { + preferences.put(PREF_PARTITION_SIZE, settings.partitionSize()); + preferences.putBoolean(PREF_ENCRYPT_ENABLED, settings.encryptEnabled()); + preferences.putBoolean(PREF_GENERATE_KEY_ENABLED, settings.generateKeyEnabled()); + preferences.put(PREF_ENCRYPTION_KEY_PATH, settings.encryptionKeyPath()); + + try + { + preferences.flush(); + } + catch (BackingStoreException e) + { + Logger.log(e); + } + } +} \ No newline at end of file diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSettings.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSettings.java new file mode 100644 index 000000000..8ca88aea2 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSettings.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ + +package com.espressif.idf.ui.nvs.dialog; + +import com.espressif.idf.core.util.StringUtil; + +/** + * A Data Transfer Object (DTO) that holds the settings for the NVS Editor page, implemented as an immutable Java + * Record. + */ +public record NvsEditorSettings(String partitionSize, boolean encryptEnabled, boolean generateKeyEnabled, + String encryptionKeyPath) +{ + + public static final String DEFAULT_PARTITION_SIZE = "0x3000"; //$NON-NLS-1$ + + /** + * Creates a new instance with default values. + */ + public static NvsEditorSettings createDefault() + { + return new NvsEditorSettings(DEFAULT_PARTITION_SIZE, false, true, StringUtil.EMPTY); + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSupportFactory.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSupportFactory.java new file mode 100644 index 000000000..bd5979eea --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsEditorSupportFactory.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ + +package com.espressif.idf.ui.nvs.dialog; + +import java.util.Map; + +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ComboBoxCellEditor; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; + +import com.espressif.idf.core.build.NvsTableBean; +import com.espressif.idf.core.util.NvsTableDataService; +import com.espressif.idf.core.util.StringUtil; + +/** + * Factory class responsible for creating LabelProviders and EditingSupport for the NvsCsvEditorPage's TableViewer. + */ +public class NvsEditorSupportFactory +{ + private TableViewer tableViewer; + private Map cellEditors; + private Runnable markDirtyRunnable; + + /** + * Constructor that takes the state from the NvsCsvEditorPage. + */ + public NvsEditorSupportFactory(TableViewer tableViewer, Map cellEditors, + Runnable markDirtyRunnable) + { + this.tableViewer = tableViewer; + this.cellEditors = cellEditors; + this.markDirtyRunnable = markDirtyRunnable; + } + + /** + * Factory method to create the correct LabelProvider for a given column. + */ + public NvsTableEditorLabelProvider createLabelProvider(NvsColumn column) + { + return new NvsTableEditorLabelProvider() + { + @Override + public int getColumnIndex() + { + return column.getIndex(); + } + + @Override + public String getColumnText(NvsTableBean bean) + { + switch (column) + { + case KEY: + return bean.getKey(); + case TYPE: + return bean.getType(); + case ENCODING: + return bean.getEncoding(); + case VALUE: + return bean.getValue(); + default: + return StringUtil.EMPTY; + } + } + + @Override + public String getToolTipText(Object element) + { + if (tableViewer.getElementAt(0).equals(element)) + { + return Messages.NvsEditorDialog_FirstRowIsFixedInfoMsg; + } + return super.getToolTipText(element); + } + + @Override + public Color getBackground(Object element) + { + if (column != NvsColumn.KEY && tableViewer.getElementAt(0).equals(element)) + { + return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); + } + return null; + } + }; + } + + /** + * Factory method to create the correct EditingSupport for a given column. + */ + public EditingSupport createEditingSupport(NvsColumn column) + { + switch (column) + { + case KEY: + return new NvsKeyEditingSupport(); + case TYPE: + return new NvsTypeEditingSupport(); + case ENCODING: + return new NvsEncodingEditingSupport(); + case VALUE: + return new NvsValueEditingSupport(); + default: + return null; + } + } + + private abstract class BaseNvsEditingSupport extends EditingSupport + { + public BaseNvsEditingSupport() + { + super(NvsEditorSupportFactory.this.tableViewer); + } + + @Override + protected boolean canEdit(Object element) + { + return !tableViewer.getElementAt(0).equals(element); + } + } + + private class NvsKeyEditingSupport extends EditingSupport + { + public NvsKeyEditingSupport() + { + super(NvsEditorSupportFactory.this.tableViewer); + } + + @Override + protected CellEditor getCellEditor(Object element) + { + return cellEditors.get(NvsColumn.KEY); + } + + @Override + protected boolean canEdit(Object element) + { + return true; + } + + @Override + protected Object getValue(Object element) + { + return ((NvsTableBean) element).getKey(); + } + + @Override + protected void setValue(Object element, Object value) + { + ((NvsTableBean) element).setKey((String) value); + tableViewer.update(element, null); + markDirtyRunnable.run(); + } + } + + private class NvsTypeEditingSupport extends BaseNvsEditingSupport + { + @Override + protected CellEditor getCellEditor(Object element) + { + return cellEditors.get(NvsColumn.TYPE); + } + + @Override + protected Object getValue(Object element) + { + String stringValue = ((NvsTableBean) element).getType(); + String[] choices = NvsTableDataService.getTypes(); + for (int i = 0; i < choices.length; i++) + { + if (stringValue.equals(choices[i])) + return i; + } + return 0; + } + + @Override + protected void setValue(Object element, Object value) + { + NvsTableBean bean = (NvsTableBean) element; + String newType = NvsTableDataService.getTypes()[(int) value]; + if (newType.contentEquals(bean.getType())) + { + return; + } + bean.setType(newType); + + String[] encodings = NvsTableDataService.getEncodings(bean.getType()); + ((ComboBoxCellEditor) cellEditors.get(NvsColumn.ENCODING)).setItems(encodings); + if (encodings.length > 0) + { + bean.setEncoding(encodings[0]); + } + + tableViewer.update(element, + new String[] { NvsColumn.TYPE.getDisplayName(), NvsColumn.ENCODING.getDisplayName() }); + markDirtyRunnable.run(); + } + } + + private class NvsEncodingEditingSupport extends BaseNvsEditingSupport + { + @Override + protected CellEditor getCellEditor(Object element) + { + NvsTableBean bean = (NvsTableBean) element; + ((ComboBoxCellEditor) cellEditors.get(NvsColumn.ENCODING)) + .setItems(NvsTableDataService.getEncodings(bean.getType())); + return cellEditors.get(NvsColumn.ENCODING); + } + + @Override + protected Object getValue(Object element) + { + NvsTableBean bean = (NvsTableBean) element; + String stringValue = bean.getEncoding(); + String[] choices = NvsTableDataService.getEncodings(bean.getType()); + for (int i = 0; i < choices.length; i++) + { + if (stringValue.equals(choices[i])) + return i; + } + return 0; + } + + @Override + protected void setValue(Object element, Object value) + { + NvsTableBean bean = (NvsTableBean) element; + String[] encodings = NvsTableDataService.getEncodings(bean.getType()); + if (encodings.length > (int) value) + { + bean.setEncoding(encodings[(int) value]); + } + tableViewer.update(element, null); + markDirtyRunnable.run(); + } + } + + private class NvsValueEditingSupport extends BaseNvsEditingSupport + { + @Override + protected CellEditor getCellEditor(Object element) + { + return cellEditors.get(NvsColumn.VALUE); + } + + @Override + protected Object getValue(Object element) + { + return ((NvsTableBean) element).getValue(); + } + + @Override + protected void setValue(Object element, Object value) + { + ((NvsTableBean) element).setValue((String) value); + tableViewer.update(element, null); + markDirtyRunnable.run(); + } + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsTableEditorLabelProvider.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsTableEditorLabelProvider.java index d45f4a81a..afe661a57 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsTableEditorLabelProvider.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/dialog/NvsTableEditorLabelProvider.java @@ -1,79 +1,67 @@ -/******************************************************************************* - * Copyright 2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ - package com.espressif.idf.ui.nvs.dialog; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.ITableColorProvider; -import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import com.espressif.idf.core.build.NvsTableBean; import com.espressif.idf.core.util.NvsBeanValidator; -public class NvsTableEditorLabelProvider extends CellLabelProvider implements ITableLabelProvider, ITableColorProvider +public abstract class NvsTableEditorLabelProvider extends ColumnLabelProvider { - @Override - public Color getForeground(Object element, int columnIndex) - { - String status = new NvsBeanValidator().validateBean((NvsTableBean) element, columnIndex); - if (!status.isBlank()) - { - return Display.getCurrent().getSystemColor(SWT.COLOR_RED); - } + protected NvsBeanValidator validator = new NvsBeanValidator(); - return null; - } + /** + * Subclasses must tell the provider which column index they are for (0, 1, 2, or 3). + */ + public abstract int getColumnIndex(); - @Override - public Color getBackground(Object element, int columnIndex) - { - return null; - } + /** + * Subclasses must provide the text for their specific column. + */ + public abstract String getColumnText(NvsTableBean bean); @Override - public Image getColumnImage(Object element, int columnIndex) + public void update(ViewerCell cell) { - String status = new NvsBeanValidator().validateBean((NvsTableBean) element, columnIndex); - if (!status.isBlank()) + NvsTableBean bean = (NvsTableBean) cell.getElement(); + + // 1. Set text (delegated to subclass) + cell.setText(getColumnText(bean)); + + // 2. Set color/image (uses column index from subclass) + String cellStatus = validator.validateBean(bean, getColumnIndex()); + if (!cellStatus.isBlank()) { - return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR); + cell.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); + cell.setImage(JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR)); } - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) - { - NvsTableBean bean = (NvsTableBean) element; - switch (columnIndex) + else { - case 0: - return bean.getKey(); - case 1: - return bean.getType(); - case 2: - return bean.getEncoding(); - case 3: - return bean.getValue(); - default: - break; + cell.setForeground(null); + cell.setImage(null); } - return null; + + cell.setBackground(getBackground(bean)); } + /** + * This method is called by ColumnViewerToolTipSupport *only* when the mouse is over this provider's column. It + * provides the tooltip for ONLY this cell. + */ @Override - public void update(ViewerCell cell) + public String getToolTipText(Object element) { - } + NvsTableBean bean = (NvsTableBean) element; -} + // 1. Get validation status for this specific cell + String status = validator.validateBean(bean, getColumnIndex()); + + // 2. Return the validation message or null (no tooltip) + return status.isBlank() ? null : status; + } +} \ No newline at end of file diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/handlers/NvsEditorHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/handlers/NvsEditorHandler.java index c911c1593..51b8741af 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/handlers/NvsEditorHandler.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/nvs/handlers/NvsEditorHandler.java @@ -7,11 +7,15 @@ import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; -import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.FileEditorInput; +import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.util.NvsTableDataService; import com.espressif.idf.ui.EclipseUtil; -import com.espressif.idf.ui.nvs.dialog.NvsEditorDialog; +import com.espressif.idf.ui.nvs.dialog.NvsEditor; public class NvsEditorHandler extends AbstractHandler { @@ -20,18 +24,33 @@ public class NvsEditorHandler extends AbstractHandler @Override public Object execute(ExecutionEvent event) throws ExecutionException { - IProject selectedProject = EclipseUtil.getSelectedProjectInExplorer(); IFile csvFile = selectedProject.getFile(NVS_CSV_NAME); if (!csvFile.exists()) { + // Ensure the file exists before opening the editor new NvsTableDataService().saveCsv(csvFile, new ArrayList<>()); } - NvsEditorDialog dialog = new NvsEditorDialog(Display.getDefault().getActiveShell()); - dialog.setCsvFile(csvFile); - dialog.open(); + + var window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window != null) + { + IWorkbenchPage page = window.getActivePage(); + if (page != null) + { + try + { + FileEditorInput input = new FileEditorInput(csvFile); + page.openEditor(input, NvsEditor.ID); + } + catch (PartInitException e) + { + Logger.log(e); + } + } + } + return null; } - } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java index 5913e4335..672424e22 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/preferences/EspresssifPreferencesPage.java @@ -3,15 +3,12 @@ import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -22,7 +19,6 @@ import com.espressif.idf.core.IDFCorePlugin; import com.espressif.idf.core.IDFCorePreferenceConstants; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.StringUtil; public class EspresssifPreferencesPage extends PreferencePage implements IWorkbenchPreferencePage { @@ -42,7 +38,6 @@ public class EspresssifPreferencesPage extends PreferencePage implements IWorkbe private Combo gitAssetsCombo; private Combo pythonWheelCombo; - private Text idfToolsPathText; private Button automateClangdFormatCreationBtn; public EspresssifPreferencesPage() @@ -80,8 +75,6 @@ protected Control createContents(Composite parent) addBuildSettings(mainComposite); - addToolsInstallationSettings(mainComposite); - addClangdSettings(mainComposite); return mainComposite; } @@ -100,73 +93,6 @@ private void addClangdSettings(Composite mainComposite) .setSelection(getPreferenceStore().getBoolean(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE)); } - private void addToolsInstallationSettings(Composite mainComposite) - { - Group toolsInstallationGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_IN); - toolsInstallationGroup.setText(Messages.EspressifPreferencesPage_ToolsInstallationGrpTxt); - toolsInstallationGroup.setLayout(new GridLayout(3, false)); - - Label githubAssetsLabel = new Label(toolsInstallationGroup, SWT.NONE); - githubAssetsLabel.setText(Messages.EspressifPreferencesPage_ToolsInstallationGitAssetUrlLabel); - gitAssetsCombo = new Combo(toolsInstallationGroup, SWT.DROP_DOWN | SWT.BORDER); - gitAssetsCombo.setItems(IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_GLOBAL, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_CHINA); - gitAssetsCombo.select(0); - - Label pythonWheelsLabel = new Label(toolsInstallationGroup, SWT.NONE); - pythonWheelsLabel.setText(Messages.EspressifPreferencesPage_ToolsInstallationPythonPyWheelUrlLabel); - pythonWheelCombo = new Combo(toolsInstallationGroup, SWT.DROP_DOWN | SWT.BORDER); - pythonWheelCombo.setItems(IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_CHINA); - pythonWheelCombo.select(0); - - GridData gitTextGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1); - gitTextGridData.widthHint = 200; - GridData pythonTextGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1); - pythonTextGridData.widthHint = 200; - gitAssetsCombo.setLayoutData(gitTextGridData); - pythonWheelCombo.setLayoutData(pythonTextGridData); - - Label idfToolsPathLabel = new Label(toolsInstallationGroup, SWT.NONE); - idfToolsPathLabel.setText(Messages.EspressifPreferencesPage_EspIdfToolsInstallationDirectoryLabel); - idfToolsPathText = new Text(toolsInstallationGroup, SWT.SINGLE | SWT.NONE); - GridData idfToolsPathTextGridData = new GridData(SWT.FILL, SWT.CENTER, true, false); - idfToolsPathTextGridData.widthHint = 200; - idfToolsPathText.setLayoutData(idfToolsPathTextGridData); - // Add browse button - Button browseButtonIdfToolsPath = new Button(toolsInstallationGroup, SWT.PUSH); - browseButtonIdfToolsPath.setText(Messages.EspressifPreferencesPage_DirectorySelectionIDFToolsPathBrowseButton); - browseButtonIdfToolsPath.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - DirectoryDialog dialog = new DirectoryDialog(mainComposite.getShell()); - dialog.setText(Messages.EspressifPreferencesPage_DirectorySelectionIDFToolsPathTitle); - dialog.setMessage(Messages.EspressifPreferencesPage_DirectorySelectionIDFToolsPathMessage); - String dir = dialog.open(); - if (dir != null) - { - idfToolsPathText.setText(dir); - } - } - }); - - String idfToolsPath = getPreferenceStore().getString(IDFCorePreferenceConstants.IDF_TOOLS_PATH); - idfToolsPath = StringUtil.isEmpty(idfToolsPath) - ? getPreferenceStore().getDefaultString(IDFCorePreferenceConstants.IDF_TOOLS_PATH) - : idfToolsPath; - idfToolsPathText.setText(idfToolsPath); - - String gitUrl = getPreferenceStore().getString(IDFCorePreferenceConstants.IDF_GITHUB_ASSETS); - String pyWheelUrl = getPreferenceStore().getString(IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL); - gitUrl = StringUtil.isEmpty(gitUrl) ? gitAssetsCombo.getItem(0) : gitUrl; - pyWheelUrl = StringUtil.isEmpty(pyWheelUrl) ? pythonWheelCombo.getItem(0) : pyWheelUrl; - - gitAssetsCombo.setText(gitUrl); - pythonWheelCombo.setText(pyWheelUrl); - } - private void addBuildSettings(Composite mainComposite) { Group buildGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_IN); @@ -267,12 +193,6 @@ public boolean performOk() IDFCorePlugin.ERROR_MARKER_LISTENER.initialMarkerCleanup(); } - getPreferenceStore().setValue(IDFCorePreferenceConstants.IDF_GITHUB_ASSETS, gitAssetsCombo.getText()); - - getPreferenceStore().setValue(IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL, pythonWheelCombo.getText()); - - getPreferenceStore().setValue(IDFCorePreferenceConstants.IDF_TOOLS_PATH, idfToolsPathText.getText()); - getPreferenceStore().setValue(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE, automateClangdFormatCreationBtn.getSelection()); } @@ -300,7 +220,6 @@ protected void performDefaults() .setSelection(getPreferenceStore().getBoolean(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE)); gitAssetsCombo.setText(gitAssetsCombo.getItem(0)); pythonWheelCombo.setText(pythonWheelCombo.getItem(0)); - idfToolsPathText.setText(getPreferenceStore().getDefaultString(IDFCorePreferenceConstants.IDF_TOOLS_PATH)); } private void initializeDefaults() @@ -314,13 +233,6 @@ private void initializeDefaults() IDFCorePreferenceConstants.AUTOMATE_BUILD_HINTS_DEFAULT_STATUS); getPreferenceStore().setDefault(IDFCorePreferenceConstants.HIDE_ERRORS_IDF_COMPONENTS, IDFCorePreferenceConstants.HIDE_ERRORS_IDF_COMPONENTS_DEFAULT_STATUS); - - getPreferenceStore().setDefault(IDFCorePreferenceConstants.IDF_GITHUB_ASSETS, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_GLOBAL); - getPreferenceStore().setDefault(IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL); - getPreferenceStore().setDefault(IDFCorePreferenceConstants.IDF_TOOLS_PATH, - IDFCorePreferenceConstants.IDF_TOOLS_PATH_DEFAULT); getPreferenceStore().setDefault(IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE, IDFCorePreferenceConstants.AUTOMATE_CLANGD_FORMAT_FILE_DEFAULT); } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeAnalysisEditor.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeAnalysisEditor.java index 4d2d83683..f8d04ce89 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeAnalysisEditor.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeAnalysisEditor.java @@ -76,6 +76,11 @@ private boolean verifyVersion() return false; } + if (idfVersion.equalsIgnoreCase("master")) //$NON-NLS-1$ + { + return true; + } + if (idfVersion.toLowerCase().startsWith("v")) //$NON-NLS-1$ { idfVersion = idfVersion.substring(1); diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeDataManager.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeDataManager.java index 7acb68185..3a6a4aeb4 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeDataManager.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/size/IDFSizeDataManager.java @@ -205,7 +205,7 @@ protected IStatus runProcess(IFile file, List arguments) throws Exceptio ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); try { - return processRunner.runInBackground(arguments, Path.ROOT, IDFUtil.getSystemEnv()); + return processRunner.runInBackground(arguments, Path.ROOT, System.getenv()); } catch (Exception e1) { @@ -247,6 +247,11 @@ private List addJsonParseCommand() public boolean isVersionAtLeast(String currentIDFVersion, String minimumIDFVersion) { + if (currentIDFVersion.equalsIgnoreCase("master")) //$NON-NLS-1$ + { + return true; + } + Version currentVersion = Version.parse(currentIDFVersion); Version minVersion = Version.parse(minimumIDFVersion); return currentVersion.compareTo(minVersion) >= 0; diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java new file mode 100644 index 000000000..eb2eafef5 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui.tools; + +import java.io.IOException; +import java.nio.file.Paths; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.console.MessageConsoleStream; +import org.eclipse.ui.ide.IDE; +import org.osgi.service.prefs.Preferences; + +import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.DownloadListener; +import com.espressif.idf.core.tools.EimIdfConfiguratinParser; +import com.espressif.idf.core.tools.EimLoader; +import com.espressif.idf.core.tools.ToolInitializer; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.ui.UIPlugin; +import com.espressif.idf.ui.handlers.EclipseHandler; +import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; +import com.espressif.idf.ui.tools.manager.EimEditorInput; +import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; + +/** + * This is a class that other UI elements can also use to trigger + * a simulated event on any widget to launch or download the EIM. + * The primary usage is in {@link ESPIDFMainTablePage} + * @author Ali Azam Rana + * + */ +public class EimButtonLaunchListener extends SelectionAdapter +{ + private ESPIDFMainTablePage espidfMainTablePage; + private Display display; + private Preferences preferences; + private ToolInitializer toolInitializer; + private IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + private MessageConsoleStream standardConsoleStream; + private MessageConsoleStream errorConsoleStream; + private EimLoader eimLoader; + + public EimButtonLaunchListener(ESPIDFMainTablePage espidfMainTablePage, Display display, + MessageConsoleStream standardConsoleStream, MessageConsoleStream errorConsoleStream) + { + this.espidfMainTablePage = espidfMainTablePage; + this.display = display; + this.standardConsoleStream = standardConsoleStream; + this.errorConsoleStream = errorConsoleStream; + preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); + toolInitializer = new ToolInitializer(preferences); + eimLoader = new EimLoader(new EimDownlaodListener(), standardConsoleStream, errorConsoleStream, display); + } + + @Override + public void widgetSelected(SelectionEvent selectionEvent) + { + if (!toolInitializer.isEimInstalled()) + { + Job downloadJob = new Job("Download and Launch EIM") + { + + @Override + protected IStatus run(IProgressMonitor monitor) + { + eimLoader.downloadEim(monitor); + return Status.OK_STATUS; + } + }; + downloadJob.setUser(true); + downloadJob.schedule(); + } + else + { + try + { + Process process = eimLoader.launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); + eimLoader.waitForEimClosure(process, EimButtonLaunchListener.this::refreshAfterEimClose); + } + catch (IOException e) + { + Logger.log(e); + } + } + } + + private void refreshAfterEimClose() + { + display.asyncExec(() -> { + try + { + launchEspIdfManager(); + standardConsoleStream.write("Refreshing UI after EIM closed...\n"); + espidfMainTablePage.refreshEditorUI(); + espidfMainTablePage.setupInitialEspIdf(); + } + catch (IOException | PartInitException e) + { + Logger.log(e); + } + }); + } + + private void launchEspIdfManager() throws PartInitException + { + Display.getDefault().asyncExec(() -> { + IWorkbenchWindow activeww = EclipseHandler.getActiveWorkbenchWindow(); + if (activeww == null || activeww.getActivePage() == null) + { + Logger.log("Cannot open ESP-IDF Manager. No active workbench window or active page."); + return; + } + + try + { + EimIdfConfiguratinParser eimIdfConfiguratinParser = new EimIdfConfiguratinParser(); + EimJson eimJson = eimIdfConfiguratinParser.getEimJson(true); + IDE.openEditor(activeww.getActivePage(), new EimEditorInput(eimJson), ESPIDFManagerEditor.EDITOR_ID, + true); + } + catch (PartInitException| EimVersionMismatchException | IOException e) + { + Logger.log("Failed to open ESP-IDF Manager Editor."); + Logger.log(e); + if (e instanceof EimVersionMismatchException) + { + EimVersionMismatchException eimEx = (EimVersionMismatchException) e; + MessageDialog.openError(Display.getDefault().getActiveShell(), eimEx.msgTitle(), eimEx.getMessage()); + } + } + }); + + } + + private class EimDownlaodListener implements DownloadListener + { + @Override + public void onProgress(int percent) + { + display.asyncExec(() -> { + try + { + int blocks = percent / 10; + String bar = "[" + "#".repeat(blocks) + " ".repeat(10 - blocks) + "] " + percent + "%"; + standardConsoleStream.write("\r" + bar); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + + @Override + public void onCompleted(String filePath) + { + display.syncExec(() -> { + try + { + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + String appToLaunch = filePath; + + if (filePath.endsWith(".dmg")) + { + try + { + appToLaunch = eimLoader.installAndLaunchDmg(Paths.get(filePath)); + } + catch ( + IOException + | InterruptedException e) + { + Logger.log(e); + } + } + + Process process; + try + { + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, appToLaunch); + process = eimLoader.launchEim(appToLaunch); + eimLoader.waitForEimClosure(process, EimButtonLaunchListener.this::refreshAfterEimClose); + } + catch (IOException e) + { + Logger.log(e); + } + } + + @Override + public void onError(String message, Exception e) + { + display.asyncExec(() -> { + try + { + errorConsoleStream.write("Download Failed: " + e.getMessage()); + } + catch (IOException e1) + { + Logger.log(e1); + } + }); + } + + } + +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java new file mode 100644 index 000000000..5f53a295a --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EspressifToolStartup.java @@ -0,0 +1,433 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui.tools; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IStartup; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.console.MessageConsoleStream; +import org.eclipse.ui.ide.IDE; +import org.osgi.service.prefs.Preferences; + +import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.build.Messages; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.DownloadListener; +import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.EimLoader; +import com.espressif.idf.core.tools.ToolInitializer; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.core.tools.watcher.EimJsonWatchService; +import com.espressif.idf.core.util.IDFUtil; +import com.espressif.idf.core.util.StringUtil; +import com.espressif.idf.ui.GlobalModalLock; +import com.espressif.idf.ui.IDFConsole; +import com.espressif.idf.ui.UIPlugin; +import com.espressif.idf.ui.handlers.EclipseHandler; +import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; +import com.espressif.idf.ui.tools.manager.EimEditorInput; +import com.espressif.idf.ui.tools.watcher.EimJsonUiChangeHandler; + +/** + * Startup class to handle the tools + * + * @author Ali Azam Rana + * + */ +public class EspressifToolStartup implements IStartup +{ + private EimJsonUiChangeHandler eimJsonUiChangeHandler; + private ToolInitializer toolInitializer; + private Preferences preferences; + private EimJson eimJson; + private EimLoader eimLoader; + private MessageConsoleStream standardConsoleStream; + private MessageConsoleStream errorConsoleStream; + private IDFEnvironmentVariables idfEnvironmentVariables; + + @Override + public void earlyStartup() + { + preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); + toolInitializer = new ToolInitializer(preferences); + standardConsoleStream = getConsoleStream(false); + errorConsoleStream = getConsoleStream(true); + idfEnvironmentVariables = new IDFEnvironmentVariables(); + eimLoader = new EimLoader(new StartupClassDownloadEimDownloadListener(), standardConsoleStream, + errorConsoleStream, Display.getDefault()); + eimJsonUiChangeHandler = new EimJsonUiChangeHandler(preferences); + EimJsonWatchService.getInstance().addEimJsonChangeListener(eimJsonUiChangeHandler); + + if (!toolInitializer.isEimInstalled() && !toolInitializer.isEimIdfJsonPresent()) + { + Logger.log("EIM not installed"); + notifyMissingTools(); + return; + } + + try + { + eimJson = toolInitializer.loadEimJson(); + } + catch (EimVersionMismatchException e) + { + Logger.log(e); + return; + } + + if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) + { + Logger.log("Old configuration found and not converted"); + closeEspIdfManager(); + boolean isEimInApplications = checkIfEimPathMacOsIsInApplications(); + if (!isEimInApplications) + { + promptUserToMoveEimToApplications(); + } + + EimJsonWatchService.withPausedListeners(() -> handleOldConfigExport()); + } + else if (toolInitializer.isEimIdfJsonPresent() && !toolInitializer.isEspIdfSet()) + { + promptUserToOpenToolManager(eimJson); + } + + // Set EimPath on every startup to ensure proper path in configurations + if (eimJson != null) + { + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); + } + else + { + // Fail-safe call to ensure if the eim is in Applications or user.home it is setup in env vars + toolInitializer.findAndSetEimPath(); + } + + } + + private boolean checkIfEimPathMacOsIsInApplications() + { + if (!Platform.getOS().equals(Platform.OS_MACOSX)) + return true; + + String eimPath = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH); + if (!StringUtil.isEmpty(eimPath)) + { + if (Files.exists(Paths.get(eimPath))) + { + boolean isInApplications = eimPath.startsWith("/Applications/") + || eimPath.startsWith(System.getProperty("user.home") + "/Applications/"); + if (!isInApplications) + { + Logger.log("EIM_PATH not in applications: " + eimPath); + return false; + } + } + } + + return true; + } + + private void handleOldConfigExport() + { + Display display = Display.getDefault(); + display.asyncExec(()-> { + startExportOldConfig(); + }); + } + + private void startExportOldConfig() + { + try + { + // if eim json is present it means that it contains the updated path and we use that else we fallback to + // finding eim in default paths + Path eimPath; + String eimPathEnvVar = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH); + if (eimJson != null) + { + eimPath = Paths.get(eimJson.getEimPath()); + } + else if (!StringUtil.isEmpty(eimPathEnvVar)) + { + eimPath = Paths.get(eimPathEnvVar); + } + else + { + eimPath = toolInitializer.getDefaultEimPath(); + } + + IStatus status = toolInitializer.exportOldConfig(eimPath); + Logger.log("Tools Conversion Process Message: "); + Logger.log(status.getMessage()); + if (status.getSeverity() != IStatus.ERROR) + { + preferences.putBoolean(EimConstants.OLD_CONFIG_EXPORTED_FLAG, true); + writeToStandardConsoleStream(Messages.OldConfigExportCompleteSuccessMsg); + } + else + { + writeToErrorConsoleStream(Messages.OldConfigExportCompleteFailMsg); + } + } + catch (IOException e) + { + Logger.log("Error exporting old configuration", e); + writeToErrorConsoleStream(Messages.OldConfigExportCompleteFailMsg); + } + } + + private void writeToStandardConsoleStream(String msg) + { + try + { + standardConsoleStream.write(msg); + } + catch (IOException e) + { + Logger.log(e); + } + } + + private void writeToErrorConsoleStream(String msg) + { + try + { + errorConsoleStream.write(msg); + } + catch (IOException e) + { + Logger.log(e); + } + } + + private void closeEspIdfManager() + { + Display.getDefault().asyncExec(() -> { + IWorkbenchWindow window = EclipseHandler.getActiveWorkbenchWindow(); + if (window != null) + { + IWorkbenchPage page = window.getActivePage(); + if (page != null) + { + IEditorReference[] editors = page.getEditorReferences(); + for (IEditorReference editorRef : editors) + { + if (ESPIDFManagerEditor.EDITOR_ID.equals(editorRef.getId())) + { + IEditorPart editor = editorRef.getEditor(false); + if (editor != null) + { + page.closeEditor(editor, false); + } + } + } + } + } + }); + } + + private void notifyMissingTools() + { + GlobalModalLock.showModal(() -> MessageDialog.openQuestion(Display.getDefault().getActiveShell(), + Messages.ToolsInitializationEimMissingMsgBoxTitle, Messages.ToolsInitializationEimMissingMsgBoxMessage), + response -> { + if (response) + { + // Download Launch EIM + downloadAndLaunchEim(); + } + else + { + Logger.log("User selected No to download EIM"); + } + }); + } + + private void downloadAndLaunchEim() + { + Job downloadJob = new Job("Download and Launch EIM") + { + + @Override + protected IStatus run(IProgressMonitor monitor) + { + eimLoader.downloadEim(monitor); + return Status.OK_STATUS; + } + }; + downloadJob.setUser(true); + downloadJob.schedule(); + } + + private MessageConsoleStream getConsoleStream(boolean errorStream) + { + IDFConsole idfConsole = new IDFConsole(); + return idfConsole.getConsoleStream("EIM Launch Console", null, errorStream); + } + + private void promptUserToOpenToolManager(EimJson eimJson) + { + Display.getDefault().syncExec(() -> { + String testRunValue = System.getProperty("testRun"); + Logger.log("testRun: " + testRunValue); + + if (!StringUtil.isEmpty(testRunValue) && Boolean.parseBoolean(testRunValue)) + { + openEspIdfManager(eimJson); + return; + } + + Shell shell = Display.getDefault().getActiveShell(); + MessageBox messageBox = new MessageBox(shell, SWT.ICON_WARNING | SWT.YES | SWT.NO); + messageBox.setText(Messages.NoActiveEspIdfInWorkspaceMsgTitle); + messageBox.setMessage(Messages.NoActiveEspIdfInWorkspaceMsg); + + GlobalModalLock.showModal(messageBox::open, response -> { + if (response == SWT.YES) + { + openEspIdfManager(eimJson); + } + }); + }); + } + + private void promptUserToMoveEimToApplications() + { + GlobalModalLock.showModal(() -> { + MessageDialog.openInformation(Display.getDefault().getActiveShell(), Messages.EIMNotInApplicationsTitle, + Messages.EIMNotInApplicationsMessage); + return null; + }, ignored -> { + }); + } + + private void openEspIdfManager(EimJson eimJson) + { + Display.getDefault().asyncExec(() -> { + IWorkbenchWindow window = EclipseHandler.getActiveWorkbenchWindow(); + try + { + EimEditorInput input = new EimEditorInput(eimJson); + input.setFirstStartup(true); + IDE.openEditor(window.getActivePage(), input, ESPIDFManagerEditor.EDITOR_ID); + IDFUtil.closeWelcomePage(window); + } + catch (PartInitException e) + { + Logger.log(e); + } + }); + } + + private class StartupClassDownloadEimDownloadListener implements DownloadListener + { + + @Override + public void onProgress(int percent) + { + Display.getDefault().asyncExec(() -> { + try + { + int blocks = percent / 10; + String bar = "[" + "#".repeat(blocks) + " ".repeat(10 - blocks) + "] " + percent + "%"; + standardConsoleStream.write("\r" + bar); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + } + + @Override + public void onCompleted(String filePath) + { + Display.getDefault().syncExec(() -> { + try + { + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + Process process = null; + String appToLaunch = filePath; + try + { + if (filePath.endsWith(".dmg")) + { + appToLaunch = eimLoader.installAndLaunchDmg(Paths.get(filePath)); + } + + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, appToLaunch); + process = eimLoader.launchEim(appToLaunch); + } + catch ( + IOException + | InterruptedException e) + { + Logger.log(e); + } + + eimLoader.waitForEimClosure(process, () -> { + if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) + { + Logger.log("Old configuration found and not converted"); + handleOldConfigExport(); + } + try + { + eimJson = toolInitializer.loadEimJson(); + } + catch (EimVersionMismatchException e) + { + Logger.log(e); + MessageDialog.openError(Display.getDefault().getActiveShell(), e.msgTitle(), e.getMessage()); + return; + } + openEspIdfManager(eimJson); + }); + } + + @Override + public void onError(String message, Exception e) + { + Display.getDefault().asyncExec(() -> { + try + { + errorConsoleStream.write("Download Failed: " + e.getMessage()); + } + catch (IOException e1) + { + Logger.log(e1); + } + }); + } + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/GitWizardRepProgressMonitor.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/GitWizardRepProgressMonitor.java deleted file mode 100644 index d245dc821..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/GitWizardRepProgressMonitor.java +++ /dev/null @@ -1,138 +0,0 @@ -/******************************************************************************* - * Copyright 2022 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.tools; - -import java.text.MessageFormat; -import java.time.Duration; -import java.util.Queue; - -import org.eclipse.jgit.lib.BatchingProgressMonitor; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.ProgressBar; - -/** - * Git cloning progress report class to add updated messages to the passed queue of messages which can be then consumed - * by the initiator - * - * @author Ali Azam Rana - * - */ -public class GitWizardRepProgressMonitor extends BatchingProgressMonitor -{ - private Queue logMessages; - private boolean jobCancelled; - private ProgressBar progressBar; - private Display display; - - public GitWizardRepProgressMonitor(Queue logMessages, ProgressBar progressBar) - { - this.logMessages = logMessages; - this.progressBar = progressBar; - display = progressBar.getDisplay(); - } - - protected void onUpdate(String taskName, int workCurr) - { - onUpdate(taskName, workCurr, null); - } - - protected void onEndTask(String taskName, int workCurr) - { - onEndTask(taskName, workCurr, null); - } - - protected void onUpdate(String taskName, int workCurr, int workTotal, int percentDone) - { - onUpdate(taskName, workCurr, null); - } - - protected void onEndTask(String taskName, int workCurr, int workTotal, int percentDone) - { - onEndTask(taskName, workCurr, workTotal, percentDone, null); - } - - protected void onUpdate(String taskName, int workCurr, Duration duration) - { - updateProgressBar(workCurr); - setProgressBarVisibility(false); - logMessages.add(MessageFormat.format("{0} {1}", taskName, workCurr)); //$NON-NLS-1$ - } - - protected void onEndTask(String taskName, int workCurr, Duration duration) - { - updateProgressBar(workCurr); - logMessages.add(MessageFormat.format("Finished {0} {1}", taskName, workCurr)); //$NON-NLS-1$ - } - - protected void onUpdate(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) - { - initializeMaxProgressbar(workTotal); - updateProgressBar(workCurr); - logMessages.add( - MessageFormat.format("{0} {1}, total {2} {3}% Completed", taskName, workCurr, workTotal, percentDone)); //$NON-NLS-1$ - } - - protected void onEndTask(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) - { - initializeMaxProgressbar(workTotal); - updateProgressBar(workCurr); - setProgressBarVisibility(false); - logMessages.add(MessageFormat.format("Finished {0} {1}, total {2} {3}% Completed", taskName, workCurr, //$NON-NLS-1$ - workTotal, percentDone)); - } - - @Override - public boolean isCancelled() - { - if (jobCancelled) - { - logMessages.add("Cancelled by User"); //$NON-NLS-1$ - } - return jobCancelled; - } - - public void setJobCancelled(boolean jobCancelled) - { - this.jobCancelled = jobCancelled; - } - - private void initializeMaxProgressbar(int max) - { - display.asyncExec(new Runnable() - { - @Override - public void run() - { - progressBar.setVisible(true); - progressBar.setMaximum(max); - } - }); - } - - private void updateProgressBar(int updateValue) - { - display.asyncExec(new Runnable() - { - @Override - public void run() - { - progressBar.setSelection(updateValue); - } - }); - } - - private void setProgressBarVisibility(boolean visible) - { - display.asyncExec(new Runnable() - { - @Override - public void run() - { - progressBar.setVisible(visible); - } - }); - } - -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/LogMessagesThread.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/LogMessagesThread.java deleted file mode 100644 index 20e25273f..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/LogMessagesThread.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright 2022 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.tools; - -import java.util.Queue; - -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Text; - -import com.espressif.idf.core.logging.Logger; - -/** - * Thread for logging messages in a queue to the SWT Text - * - * @author Ali Azam Rana - * - */ -public class LogMessagesThread extends Thread -{ - private final Queue logMessages; - private boolean stopLogging; - private final Text logAreaText; - private Display display; - - public LogMessagesThread(Queue logMessages, Text logAreaText, Display display) - { - this.logMessages = logMessages; - this.logAreaText = logAreaText; - this.display = display; - } - - @Override - public void run() - { - while (!stopLogging) - { - try - { - Thread.sleep(50); - } - catch (InterruptedException e) - { - Logger.log(e); - } - if (logMessages.size() != 0) - { - String msg = logMessages.poll(); - showMessage(msg); - } - } - } - - private void showMessage(final String message) - { - if (display == null && logAreaText != null) - { - display = logAreaText.getDisplay(); - } - display.asyncExec(new Runnable() - { - public void run() - { - if (logAreaText.getText().length() != 0) - { - logAreaText.append(System.getProperty("line.separator")); //$NON-NLS-1$ - } - logAreaText.append(message); - } - }); - } - - public void setStopLogging(boolean stopLogging) - { - this.stopLogging = stopLogging; - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ManageEspIdfVersionsHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ManageEspIdfVersionsHandler.java index ceb02b514..27ae83b0f 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ManageEspIdfVersionsHandler.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ManageEspIdfVersionsHandler.java @@ -1,24 +1,23 @@ package com.espressif.idf.ui.tools; -import java.io.File; +import java.io.IOException; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.part.FileEditorInput; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.IToolsInstallationWizardConstants; +import com.espressif.idf.core.tools.EimIdfConfiguratinParser; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.ui.handlers.EclipseHandler; import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; +import com.espressif.idf.ui.tools.manager.EimEditorInput; public class ManageEspIdfVersionsHandler extends AbstractHandler { @@ -39,18 +38,28 @@ public void run() { IWorkbenchWindow activeww = EclipseHandler.getActiveWorkbenchWindow(); IDFUtil.closeWelcomePage(activeww); - + + EimJson eimJson = new EimJson(); + try { - File inputFile = new File(toolSetConfigFilePath()); - if (!inputFile.exists()) + EimIdfConfiguratinParser eimIdfConfiguratinParser = new EimIdfConfiguratinParser(); + eimJson = eimIdfConfiguratinParser.getEimJson(true); + } + catch (IOException | EimVersionMismatchException e) + { + Logger.log(e); + if (e instanceof EimVersionMismatchException) { - inputFile.createNewFile(); + EimVersionMismatchException eimEx = (EimVersionMismatchException) e; + MessageDialog.openError(Display.getDefault().getActiveShell(), eimEx.msgTitle(), eimEx.getMessage()); } + } - IFile iFile = ResourcesPlugin.getWorkspace().getRoot() - .getFile(new Path(inputFile.getAbsolutePath())); - IDE.openEditor(activeww.getActivePage(), new FileEditorInput(iFile), ESPIDFManagerEditor.EDITOR_ID); + try + { + IDE.openEditor(activeww.getActivePage(), new EimEditorInput(eimJson), ESPIDFManagerEditor.EDITOR_ID, + true); } catch (Exception e) { @@ -59,14 +68,4 @@ public void run() } }); } - - private String toolSetConfigFilePath() - { - IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation(); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(path.toOSString()); - stringBuilder.append(File.separatorChar); - stringBuilder.append(IToolsInstallationWizardConstants.TOOL_SET_CONFIG_FILE); - return stringBuilder.toString(); - } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java index 25f631a0f..15cc07a12 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java @@ -16,118 +16,24 @@ public class Messages extends NLS { private static final String BUNDLE_NAME = "com.espressif.idf.ui.tools.messages"; //$NON-NLS-1$ - public static String UrlDescriptionText; - public static String SizeDescriptionText; - public static String SupportedTargetsDescriptionText; - public static String ToolsManagerShellHeading; - public static String ToolsTreeNameCol; - public static String ToolsTreeSizeCol; - public static String ToolsTreeStatusCol; - public static String DescriptionText; - public static String InstallToolsText; - public static String DeleteToolsText; - public static String Installed; - public static String DownloadFileText; - public static String ExtractionTextMessage; - public static String InstallingToolMessage; - public static String UpdatingPathMessage; - public static String PreviousToolMessage; - public static String UpdateToolPathMessage; - public static String SystemPathMessage; - public static String ExtractionCompletedMessage; - public static String RemovedPathMessage; - public static String ManageToolsInstallationShell_mntmNewItem_text; - public static String ManageToolsInstallationShell_tltmCheckItem_text; - public static String ManageToolsInstallationShell_label_text; - public static String SelectRecommended; - public static String FilterLabel; - public static String ManageToolsInstallation; - public static String ManageToolsInstallationDescription; - public static String ToolsManagerWizard; - public static String InstallPreRquisitePage; - public static String InstallPreRquisitePage_lblLog_text; - public static String InstallToolsPreReqPageDescription; - public static String FileSelectionDialogTitle; - public static String DirectorySelectionDialogMessage; - public static String GitLabel; - public static String PythonLabel; - public static String BrowseButton; - public static String InstallEspIdfPage; - public static String InstallEspIdfPageDescription; - public static String InstallEspIdfPage_Existing; - public static String InstallEspIdfPage_btnNew_text; - public static String InstallEspIdfPage_lblEspidfPath_text; - public static String InstallEspIdfPage_lblEspidfVersion_text; - public static String InstallEspIdfPage_btnDownload_text; - public static String SelectPythonVersion; - public static String InstallEspIdfPage_lblDownloadDirectory_text; - public static String SelectDownloadDir; - public static String GitCloningJobMsg; - public static String CloningCompletedMsg; - public static String IDFDownloadWizard_DownloadingMessage; - public static String IDFDownloadWizard_DownloadCompleteMsg; - public static String IDFDownloadWizard_DecompressingMsg; - public static String IDFDownloadWizard_DecompressingCompleted; - public static String IDFDownloadWizard_UpdatingIDFPathMessage; - public static String BtnCancel; - public static String OperationCancelledByUser; - public static String InstallToolsHandler_CopyingOpenOCDRules; - public static String InstallToolsHandler_OpenOCDRulesCopied; - public static String InstallToolsHandler_OpenOCDRulesCopyError; - public static String InstallToolsHandler_OpenOCDRulesCopyPaths; - public static String InstallToolsHandler_OpenOCDRulesCopyWarning; - public static String InstallToolsHandler_OpenOCDRulesCopyWarningMessage; - public static String InstallToolsHandler_OpenOCDRulesNotCopied; - public static String AbstractToolsHandler_ExecutingMsg; - public static String ToolAreadyPresent; - public static String ForceDownload_ToolTip; - public static String ForceDownload; - public static String InstallToolsProgressShell_lblNewLabel_text; - public static String InstallToolsProgressShell_text_text; - public static String InstallToolsProgressShell_txtTxtinstalledtool_text; - public static String RemovingDirectoryMessage; - public static String RemoveToolMessageBox; - public static String RemoveToolMessageBoxTitle; - public static String SelectAllButton; - public static String DeselectAllButton; - public static String FilterTargets; - public static String Warning; - public static String DirectorySelectionDialog_IDFDirLabel; - public static String DirectorySelectionDialog_SelectIDFDirMessage; - public static String NotInstalled; - public static String Available; - public static String ShowAvailableVersionsOnly; - public static String ForceDownloadToolTip; - public static String RemoveToolMessageBoxFinish; - public static String SelectAllButtonToolTip; - public static String DeselectAllButtonToolTip; - public static String SelectRecommendedToolTip; - public static String FilterTargetBoxToolTip; - public static String ShowAvailableVersionsOnlyToolTip; - public static String DeleteToolsTextToolTip; - public static String MissingToolsValidationMessage_A; - public static String MissingToolsValidationMessage_B; - public static String MissingToolsValidationLink; - - public static String EspIdfEditorTitle; public static String EspIdfManagerVersionCol; public static String EspIdfManagerLocationCol; - public static String EspIdfManagerStateCol; public static String EspIdfManagerActivateCol; - public static String EspIdfManagerAddToolsBtn; - public static String EspIdfManagerRemoveAllBtn; - public static String EspIdfManagerDeleteBtn; - public static String EspIdfManagerMessageBoxDeleteConfirmMessage; - public static String EspIdfManagerMessageBoxDeleteConfirmMessageTitle; - public static String EspIdfManagerMessageBoxDeleteAllConfirmMessage; - public static String EspIdfManagerMessageBoxDeleteAllConfirmMessageTitle; - - public static String IDFDownloadHandler_ESPIDFConfiguration; - public static String IDFDownloadHandler_DownloadPage_Title; - public static String IDFDownloadHandler_DownloadPageMsg; + public static String EspIdfManagerNameCol; public static String EspIdfManagerReloadBtnToolTip; - public static String EspIdfManagerDeleteBtnToolTip; + public static String IDFGuideLinkLabel_Text; + public static String EIMButtonDownloadText; + public static String EIMButtonLaunchText; + + public static String IDFToolsHandler_ToolsManagerConsole; + + public static String EimJsonChangedMsgTitle; + public static String EimJsonChangedMsgDetail; + public static String EimJsonStateChangedMsgDetail; + + public static String MsgYes; + public static String MsgNo; static { diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJobListener.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/SetupToolsJobListener.java similarity index 70% rename from bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJobListener.java rename to bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/SetupToolsJobListener.java index 438e5e510..c292171b3 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJobListener.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/SetupToolsJobListener.java @@ -4,6 +4,7 @@ *******************************************************************************/ package com.espressif.idf.ui.tools; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.core.runtime.preferences.InstanceScope; @@ -14,25 +15,28 @@ import com.espressif.idf.core.logging.Logger; import com.espressif.idf.core.resources.OpenDialogListenerSupport; import com.espressif.idf.core.resources.PopupDialog; +import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.SetupToolsInIde; import com.espressif.idf.ui.UIPlugin; import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; -import com.espressif.idf.ui.update.InstallToolsHandler; /** - * Listener for {@link ToolsActivationJob} + * Listener for {@link SetupToolsInIde} * @author Ali Azam Rana * */ -public class ToolsActivationJobListener extends JobChangeAdapter +public class SetupToolsJobListener extends JobChangeAdapter { private ESPIDFMainTablePage espidfMainTablePage; + private SetupToolsInIde setupToolsInIde; - public ToolsActivationJobListener(ESPIDFMainTablePage espidfMainTablePage) + public SetupToolsJobListener(ESPIDFMainTablePage espidfMainTablePage, SetupToolsInIde setupToolsInIde) { this.espidfMainTablePage = espidfMainTablePage; + this.setupToolsInIde = setupToolsInIde; } - public ToolsActivationJobListener() + public SetupToolsJobListener() { } @@ -46,23 +50,21 @@ public void aboutToRun(IJobChangeEvent event) @Override public void done(IJobChangeEvent event) { - Display.getDefault().asyncExec(() -> { - if (espidfMainTablePage != null) - { - espidfMainTablePage.refreshEditorUI(); - } - }); - OpenDialogListenerSupport.getSupport().firePropertyChange(PopupDialog.ENABLE_LAUNCHBAR_EVENTS.name(), null, - null); - Preferences scopedPreferenceStore = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); + + if (event.getResult().getSeverity() != IStatus.OK) + { + // Rollback all the changes + setupToolsInIde.rollback(); + } + if (event.getResult().isOK()) { - scopedPreferenceStore.putBoolean(InstallToolsHandler.INSTALL_TOOLS_FLAG, true); + scopedPreferenceStore.putBoolean(EimConstants.INSTALL_TOOLS_FLAG, true); } else { - scopedPreferenceStore.putBoolean(InstallToolsHandler.INSTALL_TOOLS_FLAG, false); + scopedPreferenceStore.putBoolean(EimConstants.INSTALL_TOOLS_FLAG, false); } try @@ -73,5 +75,14 @@ public void done(IJobChangeEvent event) { Logger.log(e); } + + Display.getDefault().asyncExec(() -> { + if (espidfMainTablePage != null) + { + espidfMainTablePage.refreshEditorUI(); + } + }); + OpenDialogListenerSupport.getSupport().firePropertyChange(PopupDialog.ENABLE_LAUNCHBAR_EVENTS.name(), null, + null); } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java deleted file mode 100644 index 9859fae25..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsActivationJob.java +++ /dev/null @@ -1,213 +0,0 @@ -/******************************************************************************* - * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.tools; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.List; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.MessageBox; -import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; - -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.toolchain.ESPToolChainManager; -import com.espressif.idf.core.toolchain.IDFTargetsReader; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.LspService; -import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.UIPlugin; -import com.espressif.idf.ui.update.ExportIDFTools; -import com.espressif.idf.ui.update.Messages; - -/** - * Job to activate the provide {@link IDFToolSet} in the given ide environment - * - * @author Ali Azam Rana - * - */ -public class ToolsActivationJob extends ToolsJob -{ - public static final String INSTALL_TOOLS_FLAG = "INSTALL_TOOLS_FLAG"; //$NON-NLS-1$ - - public ToolsActivationJob(IDFToolSet idfToolSet, String pythonExecutablePath, String gitExecutablePath) - { - super("Tools Activation Job", null, null); - this.idfToolSet = idfToolSet; - } - - @Override - protected IStatus run(IProgressMonitor monitor) - { - if (idfToolSet == null) - { - return Status.error("IDF Tool Set Cannot be null"); - } - - // verify with export script to test if everything is okay with installation - - monitor.beginTask("Verifying if there are any changes to the installed tools", 5); - monitor.worked(1); - - ExportIDFTools exportIDFTools = new ExportIDFTools(); - IStatus status = exportIDFTools.getToolsExportOutputFromGivenIdfPath(idfToolSet.getSystemPythonExecutablePath(), - idfToolSet.getSystemGitExecutablePath(), console, errorConsoleStream, idfToolSet.getIdfLocation()); - if (status.getSeverity() == IStatus.ERROR) - { - return Status.error("INSTALL_AGAIN"); - } - monitor.worked(1); - - monitor.setTaskName("Exporting variables to eclipse"); - processExportCmdOutput(status.getMessage()); - setEnvVarsInEclipse(); - monitor.worked(1); - - monitor.setTaskName("Setting up toolchains and targets"); - setUpToolChainsAndTargets(); - monitor.worked(1); - - // post export operations like copying openocd rules may also need to setup with the python dependencies here as - // well like websocket-client - monitor.setTaskName(Messages.InstallToolsHandler_InstallingWebscoketMsg); - handleWebSocketClientInstall(); - monitor.worked(1); - - monitor.setTaskName("Setting OpenOCD rules"); - copyOpenOcdRules(); - monitor.worked(1); - - idfToolSet.setActive(true); - - toolSetConfigurationManager.export(idfToolSet); - console.println("Tools Activated"); - LspService lspService = new LspService(); - lspService.updateClangdPath(); - lspService.updateQueryDriver(); - console.println(Messages.ClangdPreferences_UpdatedMsg); - Preferences scopedPreferenceStore = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); - scopedPreferenceStore.putBoolean(INSTALL_TOOLS_FLAG, true); - try - { - scopedPreferenceStore.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - - return Status.OK_STATUS; - } - - private void copyOpenOcdRules() - { - if (Platform.getOS().equals(Platform.OS_LINUX) - && !IDFUtil.getOpenOCDLocation().equalsIgnoreCase(StringUtil.EMPTY)) - { - console.println(Messages.InstallToolsHandler_CopyingOpenOCDRules); - // Copy the rules to the idf - StringBuilder pathToRules = new StringBuilder(); - pathToRules.append(IDFUtil.getOpenOCDLocation()); - pathToRules.append("/../share/openocd/contrib/60-openocd.rules"); //$NON-NLS-1$ - File rulesFile = new File(pathToRules.toString()); - if (rulesFile.exists()) - { - Path source = Paths.get(pathToRules.toString()); - Path target = Paths.get("/etc/udev/rules.d/60-openocd.rules"); //$NON-NLS-1$ - console.println(String.format(Messages.InstallToolsHandler_OpenOCDRulesCopyPaths, source.toString(), - target.toString())); - - Display.getDefault().syncExec(new Runnable() - { - @Override - public void run() - { - try - { - if (target.toFile().exists()) - { - MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), - SWT.ICON_WARNING | SWT.YES | SWT.NO); - messageBox.setText(Messages.InstallToolsHandler_OpenOCDRulesCopyWarning); - messageBox.setMessage(Messages.InstallToolsHandler_OpenOCDRulesCopyWarningMessage); - int response = messageBox.open(); - if (response == SWT.YES) - { - Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); - } - else - { - console.println(Messages.InstallToolsHandler_OpenOCDRulesNotCopied); - return; - } - } - else - { - Files.copy(source, target); - } - - console.println(Messages.InstallToolsHandler_OpenOCDRulesCopied); - } - catch (IOException e) - { - Logger.log(e); - errorConsoleStream.println(Messages.InstallToolsHandler_OpenOCDRulesCopyError); - } - } - }); - } - } - } - - private void setUpToolChainsAndTargets() - { - // Get current active idf - String idfPath = IDFUtil.getIDFPath(); - List targets = IDFTargetsReader.readTargetsFromEspIdf(idfPath).getAllTargetNames(); - - ESPToolChainManager espToolChainManager = new ESPToolChainManager(); - espToolChainManager.removeLaunchTargetsNotPresent(targets); - espToolChainManager.removeCmakeToolChains(); - espToolChainManager.removeStdToolChains(); - espToolChainManager.configureToolChain(targets); - } - - private void setEnvVarsInEclipse() - { - if (idfToolSet == null) - throw new RuntimeException("Tools Cannot be null"); - - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - idfEnvironmentVariables.removeAllEnvVariables(); - idfToolSet.getEnvVars().forEach((key, value) -> { - if (value != null) - idfEnvironmentVariables.addEnvVariable(key, value); - }); - String path = replacePathVariable(idfToolSet.getEnvVars().get(IDFEnvironmentVariables.PATH)); - - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_PATH, idfToolSet.getIdfLocation()); - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PATH, path); - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PYTHON_EXE_PATH, - idfToolSet.getSystemPythonExecutablePath()); - - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, "1"); - // IDF_MAINTAINER=1 to be able to build with the clang toolchain - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_MAINTAINER, "1"); - IDFUtil.updateEspressifPrefPageOpenocdPath(); - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationJob.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationJob.java deleted file mode 100644 index 988624c55..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationJob.java +++ /dev/null @@ -1,163 +0,0 @@ -/******************************************************************************* - * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.tools; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.cdt.cmake.core.ICMakeToolChainFile; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.ui.console.MessageConsoleStream; - -import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.toolchain.ESPToolChainManager; -import com.espressif.idf.core.toolchain.ESPToolchain; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.ui.update.ExportIDFTools; -import com.espressif.idf.ui.update.Messages; - -/** - * Class to install the dependencies and any - * given tools for an idf with given {@link IDFToolSet} - * @author Ali Azam Rana - * - */ -public class ToolsInstallationJob extends ToolsJob -{ - public ToolsInstallationJob(String pythonExecutablePath, String gitExecutablePath, String idfPath) - { - super(Messages.InstallToolsHandler_InstallingToolsMsg, pythonExecutablePath, gitExecutablePath); - this.idfPath = idfPath; - this.idfToolSet.setIdfLocation(idfPath); - this.idfToolSet.setSystemGitExecutablePath(gitExecutablePath); - this.idfToolSet.setSystemPythonExecutablePath(pythonExecutablePath); - } - - @Override - protected IStatus run(IProgressMonitor monitor) - { - monitor.beginTask(Messages.InstallToolsHandler_ItWilltakeTimeMsg, 5); - monitor.worked(1); - Logger.log("" - ); - IStatus status = handleToolsInstall(); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - monitor.worked(1); - monitor.setTaskName(Messages.InstallToolsHandler_InstallingPythonMsg); - status = handleToolsInstallPython(console); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - monitor.worked(1); - - monitor.setTaskName(Messages.InstallToolsHandler_ExportingPathsMsg); - ExportIDFTools exportIDFTools = new ExportIDFTools(); - status = exportIDFTools.getToolsExportOutputFromGivenIdfPath(pythonExecutablePath, gitExecutablePath, console, - errorConsoleStream, idfPath); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - Logger.log(status.getMessage()); - processExportCmdOutput(status.getMessage()); - - monitor.worked(1); - - monitor.setTaskName(Messages.InstallToolsHandler_AutoConfigureToolchain); - ESPToolChainManager espToolChainManager = new ESPToolChainManager(); - String pathToLookForToolChains = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.PATH); - String idfPath = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.IDF_PATH); - try - { - List espToolChains = espToolChainManager - .getStdToolChains(Arrays.asList(pathToLookForToolChains.split(File.pathSeparator)), idfPath); - idfToolSet.setEspStdToolChains(espToolChains); - List cMakeToolChainFiles = espToolChainManager.getCmakeToolChains(idfPath); - idfToolSet.setEspCmakeToolChainFiles(cMakeToolChainFiles); - } - catch (CoreException e) - { - Logger.log(e); - logToConsole("Error Getting Toolchains", errorConsoleStream); - return IDFCorePlugin.errorStatus("Error Getting Toolchains", null); //$NON-NLS-1$ - } - - monitor.setTaskName("Loading Available Targets in IDF"); - - status = loadTargetsAvailableFromIdfInCurrentToolSet(); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - idfToolSet.setLaunchTargets(extractTargets(status.getMessage())); - - monitor.worked(1); - - monitor.setTaskName(Messages.InstallToolsHandler_InstallingWebscoketMsg); - handleWebSocketClientInstall(); - monitor.worked(1); - - console.println(Messages.InstallToolsHandler_ToolsCompleted); - - console.println("Writing to the configuration file"); - idfToolSet.setId(idfToolSet.hashCode()); - - toolSetConfigurationManager.export(idfToolSet); - - console.println(Messages.ToolsInstallationJobCompletedMessage); - return Status.OK_STATUS; - } - - private void logToConsole(String message, MessageConsoleStream stream) - { - try - { - stream.write(message); - } - catch (IOException e) - { - Logger.log(e); - } - } - - protected IStatus handleToolsInstall() - { - // idf_tools.py install all - List arguments = new ArrayList(); - arguments.add(IDFConstants.TOOLS_INSTALL_CMD); - arguments.add(IDFConstants.TOOLS_INSTALL_ALL_CMD); - - console.println(Messages.InstallToolsHandler_InstallingToolsMsg); - console.println(Messages.InstallToolsHandler_ItWilltakeTimeMsg); - return runCommand(arguments, console); - } - - protected IStatus handleToolsInstallPython(MessageConsoleStream console) - { - List arguments; - // idf_tools.py install-python-env - arguments = new ArrayList(); - arguments.add(IDFConstants.TOOLS_INSTALL_PYTHON_CMD); - return runCommand(arguments, console); - } - -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsJob.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsJob.java deleted file mode 100644 index 5fec36a23..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsJob.java +++ /dev/null @@ -1,565 +0,0 @@ -/******************************************************************************* - * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.tools; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.osgi.util.NLS; -import org.eclipse.ui.console.MessageConsoleStream; - -import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFCorePreferenceConstants; -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.ProcessBuilderFactory; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.tools.ToolSetConfigurationManager; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.IDFConsole; -import com.espressif.idf.ui.InputStreamConsoleThread; -import com.espressif.idf.ui.UIPlugin; -import com.espressif.idf.ui.update.Messages; - -/** - * Parent class for all tools related activity - * any common methods must be added here - * The class was created to save - * code and split the operation of installation and activation in two - * @author Ali Azam Rana - * - */ -public abstract class ToolsJob extends Job -{ - - protected IDFConsole idfConsole; - protected MessageConsoleStream console; - protected MessageConsoleStream errorConsoleStream; - protected String pythonExecutablePath; - protected String gitExecutablePath; - protected IDFToolSet idfToolSet; - protected ToolSetConfigurationManager toolSetConfigurationManager; - protected String idfPath; - - public ToolsJob(String name, String pythonExecutablePath, String gitExecutablePath) - { - super(name); - this.pythonExecutablePath = pythonExecutablePath; - this.gitExecutablePath = gitExecutablePath; - idfToolSet = new IDFToolSet(); - toolSetConfigurationManager = new ToolSetConfigurationManager(); - activateIDFConsoleView(); - } - - protected void processExportCmdOutput(final String exportCmdOp) - { - // process export command output - final String[] exportEntries = exportCmdOp.split("\n"); //$NON-NLS-1$ - for (String entry : exportEntries) - { - entry = entry.replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ - if (entry.startsWith("Error")) - { - try - { - errorConsoleStream.write(entry); - } - catch (IOException e) - { - Logger.log(e); - } - } - String[] keyValue = entry.split("="); //$NON-NLS-1$ - if (keyValue.length == 2) // 0 - key, 1 - value - { - final String msg = MessageFormat.format("Key: {0} Value: {1}", keyValue[0], keyValue[1]); //$NON-NLS-1$ - Logger.log(msg); - String key = keyValue[0]; - String value = keyValue[1]; - if (idfToolSet.getEnvVars() == null) - { - idfToolSet.setEnvVars(new HashMap()); - } - - idfToolSet.getEnvVars().put(key, value); - } - - } - - idfToolSet.getEnvVars().put(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, "1"); //$NON-NLS-1$ - // IDF_MAINTAINER=1 to be able to build with the clang toolchain - idfToolSet.getEnvVars().put(IDFEnvironmentVariables.IDF_MAINTAINER, "1"); //$NON-NLS-1$ - if (!StringUtil.isEmpty(idfPath)) - { - idfToolSet.getEnvVars().put(IDFEnvironmentVariables.IDF_PATH, idfPath); - idfToolSet.setIdfLocation(idfPath); - } - - IStatus status = getIdfVersionFromIdfPy(); - String cmdOutput = status.getMessage(); - Pattern pattern = Pattern.compile("v(\\d+\\.\\d+\\.\\d+)"); //$NON-NLS-1$ - Matcher matcher = pattern.matcher(cmdOutput.toLowerCase()); - if (matcher.find()) - { - idfToolSet.setIdfVersion(matcher.group(1)); - } - else - { - idfToolSet.setIdfVersion(idfToolSet.getEnvVars().computeIfAbsent(IDFEnvironmentVariables.ESP_IDF_VERSION, k -> StringUtil.EMPTY)); - } - idfToolSet.getEnvVars().put(IDFEnvironmentVariables.ESP_IDF_VERSION, idfToolSet.getIdfVersion()); - - } - - protected String replacePathVariable(String value) - { - // Get system PATH - Map systemEnv = new HashMap<>(IDFUtil.getSystemEnv()); - String pathEntry = systemEnv.get("PATH"); //$NON-NLS-1$ - if (pathEntry == null) - { - pathEntry = systemEnv.get("Path"); // for Windows //$NON-NLS-1$ - if (pathEntry == null) // no idea - { - Logger.log(new Exception("No PATH found in the system environment variables")); //$NON-NLS-1$ - } - } - - if (!StringUtil.isEmpty(pathEntry)) - { - value = value.replace("$PATH", pathEntry); // macOS //$NON-NLS-1$ - value = value.replace("%PATH%", pathEntry); // Windows //$NON-NLS-1$ - } - return value; - } - - protected IStatus loadTargetsAvailableFromIdfInCurrentToolSet() - { - List arguments = new ArrayList(); - arguments.add(IDFConstants.IDF_LIST_TARGETS_CMD); - return runCommandIdfPyInIdfEnv(arguments, console); - } - - protected List extractTargets(String input) - { - List targets = new ArrayList(); - Pattern pattern = Pattern.compile("^esp32.*", Pattern.MULTILINE); - Matcher matcher = pattern.matcher(input); - while (matcher.find()) - { - targets.add(matcher.group()); - } - return targets; - } - - protected IStatus handleWebSocketClientInstall() - { - String websocketClient = "websocket-client"; //$NON-NLS-1$ - // pip install websocket-client - List arguments = new ArrayList(); - final String pythonEnvPath = pythonVirtualExecutablePath(idfToolSet); - if (pythonEnvPath == null || !new File(pythonEnvPath).exists()) - { - console.println(String.format("%s executable not found. Unable to run `%s -m pip install websocket-client`", //$NON-NLS-1$ - IDFConstants.PYTHON_CMD, IDFConstants.PYTHON_CMD)); - return IDFCorePlugin.errorStatus( - String.format("%s executable not found. Unable to run `%s -m pip install websocket-client`", //$NON-NLS-1$ - IDFConstants.PYTHON_CMD, IDFConstants.PYTHON_CMD), - null); - } - arguments.add(pythonEnvPath); - arguments.add("-m"); //$NON-NLS-1$ - arguments.add("pip"); //$NON-NLS-1$ - arguments.add("list"); //$NON-NLS-1$ - - ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - - try - { - String cmdMsg = "Executing " + getCommandString(arguments); //$NON-NLS-1$ - if (console != null) - { - console.println(cmdMsg); - } - Logger.log(cmdMsg); - - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - Logger.log(environment.toString()); - - IStatus status = processRunner.runInBackground(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), - IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - if (errorConsoleStream != null) - { - errorConsoleStream.println("Unable to get the process status."); - } - return IDFCorePlugin.errorStatus("Unable to get the process status.", null); //$NON-NLS-1$ - } - - String cmdOutput = status.getMessage(); - if (cmdOutput.contains(websocketClient)) - { - return IDFCorePlugin.okStatus("websocket-client already installed", null); //$NON-NLS-1$ - } - - // websocket client not installed so installing it now. - arguments.remove(arguments.size() - 1); - arguments.add("install"); //$NON-NLS-1$ - arguments.add(websocketClient); - - status = processRunner.runInBackground(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), - IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - if (errorConsoleStream != null) - { - errorConsoleStream.println("Unable to get the process status."); - } - return IDFCorePlugin.errorStatus("Unable to get the process status.", null); //$NON-NLS-1$ - } - - if (console != null) - { - console.println(status.getMessage()); - } - - return status; - } - catch (Exception e1) - { - Logger.log(IDFCorePlugin.getPlugin(), e1); - if (errorConsoleStream != null) - { - errorConsoleStream.println(e1.getLocalizedMessage()); - } - return IDFCorePlugin.errorStatus(e1.getLocalizedMessage(), e1); // $NON-NLS-1$; - } - } - - protected String pythonVirtualExecutablePath(IDFToolSet idfToolSet) - { - String pythonVirtualPath = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.IDF_PYTHON_ENV_PATH); - StringBuilder pythonVirtualExePath = new StringBuilder(); - pythonVirtualExePath.append(pythonVirtualPath); - pythonVirtualExePath.append("/"); //$NON-NLS-1$ - if (Platform.getOS().equals(Platform.OS_WIN32)) - { - pythonVirtualExePath.append("Scripts"); //$NON-NLS-1$ - pythonVirtualExePath.append("/"); //$NON-NLS-1$ - pythonVirtualExePath.append("python.exe"); //$NON-NLS-1$ - } - else - { - pythonVirtualExePath.append("bin"); //$NON-NLS-1$ - pythonVirtualExePath.append("/"); //$NON-NLS-1$ - pythonVirtualExePath.append("python"); //$NON-NLS-1$ - } - - - return pythonVirtualExePath.toString(); - } - - - private String getCommandString(List arguments) - { - StringBuilder builder = new StringBuilder(); - arguments.forEach(entry -> builder.append(entry + " ")); //$NON-NLS-1$ - - return builder.toString().trim(); - } - - protected void activateIDFConsoleView() - { - idfConsole = new IDFConsole(); - console = idfConsole.getConsoleStream(Messages.IDFToolsHandler_ToolsManagerConsole, null, false, true); - errorConsoleStream = idfConsole.getConsoleStream(Messages.IDFToolsHandler_ToolsManagerConsole, null, true, - true); - } - - protected IStatus getIdfVersionFromIdfPy() - { - List arguments = new ArrayList(); - arguments.add("--version"); - return runCommandIdfPyInIdfEnv(arguments, console); - } - - /** - * Append the git directory to the existing CDT build environment PATH variable - * - * @param path CDT build environment PATH - * @param gitExecutablePath - * @return PATH value with git appended - */ - protected String appendGitToPath(String path, String gitExecutablePath) - { - IPath gitPath = new Path(gitExecutablePath); - if (!gitPath.toFile().exists()) - { - Logger.log(NLS.bind("{0} doesn't exist", gitExecutablePath)); //$NON-NLS-1$ - return path; - } - - String gitDir = gitPath.removeLastSegments(1).toOSString(); // ../bin/git - if (!StringUtil.isEmpty(path) && !path.contains(gitDir)) // Git not found on the CDT build PATH environment - { - return path.concat(";").concat(gitDir); // append git path //$NON-NLS-1$ - } - return path; - } - - protected IStatus runCommandIdfPyInIdfEnv(List arguments, MessageConsoleStream console) - { - ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - StringBuilder output = new StringBuilder(); - int waitCount = 10; - try - { - arguments.add(0, pythonVirtualExecutablePath(idfToolSet)); - arguments.add(1, IDFUtil.getIDFPythonScriptFile(idfToolSet.getIdfLocation()).getAbsolutePath()); - - String cmdMsg = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); //$NON-NLS-1$ - console.println(cmdMsg); - Logger.log(cmdMsg); - - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - Logger.log(environment.toString()); - environment.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - loadIdfPathWithSystemPath(environment); - environment.remove(IDFEnvironmentVariables.IDF_PYTHON_ENV_PATH); - environment.remove(IDFEnvironmentVariables.ESP_IDF_VERSION); - environment.remove(IDFEnvironmentVariables.IDF_PATH); - environment.remove(IDFEnvironmentVariables.OPENOCD_SCRIPTS); - - if (gitExecutablePath != null) - { - addPathToEnvironmentPath(environment, gitExecutablePath); - } - Process process = processRunner.run(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line; - while ((line = reader.readLine()) != null) - { - output.append(line).append(System.lineSeparator()); - } - - while (process.isAlive() && waitCount > 0) - { - try - { - Thread.sleep(300); - } - catch (InterruptedException e) - { - Logger.log(e); - } - waitCount--; - } - - if (waitCount == 0) - { - console.println("Process possibly stuck"); - Logger.log("Process possibly stuck"); - return Status.CANCEL_STATUS; - } - - IStatus status = new Status(process.exitValue() == 0 ? IStatus.OK : IStatus.ERROR, UIPlugin.PLUGIN_ID, - process.exitValue(), output.toString(), null); - if (status.getSeverity() == IStatus.ERROR) - { - errorConsoleStream.print( - status.getException() != null ? status.getException().getMessage() : status.getMessage()); - } - console.println(status.getMessage()); - console.println(); - - return status; - } - catch (Exception e1) - { - Logger.log(IDFCorePlugin.getPlugin(), e1); - return IDFCorePlugin.errorStatus(e1.getMessage(), e1); - } - } - - private void addPathToEnvironmentPath(Map environment, String gitExecutablePath) - { - IPath gitPath = new org.eclipse.core.runtime.Path(gitExecutablePath); - if (gitPath.toFile().exists()) - { - String gitDir = gitPath.removeLastSegments(1).toOSString(); - String path1 = environment.get("PATH"); //$NON-NLS-1$ - String path2 = environment.get("Path"); //$NON-NLS-1$ - if (!StringUtil.isEmpty(path1) && !path1.contains(gitDir)) // Git not found on the PATH environment - { - path1 = gitDir.concat(";").concat(path1); //$NON-NLS-1$ - environment.put("PATH", path1); //$NON-NLS-1$ - } - else if (!StringUtil.isEmpty(path2) && !path2.contains(gitDir)) // Git not found on the Path environment - { - path2 = gitDir.concat(";").concat(path2); //$NON-NLS-1$ - environment.put("Path", path2); //$NON-NLS-1$ - } - } - } - - private void loadIdfPathWithSystemPath(Map systemEnv) - { - String idfExportPath = idfToolSet.getEnvVars().get(IDFEnvironmentVariables.PATH); - String pathVar = "PATH"; // for Windows //$NON-NLS-1$ - String pathEntry = systemEnv.get(pathVar); // $NON-NLS-1$ - if (pathEntry == null) - { - pathVar = "Path"; //$NON-NLS-1$ - pathEntry = systemEnv.get(pathVar); - if (pathEntry == null) // no idea - { - Logger.log(new Exception("No PATH found in the system environment variables")); //$NON-NLS-1$ - } - } - - if (!StringUtil.isEmpty(pathEntry)) - { - idfExportPath = idfExportPath.replace("$PATH", pathEntry); // macOS //$NON-NLS-1$ - idfExportPath = idfExportPath.replace("%PATH%", pathEntry); // Windows //$NON-NLS-1$ - } - systemEnv.put(pathVar, idfExportPath); - for (Entry entry : idfToolSet.getEnvVars().entrySet()) - { - if (entry.getKey().equals(IDFEnvironmentVariables.PATH)) - continue; - - systemEnv.put(entry.getKey(), entry.getValue()); - } - } - - protected IStatus runCommand(List arguments, MessageConsoleStream console) - { - ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - - try - { - // insert python.sh/exe path and idf_tools.py - arguments.add(0, pythonExecutablePath); - arguments.add(1, IDFUtil.getIDFToolsScriptFile(idfToolSet.getIdfLocation()).getAbsolutePath()); - - String cmdMsg = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); //$NON-NLS-1$ - console.println(cmdMsg); - Logger.log(cmdMsg); - - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - Logger.log(environment.toString()); - environment.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - environment.put("IDF_GITHUB_ASSETS", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_GLOBAL, null)); - - environment.put("PIP_EXTRA_INDEX_URL", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL, null)); - - if (gitExecutablePath != null) - { - addPathToEnvironmentPath(environment, gitExecutablePath); - } - Process process = processRunner.run(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - IStatus status = processData(process); - console.println(); - - return IDFCorePlugin.okStatus(status.getMessage(), null); - } - catch (Exception e1) - { - Logger.log(IDFCorePlugin.getPlugin(), e1); - return IDFCorePlugin.errorStatus(e1.getMessage(), e1); - } - } - - private IStatus processData(Process process) - { - - InputStream inputStream = process.getInputStream(); - InputStream errorStream = process.getErrorStream(); - - InputStreamConsoleThread readerThread = null; - InputStreamConsoleThread errorThread = null; - try - { - - readerThread = new InputStreamConsoleThread(inputStream, console); - errorThread = new InputStreamConsoleThread(errorStream, console); - - readerThread.start(); - errorThread.start(); - - // This will wait till the process is done. - int exitValue = process.waitFor(); - - readerThread.interrupt(); - errorThread.interrupt(); - readerThread.join(); - errorThread.join(); - - if (exitValue == 0) - { - return Status.OK_STATUS; - } - - return new Status(IStatus.ERROR, IDFCorePlugin.PLUGIN_ID, "Error"); //$NON-NLS-1$ - - } - catch (InterruptedException e) - { - try - { - if (readerThread != null) - { - readerThread.interrupt(); - } - if (errorThread != null) - { - errorThread.interrupt(); - } - if (readerThread != null) - { - readerThread.join(); - } - if (errorThread != null) - { - errorThread.join(); - } - } - catch (InterruptedException e1) - { - // ignore - } - return new Status(IStatus.ERROR, IDFCorePlugin.PLUGIN_ID, e.getMessage(), e); - } - } - -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/ESPIDFManagerEditor.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/ESPIDFManagerEditor.java index d727d615c..115eab859 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/ESPIDFManagerEditor.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/ESPIDFManagerEditor.java @@ -16,13 +16,14 @@ /** * Editor main class used for tools management + * * @author Ali Azam Rana * */ public class ESPIDFManagerEditor extends EditorPart { public static final String EDITOR_ID = "com.espressif.idf.ui.manageespidf"; - + @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { @@ -30,8 +31,7 @@ public void init(IEditorSite site, IEditorInput input) throws PartInitException setInput(input); setPartName(Messages.EspIdfEditorTitle); } - - + @Override public void doSave(IProgressMonitor monitor) { @@ -49,14 +49,26 @@ public boolean isSaveAsAllowed() { return false; } - + @Override public void createPartControl(Composite parent) { - ESPIDFMainTablePage espidfMainTablePage = ESPIDFMainTablePage.getInstance(); - espidfMainTablePage.createPage(parent); - } + IEditorInput input = getEditorInput(); + if (input instanceof EimEditorInput eimInput) + { + ESPIDFMainTablePage espidfMainTablePage = ESPIDFMainTablePage.getInstance(eimInput.getEimJson()); + espidfMainTablePage.createPage(parent); + if (eimInput.isFirstStartup()) + { + espidfMainTablePage.setupInitialEspIdf(); + } + } + else + { + getSite().getPage().closeEditor(this, false); + } + } @Override public boolean isDirty() @@ -64,10 +76,9 @@ public boolean isDirty() return false; } - @Override public void setFocus() { - + } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/EimEditorInput.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/EimEditorInput.java new file mode 100644 index 000000000..8b65e7539 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/EimEditorInput.java @@ -0,0 +1,93 @@ +package com.espressif.idf.ui.tools.manager; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IPersistableElement; + +import com.espressif.idf.core.tools.vo.EimJson; + +public class EimEditorInput implements IEditorInput +{ + private EimJson eimJson; + private boolean firstStartup; + private String FILE_NAME = "idf_eim.json"; //$NON-NLS-1$ + + public EimEditorInput(EimJson eimJson) + { + this.eimJson = eimJson; + } + + public EimJson getEimJson() + { + return eimJson; + } + + @Override + public T getAdapter(Class adapter) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean exists() + { + return true; + } + + @Override + public ImageDescriptor getImageDescriptor() + { + return null; + } + + @Override + public String getName() + { + return null; + } + + @Override + public IPersistableElement getPersistable() + { + return null; + } + + @Override + public String getToolTipText() + { + return null; + } + + public boolean isFirstStartup() + { + return firstStartup; + } + + public void setFirstStartup(boolean firstStartup) + { + this.firstStartup = firstStartup; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null || getClass() != obj.getClass()) + { + return false; + } + EimEditorInput that = (EimEditorInput) obj; + return FILE_NAME.equals(that.FILE_NAME); + } + + @Override + public int hashCode() + { + return FILE_NAME.hashCode(); + } + +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java index 76df9e544..924c9cd41 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java @@ -4,9 +4,11 @@ *******************************************************************************/ package com.espressif.idf.ui.tools.manager.pages; -import java.text.MessageFormat; +import java.io.IOException; import java.util.List; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; @@ -16,7 +18,6 @@ import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; -import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TableEditor; import org.eclipse.swt.events.SelectionAdapter; @@ -30,21 +31,30 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.console.MessageConsoleStream; +import org.osgi.service.prefs.Preferences; -import com.espressif.idf.core.tools.ToolSetConfigurationManager; -import com.espressif.idf.core.tools.vo.IDFToolSet; -import com.espressif.idf.core.util.IDFUtil; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimConstants; +import com.espressif.idf.core.tools.EimIdfConfiguratinParser; +import com.espressif.idf.core.tools.SetupToolsInIde; +import com.espressif.idf.core.tools.ToolInitializer; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.util.ToolsUtility; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.core.tools.vo.IdfInstalled; +import com.espressif.idf.ui.IDFConsole; import com.espressif.idf.ui.UIPlugin; -import com.espressif.idf.ui.install.IDFNewToolsWizard; +import com.espressif.idf.ui.tools.EimButtonLaunchListener; import com.espressif.idf.ui.tools.Messages; -import com.espressif.idf.ui.tools.ToolsActivationJob; -import com.espressif.idf.ui.tools.ToolsActivationJobListener; +import com.espressif.idf.ui.tools.SetupToolsJobListener; /** * Main UI class for all listing and interacting with the tools + * * @author Ali Azam Rana * */ @@ -52,57 +62,106 @@ public class ESPIDFMainTablePage { private Composite container; private TableViewer tableViewer; - private ToolSetConfigurationManager toolSetConfigurationManager; private ColumnViewerComparator comparator; private TableViewerColumn versionColumn; private TableViewerColumn locationColumn; private TableViewerColumn activateColumn; private TableViewerColumn removeColumn; + private TableViewerColumn nameColumn; + private Button eimLaunchBtn; + private TableColumnLayout tableColumnLayout; private Composite tableComposite; - private List idfToolSets; - private Button removeAllButton; - - private static final String REMOVE_ICON = "icons/tools/delete.png"; //$NON-NLS-1$ + private List idfInstalledList; + private static EimJson eimJson; + private EimIdfConfiguratinParser eimIdfConfiguratinParser; + private ToolInitializer toolInitializer; + private static final String RELOAD_ICON = "icons/tools/reload.png"; //$NON-NLS-1$ private static final String IDF_TOOL_SET_BTN_KEY = "IDFToolSet"; //$NON-NLS-1$ - + private static ESPIDFMainTablePage espidfMainTablePage; - + private ESPIDFMainTablePage() { + eimIdfConfiguratinParser = new EimIdfConfiguratinParser(); + toolInitializer = new ToolInitializer( + org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID)); } - - public static ESPIDFMainTablePage getInstance() + + public static ESPIDFMainTablePage getInstance(EimJson eimJson) { if (espidfMainTablePage == null) { espidfMainTablePage = new ESPIDFMainTablePage(); } - + + ESPIDFMainTablePage.eimJson = eimJson; return espidfMainTablePage; } - + public Composite createPage(Composite composite) { - toolSetConfigurationManager = new ToolSetConfigurationManager(); - idfToolSets = toolSetConfigurationManager.getIdfToolSets(true); + idfInstalledList = eimJson != null ? eimJson.getIdfInstalled() : null; container = new Composite(composite, SWT.NONE); final int numColumns = 2; GridLayout gridLayout = new GridLayout(numColumns, false); container.setLayout(gridLayout); + createButtonAndGuideLink(container); createIdfTable(container); return container; } + private void createButtonAndGuideLink(Composite composite) + { + Link guideLink = new Link(composite, SWT.WRAP); + guideLink.setText(Messages.IDFGuideLinkLabel_Text); + guideLink.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1)); + guideLink.addListener(SWT.Selection, e -> { + try + { + java.awt.Desktop.getDesktop() + .browse(new java.net.URI("https://dl.espressif.com/dl/esp-idf/support-periods.svg")); //$NON-NLS-1$ + } + catch (Exception ex) + { + Logger.log(ex); + } + }); + + eimLaunchBtn = new Button(composite, SWT.PUSH); + eimLaunchBtn.setText( + !toolInitializer.isEimInstalled() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); + eimLaunchBtn.addSelectionListener(new EimButtonLaunchListener(espidfMainTablePage, Display.getDefault(), + getConsoleStream(false), getConsoleStream(true))); + } + + public void setupInitialEspIdf() + { + if (idfInstalledList != null && idfInstalledList.size() == 1) + { + // activate the only available esp-idf first check if its not already active + Preferences scopedPreferenceStore = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); + if (!scopedPreferenceStore.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false)) + { + SetupToolsInIde setupToolsInIde = new SetupToolsInIde(idfInstalledList.get(0), eimJson, + getConsoleStream(true), getConsoleStream(false)); + SetupToolsJobListener toolsActivationJobListener = new SetupToolsJobListener(ESPIDFMainTablePage.this, + setupToolsInIde); + setupToolsInIde.addJobChangeListener(toolsActivationJobListener); + setupToolsInIde.schedule(); + } + } + } + public void refreshEditorUI() { if (container == null) return; for (TableItem item : tableViewer.getTable().getItems()) { - String EDITOR_KEY = "action_editor"; - String EDITOR_KEY_LAST = "action_editor_last"; + String EDITOR_KEY = "action_editor"; //$NON-NLS-1$ + String EDITOR_KEY_LAST = "action_editor_last"; //$NON-NLS-1$ TableEditor editorFirst = (TableEditor) item.getData(EDITOR_KEY); TableEditor editorLast = (TableEditor) item.getData(EDITOR_KEY_LAST); if (editorFirst != null) @@ -114,43 +173,56 @@ public void refreshEditorUI() editorFirst.dispose(); // Dispose the editor itself item.setData(EDITOR_KEY, null); // Clear the stored editor reference } - + if (editorLast != null) { if (editorLast.getEditor() != null && !editorLast.getEditor().isDisposed()) { editorLast.getEditor().dispose(); } - + editorLast.dispose(); item.setData(EDITOR_KEY_LAST, null); } } - toolSetConfigurationManager.setReload(true); - idfToolSets = toolSetConfigurationManager.getIdfToolSets(true); + try + { + try + { + eimJson = eimIdfConfiguratinParser.getEimJson(true); + } + catch (EimVersionMismatchException e) + { + Logger.log(e); + MessageDialog.openError(Display.getDefault().getActiveShell(), e.msgTitle(), e.getMessage()); + } + // eimJson is null if EIM was closed before tool installation completed + if (eimJson == null) + { + return; + } + } + catch (IOException e) + { + Logger.log(e); + } + + idfInstalledList = eimJson.getIdfInstalled(); setupColumns(); - tableViewer.setInput(idfToolSets); + tableViewer.setInput(idfInstalledList); tableViewer.getControl().requestLayout(); tableViewer.refresh(); + eimLaunchBtn.setText( + !toolInitializer.isEimInstalled() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); container.redraw(); - toolSetConfigurationManager.setReload(false); - - if (idfToolSets == null || idfToolSets.isEmpty()) - { - removeAllButton.setEnabled(false); - } - else - { - removeAllButton.setEnabled(true); - } } private Composite createIdfTable(Composite parent) { Group idfToolsGroup = new Group(parent, SWT.SHADOW_ETCHED_IN); - idfToolsGroup.setText("IDF Tools"); + idfToolsGroup.setText("IDF Tools"); //$NON-NLS-1$ idfToolsGroup.setLayout(new GridLayout(2, false)); - idfToolsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + idfToolsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); // Composite for the TableViewer, with TableColumnLayout tableComposite = new Composite(idfToolsGroup, SWT.NONE); @@ -159,13 +231,13 @@ private Composite createIdfTable(Composite parent) tableComposite.setLayout(tableColumnLayout); tableViewer = new TableViewer(tableComposite, SWT.BORDER | SWT.H_SCROLL); tableViewer.setContentProvider(ArrayContentProvider.getInstance()); - + Table table = tableViewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(true); table.addListener(SWT.MeasureItem, event -> { - event.height = 25; - }); + event.height = 25; + }); comparator = new ColumnViewerComparator(); tableViewer.setComparator(comparator); setupColumns(); @@ -173,120 +245,74 @@ private Composite createIdfTable(Composite parent) e.height = 30; }); - tableViewer.setInput(toolSetConfigurationManager.getIdfToolSets(true)); + tableViewer.setInput(idfInstalledList); table.layout(); // Composite for the "Add" button - Composite buttonComposite = new Composite(idfToolsGroup, SWT.NONE); - GridData buttonCompositeGridData = new GridData(SWT.RIGHT, SWT.CENTER, false, false); - buttonCompositeGridData.verticalAlignment = SWT.TOP; // Aligns the button composite at the top - buttonComposite.setLayoutData(buttonCompositeGridData); - buttonComposite.setLayout(new GridLayout(1, true)); - - // Creating the "Add" button - Button addButton = new Button(buttonComposite, SWT.PUSH); - addButton.setText(Messages.EspIdfManagerAddToolsBtn); - GridData addButtonGridData = new GridData(SWT.FILL, SWT.CENTER, true, false); - addButton.setLayoutData(addButtonGridData); - addButton.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - IDFNewToolsWizard wizard = new IDFNewToolsWizard(ESPIDFMainTablePage.this); - wizard.setWindowTitle(Messages.IDFDownloadHandler_ESPIDFConfiguration); - WizardDialog wizDialog = new WizardDialog(container.getShell(), wizard); - wizDialog.create(); - - wizDialog.setTitle(Messages.IDFDownloadHandler_DownloadPage_Title); - wizDialog.setMessage(Messages.IDFDownloadHandler_DownloadPageMsg); - wizDialog.getShell().setSize(Math.max(850, wizDialog.getShell().getSize().x), 550); + Composite buttonComposite = new Composite(idfToolsGroup, SWT.NONE); + GridData buttonCompositeGridData = new GridData(SWT.RIGHT, SWT.CENTER, false, false); + buttonCompositeGridData.verticalAlignment = SWT.TOP; // Aligns the button composite at the top + buttonComposite.setLayoutData(buttonCompositeGridData); + buttonComposite.setLayout(new GridLayout(1, true)); - wizDialog.open(); - } - }); - - removeAllButton = new Button(buttonComposite, SWT.PUSH); - removeAllButton.setText(Messages.EspIdfManagerRemoveAllBtn); - removeAllButton.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), - SWT.ICON_WARNING | SWT.YES | SWT.NO); - messageBox.setMessage(Messages.EspIdfManagerMessageBoxDeleteAllConfirmMessage); - messageBox.setText(Messages.EspIdfManagerMessageBoxDeleteAllConfirmMessageTitle); - int response = messageBox.open(); - if (response == SWT.YES) - { - for(IDFToolSet idfToolSet : idfToolSets) - { - toolSetConfigurationManager.delete(idfToolSet); - } - refreshEditorUI(); - } - } - }); - - GridData removeAllButtonGridData = new GridData(SWT.FILL, SWT.CENTER, true, false); - removeAllButton.setLayoutData(removeAllButtonGridData); - if (idfToolSets == null || idfToolSets.isEmpty()) - { - removeAllButton.setEnabled(false); - } - else - { - removeAllButton.setEnabled(true); - } - return idfToolsGroup; } - + private void disposeColumns() { if (activateColumn != null && activateColumn.getColumn() != null) { activateColumn.getColumn().dispose(); } - + if (versionColumn != null && versionColumn.getColumn() != null) { versionColumn.getColumn().dispose(); } - + if (locationColumn != null && locationColumn.getColumn() != null) { locationColumn.getColumn().dispose(); } - + if (removeColumn != null && removeColumn.getColumn() != null) { removeColumn.getColumn().dispose(); } + + if (nameColumn != null && nameColumn.getColumn() != null) + { + nameColumn.getColumn().dispose(); + } } private void setupColumns() { disposeColumns(); int colIndex = 0; - + activateColumn = new TableViewerColumn(tableViewer, SWT.NONE); activateColumn.getColumn().setText(Messages.EspIdfManagerActivateCol); activateColumn.setLabelProvider(new IdfManagerTableColumnLabelProvider()); tableColumnLayout.setColumnData(activateColumn.getColumn(), new ColumnWeightData(2, 5, true)); - + versionColumn = new TableViewerColumn(tableViewer, SWT.NONE); versionColumn.getColumn().setText(Messages.EspIdfManagerVersionCol); versionColumn.setLabelProvider(new IdfManagerTableColumnLabelProvider()); setComparatorForCols(versionColumn, colIndex++); tableColumnLayout.setColumnData(versionColumn.getColumn(), new ColumnWeightData(3, 50, true)); + nameColumn = new TableViewerColumn(tableViewer, SWT.NONE); + nameColumn.getColumn().setText(Messages.EspIdfManagerNameCol); + nameColumn.setLabelProvider(new IdfManagerTableColumnLabelProvider()); + setComparatorForCols(nameColumn, colIndex++); + tableColumnLayout.setColumnData(nameColumn.getColumn(), new ColumnWeightData(3, 50, true)); + locationColumn = new TableViewerColumn(tableViewer, SWT.NONE); locationColumn.getColumn().setText(Messages.EspIdfManagerLocationCol); locationColumn.setLabelProvider(new IdfManagerTableColumnLabelProvider()); setComparatorForCols(locationColumn, colIndex++); tableColumnLayout.setColumnData(locationColumn.getColumn(), new ColumnWeightData(10, 100, true)); - + removeColumn = new TableViewerColumn(tableViewer, SWT.NONE); removeColumn.setLabelProvider(new IdfManagerTableColumnLabelProvider()); tableColumnLayout.setColumnData(removeColumn.getColumn(), new ColumnWeightData(3, 100, true)); @@ -318,36 +344,23 @@ public void widgetSelected(SelectionEvent e) } - private void performDeleteOperation(IDFToolSet idfToolSet) - { - MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), - SWT.ICON_WARNING | SWT.YES | SWT.NO); - messageBox.setMessage(MessageFormat.format(Messages.EspIdfManagerMessageBoxDeleteConfirmMessage, idfToolSet.getIdfVersion())); - messageBox.setText(Messages.EspIdfManagerMessageBoxDeleteConfirmMessageTitle); - int response = messageBox.open(); - if (response == SWT.YES) - { - toolSetConfigurationManager.delete(idfToolSet); - } - } - private class IdfManagerTableColumnLabelProvider extends ColumnLabelProvider { private Color activeBackgroundColor; - + private IdfManagerTableColumnLabelProvider() { super(); this.activeBackgroundColor = new Color(Display.getCurrent(), 144, 238, 144); } - + @Override public Color getBackground(Object element) { - if (element instanceof IDFToolSet) + if (element instanceof IdfInstalled) { - IDFToolSet idfToolSet = (IDFToolSet) element; - if (idfToolSet.isActive()) + IdfInstalled idfInstalled = (IdfInstalled) element; + if (ToolsUtility.isIdfInstalledActive(idfInstalled)) { // Return the green color for active rows return activeBackgroundColor; @@ -374,7 +387,7 @@ else if (isLastCol) { updateDataIntoCells(cell); } - + Color color = getBackground(cell.getElement()); if (color != null) { @@ -384,31 +397,40 @@ else if (isLastCol) private void updateDataIntoCells(ViewerCell cell) { - if ((!(cell.getElement() instanceof IDFToolSet)) && cell.getElement() == null) + if ((!(cell.getElement() instanceof IdfInstalled)) && cell.getElement() == null) return; - IDFToolSet idfToolSet = (IDFToolSet) cell.getElement(); + IdfInstalled idfInstalled = (IdfInstalled) cell.getElement(); switch (cell.getColumnIndex()) { case 0: break; case 1: - cell.setText(idfToolSet.getIdfVersion()); + cell.setText(getIdfVersion(idfInstalled)); break; case 2: - cell.setText(idfToolSet.getIdfLocation()); + cell.setText(idfInstalled.getName()); break; case 3: + cell.setText(idfInstalled.getPath()); + break; + case 4: break; } } + private String getIdfVersion(IdfInstalled idfInstalled) + { + String version = ToolsUtility.getIdfVersion(idfInstalled, eimJson.getGitPath()); + return version; + } + private void createButtonsForFirstCol(ViewerCell cell) { TableItem item = (TableItem) cell.getItem(); - + // using a unique key to store the editor to avoid creating multiple editors for the same cell - String EDITOR_KEY = "action_editor"; + String EDITOR_KEY = "action_editor"; //$NON-NLS-1$ if (item.getData(EDITOR_KEY) != null) { return; // This cell already has an editor @@ -417,31 +439,31 @@ private void createButtonsForFirstCol(ViewerCell cell) Composite buttonComposite = new Composite(tableViewer.getTable(), SWT.NONE); buttonComposite.setLayout(new FillLayout()); item.setData(EDITOR_KEY, editor); - IDFToolSet idfToolSet = (IDFToolSet) cell.getElement(); + IdfInstalled idfInstalled = (IdfInstalled) cell.getElement(); Button setActiveButton = new Button(buttonComposite, SWT.RADIO); - setActiveButton.setSelection(idfToolSet.isActive()); - setActiveButton.setData(IDF_TOOL_SET_BTN_KEY, idfToolSet); + setActiveButton.setSelection(ToolsUtility.isIdfInstalledActive(idfInstalled)); + setActiveButton.setData(IDF_TOOL_SET_BTN_KEY, idfInstalled); setActiveButton.addListener(SWT.Selection, e -> { Button btn = (Button) e.widget; - ToolsActivationJob toolsActivationJob = new ToolsActivationJob((IDFToolSet) btn.getData(IDF_TOOL_SET_BTN_KEY), - null, null); - ToolsActivationJobListener toolsActivationJobListener = new ToolsActivationJobListener( - ESPIDFMainTablePage.this); - toolsActivationJob.addJobChangeListener(toolsActivationJobListener); - toolsActivationJob.schedule(); + SetupToolsInIde setupToolsInIde = new SetupToolsInIde(idfInstalled, eimJson, getConsoleStream(true), + getConsoleStream(false)); + SetupToolsJobListener toolsActivationJobListener = new SetupToolsJobListener(ESPIDFMainTablePage.this, + setupToolsInIde); + setupToolsInIde.addJobChangeListener(toolsActivationJobListener); + setupToolsInIde.schedule(); btn.setEnabled(false); }); editor.grabHorizontal = true; editor.setEditor(buttonComposite, item, cell.getColumnIndex()); } - + private void createButtonsForLastCol(ViewerCell cell) { TableItem item = (TableItem) cell.getItem(); Rectangle cellBounds = cell.getBounds(); // using a unique key to store the editor to avoid creating multiple editors for the same cell - String EDITOR_KEY = "action_editor_last"; + String EDITOR_KEY = "action_editor_last"; //$NON-NLS-1$ if (item.getData(EDITOR_KEY) != null) { return; // This cell already has an editor @@ -452,58 +474,44 @@ private void createButtonsForLastCol(ViewerCell cell) buttonComposite.setLayout(fillLayout); buttonComposite.redraw(); item.setData(EDITOR_KEY, editor); - IDFToolSet idfToolSet = (IDFToolSet) cell.getElement(); - + IdfInstalled idfInstalled = (IdfInstalled) cell.getElement(); + int buttonHeight = Math.min(cellBounds.height - 6, 30); - - if (idfToolSet.isActive()) + + if (ToolsUtility.isIdfInstalledActive(idfInstalled)) { Button reloadButton = new Button(buttonComposite, SWT.PUSH | SWT.FLAT); reloadButton.pack(); - reloadButton.setData(IDF_TOOL_SET_BTN_KEY, idfToolSet); + reloadButton.setData(IDF_TOOL_SET_BTN_KEY, idfInstalled); reloadButton.setImage(UIPlugin.getImage(RELOAD_ICON)); reloadButton.setToolTipText(Messages.EspIdfManagerReloadBtnToolTip); reloadButton.addListener(SWT.Selection, e -> { Button btn = (Button) e.widget; - IDFToolSet selectedToolSet = (IDFToolSet) btn.getData(IDF_TOOL_SET_BTN_KEY); - ToolsActivationJob toolsActivationJob = new ToolsActivationJob(selectedToolSet, IDFUtil.getPythonExecutable(), IDFUtil.getGitExecutablePathFromSystem()); - ToolsActivationJobListener toolsActivationJobListener = new ToolsActivationJobListener(ESPIDFMainTablePage.this); - toolsActivationJob.addJobChangeListener(toolsActivationJobListener); - toolsActivationJob.schedule(); + IdfInstalled selectedToolSet = (IdfInstalled) btn.getData(IDF_TOOL_SET_BTN_KEY); + SetupToolsInIde setupToolsInIde = new SetupToolsInIde(selectedToolSet, eimJson, + getConsoleStream(true), getConsoleStream(false)); + SetupToolsJobListener toolsActivationJobListener = new SetupToolsJobListener( + ESPIDFMainTablePage.this, setupToolsInIde); + setupToolsInIde.addJobChangeListener(toolsActivationJobListener); + setupToolsInIde.schedule(); }); - + reloadButton.setSize(cellBounds.width, buttonHeight); - reloadButton.addListener(SWT.Paint, e-> e.gc.drawRectangle(reloadButton.getBounds())); + reloadButton.addListener(SWT.Paint, e -> e.gc.drawRectangle(reloadButton.getBounds())); reloadButton.redraw(); } - Button removeButton = new Button(buttonComposite, SWT.PUSH | SWT.FLAT); - removeButton.pack(); - removeButton.setData(IDF_TOOL_SET_BTN_KEY, idfToolSet); - removeButton.setImage(UIPlugin.getImage(REMOVE_ICON)); - removeButton.setToolTipText(Messages.EspIdfManagerDeleteBtnToolTip); - removeButton.addListener(SWT.Selection, e -> { - Button btn = (Button) e.widget; - IDFToolSet selectedToolSet = (IDFToolSet) btn.getData(IDF_TOOL_SET_BTN_KEY); - performDeleteOperation(selectedToolSet); - refreshEditorUI(); - }); - removeButton.setSize(cellBounds.width, buttonHeight); - removeButton.redraw(); - editor.grabHorizontal = true; editor.grabVertical = true; editor.horizontalAlignment = SWT.CENTER; editor.verticalAlignment = SWT.CENTER; - editor.minimumHeight = removeButton.getSize().y; - editor.minimumWidth = removeButton.getSize().x; editor.setEditor(buttonComposite, item, cell.getColumnIndex()); buttonComposite.layout(true, true); buttonComposite.redraw(); editor.layout(); - tableViewer.getTable().layout(true, true); + tableViewer.getTable().layout(true, true); } - + @Override public void dispose() { @@ -515,6 +523,12 @@ public void dispose() } } + private MessageConsoleStream getConsoleStream(boolean errorStream) + { + IDFConsole idfConsole = new IDFConsole(); + return idfConsole.getConsoleStream(Messages.IDFToolsHandler_ToolsManagerConsole, null, errorStream, true); + } + private class ColumnViewerComparator extends ViewerComparator { private int propertyIndex; @@ -545,20 +559,20 @@ public void setColumn(int column) @Override public int compare(Viewer viewer, Object e1, Object e2) { - IDFToolSet p1 = (IDFToolSet) e1; - IDFToolSet p2 = (IDFToolSet) e2; + IdfInstalled p1 = (IdfInstalled) e1; + IdfInstalled p2 = (IdfInstalled) e2; int rc = 0; switch (propertyIndex) { case 0: - rc = p1.getIdfVersion().compareTo(p2.getIdfVersion()); + rc = p1.getName().compareTo(p2.getName()); break; case 1: - rc = p1.getIdfLocation().compareTo(p2.getIdfLocation()); + rc = p1.getPath().compareTo(p2.getPath()); break; case 2: - Boolean p1State = p1.isActive(); - Boolean p2State = p2.isActive(); + Boolean p1State = ToolsUtility.isIdfInstalledActive(p1); + Boolean p2State = ToolsUtility.isIdfInstalledActive(p2); rc = p1State.compareTo(p2State); break; default: diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties index 8d40d45dd..1a3663fb5 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties @@ -1,132 +1,15 @@ -#Eclipse modern messages class -#Wed May 18 13:39:42 CEST 2022 -SizeDescriptionText=Size: -RemoveToolMessageBox=Do you want to delete the selected tools? -RemoveToolMessageBoxFinish=Do you want to continue or finish the changes? -SystemPathMessage=System Path: -ToolsTreeSizeCol=Size (MB) -FilterTargets=Filter Chips -UrlDescriptionText=URL: -ToolsTreeNameCol=Name -Available=Available -InstallPreRquisitePage=Install Prerequisites -ManageToolsInstallationDescription=Here you can install tools available with the selected IDF version -InstallEspIdfPage_lblEspidfPath_text=ESP-IDF Path: -ManageToolsInstallation=Tools Installation -InstallToolsText=Install Tools -InstallEspIdfPage_lblEspidfVersion_text=ESP-IDF Version: -InstallEspIdfPage_btnDownload_text=Download -Warning=Warning -ExtractionTextMessage=Extracting file: -PreviousToolMessage=Previous Tool Path: -DeselectAllButton=Deselect All -DeselectAllButtonToolTip=Deselect all tools -GitLabel=Git: -DirectorySelectionDialog_IDFDirLabel=ESP-IDF Directory: -ToolsManagerShellHeading=Manage Tools Installation -ToolsManagerWizard=Tools Installation Wizard -InstallEspIdfPage_Existing=Existing -InstallEspIdfPageDescription=Download ESP-IDF or select an existing version -ToolsTreeStatusCol=Status -SupportedTargetsDescriptionText=Supported Targets: -DownloadFileText=Downloading File: -SelectRecommended=Select Recommended -SelectRecommendedToolTip=Selects recommended tools only -DeleteToolsText=Delete Tools -DeleteToolsTextToolTip=Delete selected tools. Make sure not to delete the recommended tools for proper working -FileSelectionDialogTitle=Select tool executable file -DirectorySelectionDialog_SelectIDFDirMessage=Select ESP-IDF Directory: -FilterLabel=Type below to filter -Installed=Installed -DescriptionText=Description -ShowAvailableVersionsOnly=Show Available Versions Only -UpdateToolPathMessage=Updated Tool Path: -ManageToolsInstallationShell_mntmNewItem_text=New Item -ExtractionCompletedMessage=Extraction Completed -InstallEspIdfPage_btnNew_text=New -InstallEspIdfPage=Install ESP-IDF -ManageToolsInstallationShell_tltmCheckItem_text=Check Item -InstallEspIdfPage_lblDownloadDirectory_text=Download Directory: -NotInstalled=Not Installed -RemoveToolMessageBoxTitle=Confirmation -UpdatingPathMessage=Updating PATH -PythonLabel=Python: -InstallToolsPreReqPageDescription=Set path for the required tools here -DownloadProgressText=Download Progress: -InstallPreRquisitePage_lblLog_text=Log -BrowseButton=Browse -SelectPythonVersion=Select Python Version -SelectAllButton=Select All -SelectAllButtonToolTip=Select all tools -RemovedPathMessage=Removed Path: -InstallingToolMessage=Installing Tool: -SelectDownloadDir=Select the directory to download ESP-IDF Tools -GitCloningJobMsg=Cloning ESP-IDF {0}... -CloningCompletedMsg=Cloning completed... -IDFDownloadWizard_DownloadingMessage=Downloading {0}... -IDFDownloadWizard_DownloadCompleteMsg={0} download completed! -IDFDownloadWizard_DecompressingMsg=Extracting downloaded archive... -IDFDownloadWizard_DecompressingCompleted=Archive extracted! -IDFDownloadWizard_UpdatingIDFPathMessage=Updating IDF_PATH to: {0} -BtnCancel=Cancel -OperationCancelledByUser=Operation is cancelled by the user! -InstallToolsHandler_CopyingOpenOCDRules=Copying OpenOCD Rules -InstallToolsHandler_OpenOCDRulesCopied=Rules Copied to system -InstallToolsHandler_OpenOCDRulesNotCopied=Rules Not Copied to system -InstallToolsHandler_OpenOCDRulesCopyPaths=Copying File: %s to destination: %s -InstallToolsHandler_OpenOCDRulesCopyError=Unable to copy rules for OpenOCD to system directory, try running the eclipse with sudo command -InstallToolsHandler_OpenOCDRulesCopyWarning=Warning -InstallToolsHandler_OpenOCDRulesCopyWarningMessage=The rules file is already present in the /etc/udev/rules.d/ directory, Do you want to replace the file with the file from OpenOCD directory -AbstractToolsHandler_ExecutingMsg=Executing -ToolAreadyPresent=Tool already present in ESPRESSIF home directory. -ForceDownloadToolTip=Downloads the tools again even if they are already downloaded in ESPRESSIF home directory. -ForceDownload=Force Download -InstallToolsProgressShell_lblNewLabel_text=Tool Being Installed -ToolsTreeHeading=Tools Tree -DownloadFileText=Downloading File: -ExtractionTextMessage=Extracting file: -InstallingToolMessage=Installing Tool: -UpdatingPathMessage=Updating PATH -PreviousToolMessage=Previous Tool Path: -UpdateToolPathMessage=Updated Tool Path: -SystemPathMessage=System Path: -ExtractionCompletedMessage=Extraction Completed -RemovedPathMessage=Removed Path: -RemoveToolMessageBox=Do you want to delete the selected tools? -RemoveToolMessageBoxTitle=Confirmation -SelectAllButton=Select All -RemovedPathMessage=Removed Path: -InstallingToolMessage=Installing Tool: -SelectDownloadDir=Select the directory to download ESP-IDF Tools -GitCloningJobMsg=Cloning ESP-IDF {0}... -CloningCompletedMsg=Cloning completed... -IDFDownloadWizard_DownloadingMessage=Downloading {0}... -IDFDownloadWizard_DownloadCompleteMsg={0} download completed! -IDFDownloadWizard_DecompressingMsg=Extracting downloaded archive... -IDFDownloadWizard_DecompressingCompleted=Archive extracted! -IDFDownloadWizard_UpdatingIDFPathMessage=Updating IDF_PATH to: {0} -FilterTargetBoxToolTip=Filter the tools based on the target selection of ESP chips -ShowAvailableVersionsOnlyToolTip=Shows the versions that are available already and downloaded. The versions should be in the espressif home directory to be visible with this. -MissingToolsValidationMessage_A=Following required tools are missing: -MissingToolsValidationMessage_B=Please visit the Link to see configuration for these tools -MissingToolsValidationLink=https://github.com/espressif/idf-eclipse-plugin/blob/master/docs_readme/MissingToolsManualPathUpdateGuide.md - - EspIdfEditorTitle=ESP-IDF Manager EspIdfManagerVersionCol=ESP-IDF Version EspIdfManagerLocationCol=Location -EspIdfManagerStateCol=State EspIdfManagerActivateCol=Active -EspIdfManagerAddToolsBtn=Add ESP-IDF -EspIdfManagerRemoveAllBtn=Remove All -EspIdfManagerDeleteBtn=Delete -EspIdfManagerMessageBoxDeleteConfirmMessage=Do you want to remove the toolchain with ESP-IDF version: {0} -EspIdfManagerMessageBoxDeleteConfirmMessageTitle=Confirm Remove -EspIdfManagerMessageBoxDeleteAllConfirmMessage=Do you want to remove all ESP-IDF versions from IDE -EspIdfManagerMessageBoxDeleteAllConfirmMessageTitle=Remove All ESP-IDF Versions +EspIdfManagerNameCol=Name EspIdfManagerReloadBtnToolTip=Reload from disk -EspIdfManagerDeleteBtnToolTip=Delete ESP-IDF version from IDE - -IDFDownloadHandler_ESPIDFConfiguration=ESP-IDF Configuration -IDFDownloadHandler_DownloadPage_Title=Download or use ESP-IDF -IDFDownloadHandler_DownloadPageMsg=Please choose ESP-IDF version to download, or use an existing ESP-IDF copy \ No newline at end of file +IDFToolsHandler_ToolsManagerConsole=Espressif IDF Tools Console +IDFGuideLinkLabel_Text=Select the version of ESP-IDF you want to use. Click the radio button in Active column next to the version you want. For help in choosing the correct version, visit ESP-IDF Version Guide. +EIMButtonDownloadText=Download and Launch EIM +EIMButtonLaunchText=Launch EIM +EimJsonChangedMsgTitle=ESP-IDF Installation Changed +EimJsonChangedMsgDetail=It seems that the ESP-IDF tools have been modified. If you just installed ESP-IDF we recommend refereshing via ESP-IDF Manager . Would you like to proceed with the update? +EimJsonStateChangedMsgDetail=It looks like the ESP-IDF installation was modified since last start. The Espressif IDE cannot guarantee the consistency. Kindly refresh the installation via ESP-IDF Manager. +MsgYes=Yes +MsgNo=No diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/watcher/EimJsonUiChangeHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/watcher/EimJsonUiChangeHandler.java new file mode 100644 index 000000000..b85aab250 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/watcher/EimJsonUiChangeHandler.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui.tools.watcher; + +import java.io.IOException; +import java.nio.file.Path; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.console.MessageConsoleStream; +import org.eclipse.ui.ide.IDE; +import org.osgi.service.prefs.Preferences; + +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.EimIdfConfiguratinParser; +import com.espressif.idf.core.tools.SetupToolsInIde; +import com.espressif.idf.core.tools.exceptions.EimVersionMismatchException; +import com.espressif.idf.core.tools.vo.EimJson; +import com.espressif.idf.core.tools.watcher.EimJsonChangeListener; +import com.espressif.idf.core.tools.watcher.EimJsonStateChecker; +import com.espressif.idf.ui.EclipseUtil; +import com.espressif.idf.ui.GlobalModalLock; +import com.espressif.idf.ui.IDFConsole; +import com.espressif.idf.ui.handlers.EclipseHandler; +import com.espressif.idf.ui.tools.Messages; +import com.espressif.idf.ui.tools.SetupToolsJobListener; +import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; +import com.espressif.idf.ui.tools.manager.EimEditorInput; +import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; + +/** + * eim_idf.json file ui change handler to notify user for changes. + * + * @author Ali Azam Rana + * + */ +public class EimJsonUiChangeHandler implements EimJsonChangeListener +{ + private Preferences preferences; + private EimJson eimJson; + + public EimJsonUiChangeHandler(Preferences preferences) + { + this.preferences = preferences; + } + + @Override + public void onJsonFileChanged(Path file, boolean paused) + { + if (paused) + { + Logger.log("Listener is paused"); + return; + } + displayMessageToUser(); + } + + public void displayMessageToUser() + { + GlobalModalLock.showModal(() -> MessageDialog.openQuestion(EclipseUtil.getShell(), + Messages.EimJsonChangedMsgTitle, Messages.EimJsonChangedMsgDetail), t -> { + try + { + handleUserResponse(t); + } + catch (EimVersionMismatchException e) + { + MessageDialog.openError(EclipseUtil.getShell(), e.msgTitle(), e.getMessage()); + Logger.log(e); + } + }); + } + + public void handleUserResponse(Boolean response) throws EimVersionMismatchException + { + if (response) + { + try + { + loadEimJson(); + if (eimJson.getIdfInstalled().size() == 1) + { + // only one entry in eimJson so we can simply refresh the IDE environment with that. + setupToolsInIde(); + } + else + { + // multiple entries in json so launch manager for user to handle this + Display.getDefault().asyncExec(() -> { + try + { + launchEspIdfManager(); + } + catch (PartInitException e) + { + Logger.log(e); + } + ESPIDFMainTablePage.getInstance(eimJson).refreshEditorUI(); + }); + } + } + catch (IOException e) + { + Logger.log(e); + } + } + + EimJsonStateChecker checker = new EimJsonStateChecker(preferences); + checker.updateLastSeenTimestamp(); + } + + private void loadEimJson() throws IOException, EimVersionMismatchException + { + EimIdfConfiguratinParser eimIdfConfiguratinParser = new EimIdfConfiguratinParser(); + eimJson = eimIdfConfiguratinParser.getEimJson(true); + } + + private void setupToolsInIde() + { + SetupToolsInIde setupToolsInIde = new SetupToolsInIde(eimJson.getIdfInstalled().get(0), eimJson, + getConsoleStream(true), getConsoleStream(false)); + SetupToolsJobListener toolsActivationJobListener = new SetupToolsJobListener( + ESPIDFMainTablePage.getInstance(eimJson), setupToolsInIde); + setupToolsInIde.addJobChangeListener(toolsActivationJobListener); + setupToolsInIde.schedule(); + } + + private void launchEspIdfManager() throws PartInitException + { + Display.getDefault().asyncExec(() -> { + IWorkbenchWindow activeww = EclipseHandler.getActiveWorkbenchWindow(); + if (activeww == null || activeww.getActivePage() == null) + { + Logger.log("Cannot open ESP-IDF Manager. No active workbench window or active page."); + return; + } + + try + { + IDE.openEditor(activeww.getActivePage(), new EimEditorInput(eimJson), ESPIDFManagerEditor.EDITOR_ID, + true); + } + catch (PartInitException e) + { + Logger.log("Failed to open ESP-IDF Manager Editor."); + Logger.log(e); + } + }); + + } + + private MessageConsoleStream getConsoleStream(boolean errorStream) + { + IDFConsole idfConsole = new IDFConsole(); + return idfConsole.getConsoleStream(Messages.IDFToolsHandler_ToolsManagerConsole, null, errorStream, true); + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tracing/AppLvlTracingDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tracing/AppLvlTracingDialog.java index b9ee9d677..1cd6fc8ad 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tracing/AppLvlTracingDialog.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tracing/AppLvlTracingDialog.java @@ -298,7 +298,7 @@ private void runTraceCommand() try { List arguments = new ArrayList(Arrays.asList(parseCommandTxt.getText().split(" "))); //$NON-NLS-1$ - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); IStatus status = processRunner.runInBackground(arguments, Path.ROOT, environment); if (status == null) { diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/AbstractToolsHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/AbstractToolsHandler.java index 49a6a99c8..aa0b7fdb6 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/AbstractToolsHandler.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/AbstractToolsHandler.java @@ -16,7 +16,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.window.Window; @@ -24,7 +23,6 @@ import org.eclipse.ui.console.MessageConsoleStream; import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFCorePreferenceConstants; import com.espressif.idf.core.IDFEnvironmentVariables; import com.espressif.idf.core.ProcessBuilderFactory; import com.espressif.idf.core.SystemExecutableFinder; @@ -143,20 +141,10 @@ protected IStatus runCommand(List arguments, MessageConsoleStream consol console.println(cmdMsg); Logger.log(cmdMsg); - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); + Map environment = new HashMap<>(System.getenv()); Logger.log(environment.toString()); environment.put("PYTHONUNBUFFERED", "1"); //$NON-NLS-1$ //$NON-NLS-2$ - environment.put("IDF_GITHUB_ASSETS", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS, - IDFCorePreferenceConstants.IDF_GITHUB_ASSETS_DEFAULT_GLOBAL, null)); - - environment.put("PIP_EXTRA_INDEX_URL", //$NON-NLS-1$ - Platform.getPreferencesService().getString(IDFCorePlugin.PLUGIN_ID, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL, - IDFCorePreferenceConstants.PIP_EXTRA_INDEX_URL_DEFAULT_GLOBAL, null)); - if (gitExecutablePath != null) { addGitToEnvironment(environment, gitExecutablePath); diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/ExportIDFTools.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/ExportIDFTools.java deleted file mode 100644 index 6a6b6a6eb..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/ExportIDFTools.java +++ /dev/null @@ -1,292 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.update; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.osgi.util.NLS; -import org.eclipse.ui.console.MessageConsoleStream; - -import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.ProcessBuilderFactory; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.StringUtil; - -/** - * @author Kondal Kolipaka - * - * Run /tools/idf_tools.py export command - * - */ -public class ExportIDFTools -{ - /** - * @param pythonExePath python executable full path - * @param gitExePath git executable full path - * @param console Console stream to write messages - * @param errorConsoleStream - */ - public IStatus runToolsExportAndProcessOutput(final String pythonExePath, final String gitExePath, final MessageConsoleStream console, MessageConsoleStream errorConsoleStream) - { - final List arguments = getExportCommand(pythonExePath); - - final String cmd = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); //$NON-NLS-1$ - log(cmd, console); - - final Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - if (gitExePath != null) - { - addGitToEnvironment(environment, gitExePath); - } - final ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - try - { - final IStatus status = processRunner.runInBackground(arguments, Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Status can't be null", null)); //$NON-NLS-1$ - return IDFCorePlugin.errorStatus("Status can't be null", null); //$NON-NLS-1$ - } - - if (status.getSeverity() == IStatus.ERROR) - { - log(status.getException() != null ? status.getException().getMessage() : status.getMessage(), errorConsoleStream); - return status; - } - - // process export command output - final String exportCmdOp = status.getMessage(); - log(exportCmdOp, console); - processExportCmdOutput(exportCmdOp, gitExePath); - - return status; - } - catch (IOException e1) - { - Logger.log(IDFCorePlugin.getPlugin(), e1); - return IDFCorePlugin.errorStatus(e1.getMessage(), e1); - } - } - - public IStatus getToolsExportOutput(final String pythonExePath, final String gitExePath, final MessageConsoleStream console, MessageConsoleStream errorConsoleStream) - { - final List arguments = getExportCommand(pythonExePath); - - final String cmd = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); //$NON-NLS-1$ - log(cmd, console); - - final Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - if (gitExePath != null) - { - addGitToEnvironment(environment, gitExePath); - } - final ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - try - { - final IStatus status = processRunner.runInBackground(arguments, Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Status can't be null", null)); //$NON-NLS-1$ - return IDFCorePlugin.errorStatus("Status can't be null", null); //$NON-NLS-1$ - } - - if (status.getSeverity() == IStatus.ERROR) - { - log(status.getException() != null ? status.getException().getMessage() : status.getMessage(), errorConsoleStream); - return status; - } - - return status; - } - catch (IOException e) - { - Logger.log(IDFCorePlugin.getPlugin(), e); - return IDFCorePlugin.errorStatus(e.getMessage(), e); - } - } - - public IStatus getToolsExportOutputFromGivenIdfPath(final String pythonExePath, final String gitExePath, - final MessageConsoleStream console, MessageConsoleStream errorConsoleStream, final String idfPath) - { - final List arguments = getExportCommandUsingGivenIdfPath(pythonExePath, idfPath); - - final String cmd = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); //$NON-NLS-1$ - log(cmd, console); - - final Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - if (gitExePath != null) - { - addGitToEnvironment(environment, gitExePath); - } - - final ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - try - { - final IStatus status = processRunner.runInBackground(arguments, Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Status can't be null", null)); //$NON-NLS-1$ - return IDFCorePlugin.errorStatus("Status can't be null", null); //$NON-NLS-1$ - } - - if (status.getSeverity() == IStatus.ERROR) - { - log(status.getException() != null ? status.getException().getMessage() : status.getMessage(), errorConsoleStream); - return status; - } - - return status; - } - catch (IOException e) - { - Logger.log(IDFCorePlugin.getPlugin(), e); - return IDFCorePlugin.errorStatus(e.getMessage(), e); - } - } - - private List getExportCommandUsingGivenIdfPath(String pythonExePath, String idfPath) - { - final List arguments = new ArrayList<>(); - arguments.add(pythonExePath); - arguments.add(IDFUtil.getIDFToolsScriptFile(idfPath).getAbsolutePath()); - arguments.add(IDFConstants.TOOLS_EXPORT_CMD); - arguments.add(IDFConstants.TOOLS_EXPORT_CMD_FORMAT_VAL); - return arguments; - } - - private List getExportCommand(String pythonExePath) - { - final List arguments = new ArrayList<>(); - arguments.add(pythonExePath); - arguments.add(IDFUtil.getIDFToolsScriptFile().getAbsolutePath()); - arguments.add(IDFConstants.TOOLS_EXPORT_CMD); - arguments.add(IDFConstants.TOOLS_EXPORT_CMD_FORMAT_VAL); - return arguments; - } - - private void log(final String cmd, final MessageConsoleStream console) - { - Logger.log(cmd); - if (console != null) - { - console.println(cmd); - } - } - - private String getCommandString(final List arguments) - { - final StringBuilder builder = new StringBuilder(); - arguments.forEach(entry -> builder.append(entry + " ")); //$NON-NLS-1$ - - return builder.toString().trim(); - } - - private void processExportCmdOutput(final String exportCmdOp, final String gitExecutablePath) - { - // process export command output - final String[] exportEntries = exportCmdOp.split("\n"); //$NON-NLS-1$ - for (String entry : exportEntries) - { - entry = entry.replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ - String[] keyValue = entry.split("="); //$NON-NLS-1$ - if (keyValue.length == 2) // 0 - key, 1 - value - { - final String msg = MessageFormat.format("Key: {0} Value: {1}", keyValue[0], keyValue[1]); //$NON-NLS-1$ - Logger.log(msg); - - final IDFEnvironmentVariables idfEnvMgr = new IDFEnvironmentVariables(); - String key = keyValue[0]; - String value = keyValue[1]; - if (key.equals(IDFEnvironmentVariables.PATH)) - { - value = replacePathVariable(value); - value = appendGitToPath(value, gitExecutablePath); - } - - // add new or replace old entries - idfEnvMgr.addEnvVariable(key, value); - } - - } - } - - private String replacePathVariable(String value) - { - // Get system PATH - Map systemEnv = new HashMap<>(IDFUtil.getSystemEnv()); - String pathEntry = systemEnv.get("PATH"); //$NON-NLS-1$ - if (pathEntry == null) - { - pathEntry = systemEnv.get("Path"); // for Windows //$NON-NLS-1$ - if (pathEntry == null) // no idea - { - Logger.log(new Exception("No PATH found in the system environment variables")); //$NON-NLS-1$ - } - } - - if (!StringUtil.isEmpty(pathEntry)) - { - value = value.replace("$PATH", pathEntry); // macOS //$NON-NLS-1$ - value = value.replace("%PATH%", pathEntry); // Windows //$NON-NLS-1$ - } - return value; - } - - protected void addGitToEnvironment(Map envMap, String executablePath) - { - IPath gitPath = new Path(executablePath); - if (gitPath.toFile().exists()) - { - String gitDir = gitPath.removeLastSegments(1).toOSString(); - String path1 = envMap.get("PATH"); //$NON-NLS-1$ - String path2 = envMap.get("Path"); //$NON-NLS-1$ - if (!StringUtil.isEmpty(path1) && !path1.contains(gitDir)) // Git not found on the PATH environment - { - path1 = gitDir.concat(";").concat(path1); //$NON-NLS-1$ - envMap.put("PATH", path1); //$NON-NLS-1$ - } - else if (!StringUtil.isEmpty(path2) && !path2.contains(gitDir)) // Git not found on the Path environment - { - path2 = gitDir.concat(";").concat(path2); //$NON-NLS-1$ - envMap.put("Path", path2); //$NON-NLS-1$ - } - } - } - - /** - * Append the git directory to the existing CDT build environment PATH variable - * - * @param path CDT build environment PATH - * @param gitExecutablePath - * @return PATH value with git appended - */ - private String appendGitToPath(String path, String gitExecutablePath) - { - IPath gitPath = new Path(gitExecutablePath); - if (!gitPath.toFile().exists()) - { - Logger.log(NLS.bind("{0} doesn't exist", gitExecutablePath)); //$NON-NLS-1$ - return path; - } - - String gitDir = gitPath.removeLastSegments(1).toOSString(); // ../bin/git - if (!StringUtil.isEmpty(path) && !path.contains(gitDir)) // Git not found on the CDT build PATH environment - { - return path.concat(";").concat(gitDir); // append git path //$NON-NLS-1$ - } - return path; - } -} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/InstallToolsHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/InstallToolsHandler.java deleted file mode 100644 index 15ec76edf..000000000 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/update/InstallToolsHandler.java +++ /dev/null @@ -1,382 +0,0 @@ -/******************************************************************************* - * Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD. All rights reserved. - * Use is subject to license terms. - *******************************************************************************/ -package com.espressif.idf.ui.update; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.IJobChangeEvent; -import org.eclipse.core.runtime.jobs.IJobChangeListener; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.MessageBox; -import org.eclipse.ui.console.MessageConsoleStream; -import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; - -import com.espressif.idf.core.IDFConstants; -import com.espressif.idf.core.IDFCorePlugin; -import com.espressif.idf.core.IDFEnvironmentVariables; -import com.espressif.idf.core.ProcessBuilderFactory; -import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.toolchain.ESPToolChainManager; -import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.core.util.StringUtil; -import com.espressif.idf.ui.IDFConsole; -import com.espressif.idf.ui.UIPlugin; - -/** - * IDF Tools install command handler - * - * @author Kondal Kolipaka - * - */ -public class InstallToolsHandler extends AbstractToolsHandler -{ - public static final String INSTALL_TOOLS_FLAG = "INSTALL_TOOLS_FLAG"; //$NON-NLS-1$ - - @Override - protected void execute() - { - Job installToolsJob = new Job(Messages.InstallToolsHandler_InstallingToolsMsg) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - monitor.beginTask(Messages.InstallToolsHandler_ItWilltakeTimeMsg, 5); - monitor.worked(1); - - IStatus status = handleToolsInstall(); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - monitor.worked(1); - monitor.setTaskName(Messages.InstallToolsHandler_InstallingPythonMsg); - status = handleToolsInstallPython(console); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - monitor.worked(1); - - monitor.setTaskName(Messages.InstallToolsHandler_ExportingPathsMsg); - status = new ExportIDFTools().runToolsExportAndProcessOutput(pythonExecutablenPath, gitExecutablePath, console, - errorConsoleStream); - if (status.getSeverity() == IStatus.ERROR) - { - return status; - } - - monitor.worked(1); - console.println(Messages.InstallToolsHandler_ConfiguredBuildEnvVarMsg); - - monitor.setTaskName(Messages.InstallToolsHandler_AutoConfigureToolchain); - new ESPToolChainManager().configureToolChain(); - monitor.worked(1); - - configEnv(); - - monitor.setTaskName(Messages.InstallToolsHandler_InstallingWebscoketMsg); - handleWebSocketClientInstall(); - monitor.worked(1); - - copyOpenOcdRules(); - console.println(Messages.InstallToolsHandler_ConfiguredCMakeMsg); - - console.println(Messages.InstallToolsHandler_ToolsCompleted); - return Status.OK_STATUS; - } - }; - Preferences scopedPreferenceStore = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); - scopedPreferenceStore.putBoolean(INSTALL_TOOLS_FLAG, true); - try - { - scopedPreferenceStore.flush(); - } - catch (BackingStoreException e) - { - Logger.log(e); - } - installToolsJob.addJobChangeListener(new ToolInstallListener()); - installToolsJob.schedule(); - } - - /** - * Configure all the required environment variables here - */ - protected void configEnv() - { - IDFEnvironmentVariables idfEnvMgr = new IDFEnvironmentVariables(); - - // Enable IDF_COMPONENT_MANAGER by default - idfEnvMgr.addEnvVariable(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, "1"); - // IDF_MAINTAINER=1 to be able to build with the clang toolchain - idfEnvMgr.addEnvVariable(IDFEnvironmentVariables.IDF_MAINTAINER, "1"); - - } - - private void copyOpenOcdRules() - { - if (Platform.getOS().equals(Platform.OS_LINUX) - && !IDFUtil.getOpenOCDLocation().equalsIgnoreCase(StringUtil.EMPTY)) - { - console.println(Messages.InstallToolsHandler_CopyingOpenOCDRules); - // Copy the rules to the idf - StringBuilder pathToRules = new StringBuilder(); - pathToRules.append(IDFUtil.getOpenOCDLocation()); - pathToRules.append("/../share/openocd/contrib/60-openocd.rules"); //$NON-NLS-1$ - File rulesFile = new File(pathToRules.toString()); - if (rulesFile.exists()) - { - Path source = Paths.get(pathToRules.toString()); - Path target = Paths.get("/etc/udev/rules.d/60-openocd.rules"); //$NON-NLS-1$ - console.println(String.format(Messages.InstallToolsHandler_OpenOCDRulesCopyPaths, source.toString(), - target.toString())); - - Display.getDefault().syncExec(new Runnable() - { - @Override - public void run() - { - try - { - if (target.toFile().exists()) - { - MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), - SWT.ICON_WARNING | SWT.YES | SWT.NO); - messageBox.setText(Messages.InstallToolsHandler_OpenOCDRulesCopyWarning); - messageBox.setMessage(Messages.InstallToolsHandler_OpenOCDRulesCopyWarningMessage); - int response = messageBox.open(); - if (response == SWT.YES) - { - Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); - } - else - { - console.println(Messages.InstallToolsHandler_OpenOCDRulesNotCopied); - return; - } - } - else - { - Files.copy(source, target); - } - - console.println(Messages.InstallToolsHandler_OpenOCDRulesCopied); - } - catch (IOException e) - { - Logger.log(e); - errorConsoleStream.println(Messages.InstallToolsHandler_OpenOCDRulesCopyError); - } - } - }); - } - } - } - - protected IStatus handleToolsInstall() - { - // idf_tools.py install all - List arguments = new ArrayList(); - arguments.add(IDFConstants.TOOLS_INSTALL_CMD); - arguments.add(IDFConstants.TOOLS_INSTALL_ALL_CMD); - - console.println(Messages.InstallToolsHandler_InstallingToolsMsg); - console.println(Messages.InstallToolsHandler_ItWilltakeTimeMsg); - return runCommand(arguments, console); - } - - protected IStatus handleToolsInstallPython(MessageConsoleStream console) - { - List arguments; - // idf_tools.py install-python-env - arguments = new ArrayList(); - arguments.add(IDFConstants.TOOLS_INSTALL_PYTHON_CMD); - return runCommand(arguments, console); - } - - public IStatus handleWebSocketClientInstall() - { - String websocketClient = "websocket-client"; //$NON-NLS-1$ - // pip install websocket-client - List arguments = new ArrayList(); - final String pythonEnvPath = IDFUtil.getIDFPythonEnvPath(); - if (pythonEnvPath == null || !new File(pythonEnvPath).exists()) - { - console.println(String.format("%s executable not found. Unable to run `%s -m pip install websocket-client`", //$NON-NLS-1$ - IDFConstants.PYTHON_CMD, IDFConstants.PYTHON_CMD)); - return IDFCorePlugin.errorStatus( - String.format("%s executable not found. Unable to run `%s -m pip install websocket-client`", //$NON-NLS-1$ - IDFConstants.PYTHON_CMD, IDFConstants.PYTHON_CMD), - null); - } - arguments.add(pythonEnvPath); - arguments.add("-m"); //$NON-NLS-1$ - arguments.add("pip"); //$NON-NLS-1$ - arguments.add("list"); //$NON-NLS-1$ - - ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); - - try - { - String cmdMsg = "Executing " + getCommandString(arguments); //$NON-NLS-1$ - if (console != null) - { - console.println(cmdMsg); - } - Logger.log(cmdMsg); - - Map environment = new HashMap<>(IDFUtil.getSystemEnv()); - Logger.log(environment.toString()); - - IStatus status = processRunner.runInBackground(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), - IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - if (errorConsoleStream != null) - { - errorConsoleStream.println("Unable to get the process status."); - } - return IDFCorePlugin.errorStatus("Unable to get the process status.", null); //$NON-NLS-1$ - } - - String cmdOutput = status.getMessage(); - if (cmdOutput.contains(websocketClient)) - { - return IDFCorePlugin.okStatus("websocket-client already installed", null); //$NON-NLS-1$ - } - - // websocket client not installed so installing it now. - arguments.remove(arguments.size() - 1); - arguments.add("install"); //$NON-NLS-1$ - arguments.add(websocketClient); - - status = processRunner.runInBackground(arguments, org.eclipse.core.runtime.Path.ROOT, environment); - if (status == null) - { - Logger.log(IDFCorePlugin.getPlugin(), - IDFCorePlugin.errorStatus("Unable to get the process status.", null)); //$NON-NLS-1$ - if (errorConsoleStream != null) - { - errorConsoleStream.println("Unable to get the process status."); - } - return IDFCorePlugin.errorStatus("Unable to get the process status.", null); //$NON-NLS-1$ - } - - if (console != null) - { - console.println(status.getMessage()); - } - - return status; - } - catch (Exception e1) - { - Logger.log(IDFCorePlugin.getPlugin(), e1); - if (errorConsoleStream != null) - { - errorConsoleStream.println(e1.getLocalizedMessage()); - } - return IDFCorePlugin.errorStatus(e1.getLocalizedMessage(), e1); // $NON-NLS-1$; - } - } - - private class ToolInstallListener implements IJobChangeListener - { - Map existingVarMap; - - @Override - public void aboutToRun(IJobChangeEvent event) - { - // clean the ESP_IDF_VERSION variable first, because it's not coming from older versions of the ESP-IDF - new IDFEnvironmentVariables().removeEnvVariable(IDFEnvironmentVariables.ESP_IDF_VERSION); - this.existingVarMap = loadExistingVars(); - } - - private Map loadExistingVars() - { - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - Map existingVarMap = new HashMap<>(); - existingVarMap.put(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER)); - existingVarMap.put(IDFEnvironmentVariables.IDF_PATH, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.IDF_PATH)); - existingVarMap.put(IDFEnvironmentVariables.IDF_PYTHON_ENV_PATH, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.IDF_PYTHON_ENV_PATH)); - existingVarMap.put(IDFEnvironmentVariables.OPENOCD_SCRIPTS, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.OPENOCD_SCRIPTS)); - existingVarMap.put(IDFEnvironmentVariables.PATH, - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH)); - - return existingVarMap; - } - - @Override - public void awake(IJobChangeEvent event) - { - - } - - @Override - public void done(IJobChangeEvent event) - { - if (event.getResult().getSeverity() == IStatus.ERROR) - { - restoreOldVars(); - } - else - { - IDFUtil.updateEspressifPrefPageOpenocdPath(); - } - } - - private void restoreOldVars() - { - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); - for (Entry varsEntry : existingVarMap.entrySet()) - { - idfEnvironmentVariables.addEnvVariable(varsEntry.getKey(), varsEntry.getValue()); - } - } - - @Override - public void running(IJobChangeEvent event) - { - - } - - @Override - public void scheduled(IJobChangeEvent event) - { - - } - - @Override - public void sleeping(IJobChangeEvent event) - { - - } - } -} diff --git a/docs/en/additionalfeatures.rst b/docs/en/additionalfeatures.rst index d65988619..7128b327d 100644 --- a/docs/en/additionalfeatures.rst +++ b/docs/en/additionalfeatures.rst @@ -1,23 +1,24 @@ Additional IDE Features -=============================== -.. toctree:: - :maxdepth: 1 +======================= - LSP C/C++ Editor - CMake Editor - ESP-IDF Application Size Analysis - ESP-IDF Terminal - Install ESP-IDF Components - Heap Tracing - ESP-IDF OpenOCD Debugging - GDB Stub Debugging - Core Dump Debugging - Application Level Tracing - Partition Table Editor - NVS Partition Editor - Write Binary to Flash - DFU Flashing - Wokwi Simulator - Switch Between Languages +:link_to_translation:`zh_CN:[中文]` +.. toctree:: + :maxdepth: 1 + LSP C/C++ Editor + CMake Editor + ESP-IDF Application Size Analysis + ESP-IDF Terminal + Install ESP-IDF Components + Heap Tracing + ESP-IDF OpenOCD Debugging + GDB Stub Debugging + Core Dump Debugging + Application Level Tracing + Partition Table Editor + NVS Partition Editor + Write Binary to Flash + DFU Flashing + Wokwi Simulator + Switch Between Languages diff --git a/docs/en/additionalfeatures/appleveltracing.rst b/docs/en/additionalfeatures/appleveltracing.rst index 00b1c9e08..7220dda1e 100644 --- a/docs/en/additionalfeatures/appleveltracing.rst +++ b/docs/en/additionalfeatures/appleveltracing.rst @@ -1,7 +1,9 @@ Application Level Tracing ========================= -ESP-IDF provides a useful feature for program behavior analysis called `Application Level Tracing `_. The IDF-Eclipse plugin has a UI that allows you to start and stop tracing commands and process the received data. To familiarize yourself with this library, you can use the `app_trace_to_host `_ project or the `app_trace_basic `_ project (if using esp-idf 5.1 and higher). These projects can be created from the plugin itself: +:link_to_translation:`zh_CN:[中文]` + +ESP-IDF provides a useful feature for program behavior analysis called `Application Level Tracing Library `_. The IDF-Eclipse plugin provides a UI that allows you to start and stop tracing commands and process the received data. To get familiar with this library, you can use the `app_trace_to_host `_ project or the `app_trace_basic `_ project (if you are using ESP-IDF 5.1 or higher). These projects can be created directly from the plugin. .. image:: ../../../media/AppLvlTracing_1.png :alt: Application Level Tracing project creation @@ -11,17 +13,18 @@ Before using application-level tracing, create a debug configuration for the pro .. image:: ../../../media/AppLvlTracing_3.png :alt: Debug configuration setup -After creating the debug configuration, right-click on the project in the Project Explorer and select *ESP-IDF > Application Level Tracing*: +After creating the debug configuration, right-click on the project in the Project Explorer and select ``ESP-IDF: Application Level Tracing``. .. image:: ../../../media/AppLvlTracing_2.png :alt: Application Level Tracing option in the context menu -It may take a moment to open the application level tracing dialog, as the OpenOCD server starts first. At the top of the dialog, you will find auto-configured fields that you can adjust for the trace start command. +It may take a moment to open the application level tracing dialog, as the OpenOCD server starts first. At the top of the dialog, you will find auto-configured fields that can be adjusted if needed for the trace start command. **Start Command:** - Syntax: ``start [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]`` - Arguments: + - ``outfile``: Path to the file where data from both CPUs will be saved, with format ``file://path/to/file``. - ``poll_period``: Data polling period (in ms). If greater than 0, the command runs in non-blocking mode. Default: 1 ms. - ``trace_size``: Maximum data size to collect (in bytes). Tracing stops after the specified amount of data is received. Default: -1 (disabled). @@ -34,14 +37,14 @@ Additional information can be found `here Application Size Analysis** menu option to launch the editor. +#. Select ``ESP-IDF: Application Size Analysis`` menu option to launch the editor. -**Application Size Analysis - Overview** - -.. image:: ../../../media/sizeanalysis_overview.png +.. figure:: ../../../media/sizeanalysis_overview.png + :align: center :alt: Application Size Analysis - Overview -**Application Size Analysis - Details** + Application Size Analysis – Overview + -.. image:: ../../../media/sizeanalysis_details.png +.. figure:: ../../../media/sizeanalysis_details.png + :align: center :alt: Application Size Analysis - Details + + Application Size Analysis – Details diff --git a/docs/en/additionalfeatures/clangtoolchain.rst b/docs/en/additionalfeatures/clangtoolchain.rst index 3fdf5878c..2f6e929f6 100644 --- a/docs/en/additionalfeatures/clangtoolchain.rst +++ b/docs/en/additionalfeatures/clangtoolchain.rst @@ -1,15 +1,18 @@ -Configuring Clang Toolchain -=========================== +Clang Toolchain Configuration +============================= + +:link_to_translation:`zh_CN:[中文]` 1. After creating a new project, edit the project configuration. .. image:: https://user-images.githubusercontent.com/24419842/194882285-9faadb5d-0fe2-4012-bb6e-bc23dedbdbd2.png :alt: Project Configuration -2. Go to the ``Build Settings`` tab and select the clang toolchain: +2. Go to the ``Build Settings`` tab and select the Clang toolchain. .. image:: https://user-images.githubusercontent.com/24419842/194882462-3c0fd660-b223-4caf-964d-58224d91b518.png :alt: Clang Toolchain Selection .. note:: - Clang toolchain is currently an experimental feature, and you may encounter build issues due to incompatibility with ESP-IDF. The following describes how to address the most common build issues on the current ESP-IDF master (ESP-IDF v5.1-dev-992-gaf28c1fa21-dirty). To work around clang build errors, please refer to `this workaround guide `_. + + The Clang toolchain is currently an experimental feature, and you may encounter build issues due to incompatibility with ESP-IDF. The following describes how to address the most common build issues on the current ESP-IDF master (ESP-IDF v5.1-dev-992-gaf28c1fa21-dirty). For additional Clang-related build errors, please refer to the `workaround guide `_. diff --git a/docs/en/additionalfeatures/cmakeeditor.rst b/docs/en/additionalfeatures/cmakeeditor.rst index 707415796..4206d19e7 100644 --- a/docs/en/additionalfeatures/cmakeeditor.rst +++ b/docs/en/additionalfeatures/cmakeeditor.rst @@ -1,12 +1,14 @@ CMake Editor ============ -The CMake Editor Plug-in is integrated with the IDF Plugin for editing CMake files, such as ``CMakeLists.txt``. It provides syntax coloring, CMake command content assistance, and code templates. +:link_to_translation:`zh_CN:[中文]` + +The CMake Editor Plugin is integrated with the IDF Plugin for editing CMake files, such as ``CMakeLists.txt``. It provides syntax coloring, CMake command auto-completion, and code templates. .. image:: ../../../media/cmake_editor_ca.png :alt: CMake Editor with content assist -CMake editor preferences can be controlled using **Eclipse > Preferences > CMakeEd**. +CMake editor preferences can be controlled using ``Eclipse`` > ``Preferences`` > ``CMakeEd``. .. image:: ../../../media/cmake_editor_preferences.png :alt: CMake editor preferences diff --git a/docs/en/additionalfeatures/configureenvvariables.rst b/docs/en/additionalfeatures/configureenvvariables.rst index 311f9e37e..2bb793bbf 100644 --- a/docs/en/additionalfeatures/configureenvvariables.rst +++ b/docs/en/additionalfeatures/configureenvvariables.rst @@ -1,7 +1,9 @@ Configuring Environment Variables ================================== -All the required environment variables are automatically configured by the IDE during the ESP-IDF and Tools installation process (``Espressif > ESP-IDF Manager > Add ESP-IDF``). You can verify these variables in the Preferences page under ``C/C++ > Build > Environment``. +:link_to_translation:`zh_CN:[中文]` + +Once you install ESP-IDF through `EIM `_, all required environment variables are automatically configured by the IDE when you activate the ESP-IDF in ``Espressif`` > ``ESP-IDF Manager``. You can verify these variables on the ``Preferences`` page under ``C/C++`` > ``Build`` > ``Environment``. .. image:: ../../../media/2_environment_pref.png :alt: Environment Preferences diff --git a/docs/en/additionalfeatures/configuretoolchain.rst b/docs/en/additionalfeatures/configuretoolchain.rst index 864dc22de..500754857 100644 --- a/docs/en/additionalfeatures/configuretoolchain.rst +++ b/docs/en/additionalfeatures/configuretoolchain.rst @@ -1,57 +1,71 @@ -How to Add a Preview or Custom ESP-IDF Target in the IDE (Manual Configuration) -=============================================================================== +Add a Preview or Custom ESP-IDF Target in the IDE +================================================= -To add support for any preview or custom ESP-IDF target (such as ESP32-C5 or others not listed by default in the IDE), follow these steps: +:link_to_translation:`zh_CN:[中文]` + +To add support for any preview or custom ESP-IDF target (such as ESP32-C5 or other targets not listed by default in the IDE), follow these steps: Step 1: Configure Toolchain --------------------------- -1. Go to Preferences → C/C++ → Core Build Toolchain. -2. Under User Defined Toolchain, click on Add…. -3. Select GCC and configure as follows: - - **Compiler:** (Path to the toolchain compiler for your target, e.g. `/Users/testuser/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc`) - - **Operating System:** (e.g. `esp32c5` for ESP32-C5) - - **CPU Arch:** (e.g. `riscv32` for ESP32-C5) -4. Click Finish. - -.. image:: ../../../media/toolchain/toolchain_1.png + +1. Go to ``Preferences`` > ``C/C++`` > ``Core Build Toolchain``. +2. Under ``User Defined Toolchains``, click ``Add``. +3. Select ``GCC`` and configure as follows: + + - **Compiler**: Path to the toolchain compiler for your target, e.g., ``/Users/testuser/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc`` + - **Operating System**: e.g., ``esp32c5`` for ESP32-C5 + - **CPU Arch**: e.g., ``riscv32`` for ESP32-C5 + +4. Click ``Finish``. + +.. figure:: ../../../media/toolchain/toolchain_1.png + :align: center :alt: Core Build Toolchains Preferences (Add Custom Target) -*Core Build Toolchains Preferences: Adding a custom/preview target toolchain (example: ESP32-C5)* + Core Build Toolchains Preferences: Adding a custom/preview target toolchain (example: ESP32-C5) Step 2: Configure CMake Toolchain --------------------------------- -1. Navigate to Preferences → C/C++ → CMake. -2. Click on Add…. -3. Browse and select the CMake toolchain file for your target (e.g. `toolchain-esp32c5.cmake`). + +1. Navigate to ``Preferences`` > ``C/C++`` > ``CMake``. +2. Click ``Add``. +3. Browse and select the CMake toolchain file for your target (e.g., ``toolchain-esp32c5.cmake``). 4. Choose the corresponding toolchain entry created in Step 1. -5. Click Finish. +5. Click ``Finish``. -.. image:: ../../../media/toolchain/toolchain_2.png +.. figure:: ../../../media/toolchain/toolchain_2.png + :align: center :alt: CMake Toolchain Preferences (Add Custom Target) -*CMake Toolchain Preferences: Adding a custom/preview target toolchain file (example: ESP32-C5)* + CMake Toolchain Preferences: Adding a custom/preview target toolchain file (example: ESP32-C5) Step 3: Add Launch Target ------------------------- -1. From the IDE's top toolbar target list, click on New Launch Target. -2. Select ESP Target. + +1. From the IDE's top toolbar target list, click ``New Launch Target``. +2. Select ``ESP Target``. 3. Provide the following details: - - **Name:** (e.g. `esp32c5`) - - **IDF Target:** (e.g. `esp32c5`) -4. Click Finish. -.. image:: ../../../media/toolchain/toolchain_3.png + - ``Name``: e.g., esp32c5 + - ``IDF Target``: e.g., esp32c5 + +4. Click ``Finish``. + +.. figure:: ../../../media/toolchain/toolchain_3.png + :align: center :alt: New ESP Target Dialog (Custom Target Example) -*New ESP Target Dialog: Creating a launch target for a custom/preview target (example: ESP32-C5)* + New ESP Target Dialog: Creating a launch target for a custom/preview target (example: ESP32-C5) Step 4: Build a Project ----------------------- + - Create or open a project. - Select your custom/preview target from the target list. - Build the project. -.. image:: ../../../media/toolchain/toolchain_4.png +.. figure:: ../../../media/toolchain/toolchain_4.png + :align: center :alt: Build Output for Custom Target Project -*Build Output: Successfully building a project for a custom/preview target (example: ESP32-C5)* + Build Output: Successfully building a project for a custom/preview target (example: ESP32-C5) diff --git a/docs/en/additionalfeatures/coredumpdebugging.rst b/docs/en/additionalfeatures/coredumpdebugging.rst index 7c93cda3c..ba401ece5 100644 --- a/docs/en/additionalfeatures/coredumpdebugging.rst +++ b/docs/en/additionalfeatures/coredumpdebugging.rst @@ -1,20 +1,21 @@ .. _coredumpdebugging: Core Dump Debugging -==================== +=================== -The IDF-Eclipse plugin allows you to debug the core dump if any crash occurs on the chip and the configurations are set. Currently, only the UART core dump capture and debugging is supported. +:link_to_translation:`zh_CN:[中文]` -To enable core dump debugging for a project: +The IDF-Eclipse plugin allows you to debug the core dump if any crash occurs on the chip, provided that the required configurations are set. Currently, only UART core dump capture and debugging are supported. -1. You need to enable it first in `sdkconfig`. Launch the `sdkconfig` in the project root by double-clicking on it which will open the configuration editor. +To enable core dump debugging for a project: -2. Click on the `Core Dump` from the settings on the left and select `Data Destination` as `UART`. +1. You need to enable it first in ``sdkconfig``. Open the ``sdkconfig`` in the project root by double-clicking on it, which will launch the configuration editor. +2. Click ``Core Dump`` in the settings on the left, and set ``Data Destination`` as ``UART``. .. image:: ../../../media/CoreDumpDebugging/sdkconfig_editor.png -This will enable the core dump debugging, and whenever you connect a serial monitor for that project, if any crash occurs, it will load the dump and open a debug perspective in Eclipse to let you diagnose the dump where you can view all the information in the core dump. +This enables core dump debugging. When you connect a serial monitor for the project and a crash occurs, Eclipse automatically loads the core dump and opens the debug perspective, allowing you to inspect all the information contained in the dump. -You can view the registers stack trace and even view the value of variables in the stack frame. +You can view the registers and stack trace, and even check the value of variables in the stack frame. -To exit the debug session: simply press the `stop` button. +To exit the debug session: simply click the ``stop`` button. diff --git a/docs/en/additionalfeatures/esp-terminal.rst b/docs/en/additionalfeatures/esp-terminal.rst index 1e9b71cd4..c76c5e109 100644 --- a/docs/en/additionalfeatures/esp-terminal.rst +++ b/docs/en/additionalfeatures/esp-terminal.rst @@ -1,14 +1,16 @@ ESP-IDF Terminal -=============================== +================ -This would launch a local terminal with all the environment variables set under ``Preferences`` > ``C/C++`` > ``Build`` > ``Environment``. The default working directory would be either the currently selected project or ``IDF_PATH`` if there is no project selected. +:link_to_translation:`zh_CN:[中文]` + +This launches a local terminal with all environment variables configured under ``Preferences`` > ``C/C++`` > ``Build`` > ``Environment``. The default working directory would be either the currently selected project or ``IDF_PATH`` if no project selected. The terminal ``PATH`` is also configured with ``esptool``, ``espcoredump``, ``partition_table``, and ``app_update`` component paths, so it is convenient to access them directly from the ESP-IDF terminal. To launch the ESP-IDF Terminal: -- Click on the ``Open a Terminal`` icon from the toolbar. -- Choose ``ESP-IDF Terminal`` from the terminal drop-down and click ``OK`` to launch a terminal. +1. Click on the ``Open a Terminal`` icon from the toolbar. +2. Choose ``ESP-IDF Terminal`` from the terminal drop-down and click ``OK`` to launch a terminal. .. image:: ../../../media/idf_terminal.png :alt: ESP-IDF Terminal diff --git a/docs/en/additionalfeatures/gdbstubdebugging.rst b/docs/en/additionalfeatures/gdbstubdebugging.rst index 039a82827..a61282155 100644 --- a/docs/en/additionalfeatures/gdbstubdebugging.rst +++ b/docs/en/additionalfeatures/gdbstubdebugging.rst @@ -2,47 +2,49 @@ GDBStub Debugging ================= -You can now use the GDBStub debugging inside our Eclipse plugin to help you diagnose and debug issues on chips via Eclipse when it is in panic mode. + +:link_to_translation:`zh_CN:[中文]` + +You can now use the GDBStub debugging in the Eclipse plugin to diagnose and debug chip issues when the chip enters panic mode. To enable GDBStub debugging for a project: -1. Launch the `sdkconfig` in project root by double-clicking on it which will open the configuration editor. +1. Launch the ``sdkconfig`` file in the project root by double-clicking it. This will open the configuration editor. -.. image:: ../../../media/GDBStubDebugging/sdkconfig_editor.png + .. image:: ../../../media/GDBStubDebugging/sdkconfig_editor.png -2. Expand the `Component Config` section and select `ESP System Settings`. From the settings on the right for `Panic Handler behaviour` select the `GDBStub on Panic option` from the list. +2. Expand the ``Component Config`` section and select ``ESP System Settings``. From the settings on the right for ``Panic handler behaviour`` select the ``GDBStub on panic`` option from the list. -.. image:: ../../../media/GDBStubDebugging/sdkconfig_editor_panic_behavior.png + .. image:: ../../../media/GDBStubDebugging/sdkconfig_editor_panic_behavior.png -Now you will be taken to the GDBStub debugger automatically when you connect the serial monitor and there is a panic for this example. +When you connect the serial monitor and a panic occurs in this example, the GDBStub debugger will be launched automatically. To use the GDBStub debugging for a project: -1. Create a template `hello_world` project and add the following lines in the main C file: +1. Create a template ``hello_world`` project and add the following lines in the ``main.c`` file: - .. code-block:: c + .. code-block:: c - This is a global variable
- COREDUMP_DRAM_ATTR uint8_t global_var; + // This is a global variable + COREDUMP_DRAM_ATTR uint8_t global_var; -2. Now add these two lines just above the `esp_restart()` function: +2. Now add these two lines just above the ``esp_restart()`` function: - .. code-block:: c + .. code-block:: c - global_var = 25; - assert(0); + global_var = 25; + assert(0); -The final file should be something like this: +The final file should look like the following: .. image:: ../../../media/GDBStubDebugging/code_example.png -Build and flash the project and launch the serial monitor. On line number 45, we are signaling for a failing assert which will put the chip in panic mode and when that line reaches, you will be prompted to switch the perspective to debug mode and the chip will be halted. +Build and flash the project, then launch the serial monitor. At line 45, a failing assert is triggered, which puts the chip into panic mode. When execution reaches this line, you will be prompted to switch to the Debug perspective, and the chip will be halted. -Remember that this is a panic mode and you cannot continue the execution from here, you will have to stop and restart the chip through IDF commands or simply restart the serial monitor. +The chip is in panic mode, and execution cannot continue from this point. You must stop and restart the chip using IDF commands or by restarting the serial monitor. .. image:: ../../../media/GDBStubDebugging/debug_panic_mode.png -You can view the registers stack trace and even view the value of variables in the stack frame. - -To exit the debug session simply press the `stop` button. +You can view the registers, stack trace, and even the value of variables in the stack frame. +To exit the debug session, simply press the ``stop`` button. diff --git a/docs/en/additionalfeatures/heaptracing.rst b/docs/en/additionalfeatures/heaptracing.rst index 346a8c7a5..8446410b0 100644 --- a/docs/en/additionalfeatures/heaptracing.rst +++ b/docs/en/additionalfeatures/heaptracing.rst @@ -3,85 +3,93 @@ Heap Tracing ============ -Heap tracing enables you to monitor memory usage over time by generating and analyzing a `svdat` dump file. The IDF Eclipse Plugin supports generating heap trace files through special breakpoints. For more information on SDK-level configuration and tracing features, refer to the official `ESP-IDF documentation `_. +:link_to_translation:`zh_CN:[中文]` + +Heap tracing allows you to monitor memory usage over time by generating and analyzing a ``svdat`` dump file. The IDF Eclipse Plugin supports generating heap trace files by setting special breakpoints. For more information on SDK-level configuration and tracing features, refer to the official `ESP-IDF documentation `_. Generating Dump File -------------------- -1. **Open the sysview\_heap\_log.c file** + +1. **Open the sysview_heap_log.c File** - From the Project Explorer, locate and open the `sysview_heap_log.c` file from the **system** templates project. + From the Project Explorer, locate and open the ``sysview_heap_log.c`` file from the **system** templates project. .. image:: ../../../media/HeapTracing/sysview_heap_log_file.PNG :alt: sysview_heap_log.c file 2. **Add a Breakpoint and Configure Properties** - Add a breakpoint at the desired line, then right-click on the breakpoint icon in the editor and select `Breakpoint Properties…`. + Add a breakpoint at the desired line, then right-click on the breakpoint icon in the editor and select ``Breakpoint Properties``. .. image:: ../../../media/HeapTracing/breakpoint_properties_popup.png :alt: Breakpoint Properties 3. **Define Heap Tracing Action** - In the Breakpoint Properties window, go to `Actions`, click `New`, and select `Heap Tracing` from the `Action Type` dropdown. - - For the initial breakpoint, set the action to **Start Heap Trace** and specify the save location for the dump file (recommended to store in the project directory). Name the action meaningfully, then click OK. + In the ``Breakpoint Properties`` window, go to ``Actions``, click ``New``, and select ``Heap Tracing`` from the ``Action Type`` dropdown. + + For the initial breakpoint, set the ``Action`` to ``Start Heap Trace`` and specify the save location for the dump file (it is recommended to store it in the project directory). Name the action meaningfully, then click ``OK``. .. image:: ../../../media/HeapTracing/heap_tracing_action.png :alt: Heap Tracing Action 4. **Attach the Action to the Breakpoint** - After creating the action, click `Attach` to link it to the breakpoint, which will display it under the Actions for this breakpoint section. + After creating the action, click ``Attach`` to link it to the breakpoint, which will display the action under the ``Actions for this breakpoint`` section. .. image:: ../../../media/HeapTracing/breakpoint_properties_actions_start_attached.png :alt: Attach Action 5. **Apply and Create Additional Breakpoint** - Now you have a breakpoint that will start tracing and generate a dump file. To stop the tracing, create another breakpoint (e.g., at line 102), set its properties, and choose the **Stop Heap Trace** option in the action settings. Attach this action to the breakpoint as shown below. + Now you have a breakpoint that will start tracing and generate a dump file. To stop the tracing, create another breakpoint (e.g., at line 102), set its properties, and choose the ``Stop Heap Trace`` option in the action settings. Attach this action to the breakpoint as shown below. .. image:: ../../../media/HeapTracing/breakpoint_properties_actions_stop_attached.png :alt: Stop Heap Trace Action 6. **Launch Debug Configuration** - Launch the debug configuration for your ESP32 board. When the program hits the breakpoints, the IDE will prompt you to switch to the debugger perspective. Continue execution for each breakpoint to start and stop tracing. Refresh the project in the Project Explorer to view the dump file in the specified location. + Launch the debug configuration for your ESP32 board. When a breakpoint is hit, the IDE will prompt you to switch to the debugger perspective. Continue execution at each breakpoint to start or stop tracing, then refresh the project in the Project Explorer to view the dump file at the specified location. Analyzing the Dump File ----------------------- -The IDF Eclipse Plugin allows you to analyze generated `svdat` dump files. Right-click on the dump file and select `Heap Dump Analysis` from the context menu. +The IDF Eclipse Plugin allows you to analyze generated ``svdat`` dump files. Right-click on the dump file and select ``ESP-IDF: Heap Dump Analysis`` from the context menu. -**Note:** Ensure the project is built with the appropriate symbols file to enable analysis. +.. note:: + + Ensure the project is built with the appropriate symbols file to enable analysis. .. image:: ../../../media/HeapTracing/analysis_context_menu.png :alt: Heap Dump Analysis Context Menu -Overview Tab -------------- -The Overview Tab displays memory consumption over time in a graph format. By default, all contexts are shown; you can select specific contexts corresponding to heap events. +``Overview`` Tab +---------------- + +The ``Overview`` Tab displays memory consumption over time in a graph format. By default, all contexts are shown, but you can select specific contexts corresponding to heap events. .. image:: ../../../media/HeapTracing/overview_tab_tracing.png :alt: Memory Consumption Graph -For example, selecting multiple contexts displays them separately on the graph. +For example, selecting multiple contexts displays each of them separately on the graph. .. image:: ../../../media/HeapTracing/overview_tab_tracing_contexts.png :alt: Selected Contexts in Graph -Details Tab -------------- -The Details Tab provides further insights, showing each event in the heap trace. Rows highlighted in light orange indicate potential memory leaks (since the trace may have ended before a free event was detected). Green rows show free heap events. +``Details`` Tab +--------------- + +The ``Details`` Tab provides further insights by showing each event in the heap trace. Rows highlighted in light orange indicate potential memory leaks, as the trace may have ended before a corresponding free event was detected. Rows highlighted in green indicate free heap events. .. image:: ../../../media/HeapTracing/details_tab_tracing.png :alt: Details Tab -To filter entries for possible memory leaks, check the `View Possible Memory Leaks` box. Right-clicking on any entry allows you to view callers, opening the `Callers View` to display the call stack for the heap event. +To filter entries for possible memory leaks, check the ``View Possible Memory Leaks`` box. Right-clicking on any entry allows you to view its callers by opening the ``Callers View``, which displays the call stack for the heap event. .. image:: ../../../media/HeapTracing/show_callers_context_menu.png :alt: Show Callers -Clicking on an entry in the `Callers View` will navigate to the corresponding line in the source file. +Clicking on an entry in the ``Callers View`` will navigate to the corresponding line in the source file. .. image:: ../../../media/HeapTracing/callers_view.png - :alt: Callers View \ No newline at end of file + :alt: Callers View diff --git a/docs/en/additionalfeatures/install-esp-components.rst b/docs/en/additionalfeatures/install-esp-components.rst index 97966d34d..d57885295 100644 --- a/docs/en/additionalfeatures/install-esp-components.rst +++ b/docs/en/additionalfeatures/install-esp-components.rst @@ -1,12 +1,15 @@ Install ESP-IDF Components -=============================== -You can install the ESP-IDF Components directly into your project from the available components from the `ESP-IDF Component Registry `_. Follow the steps below: +========================== -- Right-click on the project in ``Project Explorer`` where you want to add the component, and select ``ESP-IDF > Install ESP-IDF Components``. -- A new window will open, displaying all available components to be installed. -- In the window, you can click on the ``Install`` button to add the selected component to the project. To access the README file for a component, click ``More Info``, which opens the README in your browser. +:link_to_translation:`zh_CN:[中文]` - .. image:: ../../../media/ESP-IDF_Components/components_window.png - :alt: ESP-IDF Components Window +You can install the ESP-IDF Components directly into your project from the available components in `ESP-IDF Component Registry `_. Follow the steps below: -Already added components are also shown, but the ``Install`` button text changes to ``Already Added`` and is disabled. +1. Right-click on the project where you want to add the component in ``Project Explorer``, and select ``ESP-IDF: Install ESP-IDF Components``. +2. A new window will open, displaying all available components that can be installed. +3. In the window, click the ``Install`` button to add the selected component to your project. To view a component's README file, click ``More Info`` to open the README in your browser. + +.. image:: ../../../media/ESP-IDF_Components/components_window.png + :alt: ESP-IDF Components Window + +Already-added components are also shown, but the ``Install`` button text changes to ``Already Added`` and is disabled. diff --git a/docs/en/additionalfeatures/lspeditor.rst b/docs/en/additionalfeatures/lspeditor.rst index 124e28cb7..8554aaf4a 100644 --- a/docs/en/additionalfeatures/lspeditor.rst +++ b/docs/en/additionalfeatures/lspeditor.rst @@ -1,7 +1,9 @@ LSP C/C++ Editor -================= +================ -Starting with Espressif IDE 3.0.0, the LSP Editor is the default code editor, which differs in several ways from the previous default editor. Below are the most notable differences: +:link_to_translation:`zh_CN:[中文]` + +Starting with Espressif IDE 3.0.0, the LSP Editor becomes the default code editor and behaves differently from the previous default editor. The most notable differences are listed below. Formatting ---------- @@ -25,18 +27,18 @@ You can also disable formatting for specific folders by using the ``DisableForma project ├── managed_components - │ └── .clang-format + │ └── .clang-format ├── main └── .clang-format Add the ``DisableFormat: true`` option to the ``.clang-format`` file in the ``managed_components`` folder. This flag tells ClangFormat to completely ignore this specific ``.clang-format`` file and its formatting rules within the ``managed_components`` directory. -For more information about available style options, refer to `the Clang-Format Style Options guide `_. +For more information about available style options, refer to `Configurable Format Style Options `_. Search ------ -The search text option in the right-click menu is currently unavailable in the LSP-based C/C++ Editor. However, you can use the toolbar menu ``Search`` > ``Text`` > ``Workspace`` as a workaround. +The ``Search Text`` option in the right-click menu is currently unavailable in the LSP-based C/C++ Editor. However, as a workaround, you can use ``Search`` > ``Text`` > ``Workspace`` from the toolbar menu. Inlay Hints ----------- @@ -59,28 +61,29 @@ Searching ESP-IDF Components To browse ESP-IDF components, follow these steps: -- Create a new project. -- Add the ESP-IDF components folder as a virtual folder to the newly created project. -- Press **Ctrl + Shift + T** or **Ctrl + Shift + R**. -- You should now be able to browse the ESP-IDF component files. -- To search for a specific function or keyword, use the Search menu in the toolbar. +1. Create a new project. +2. Add the ESP-IDF components folder as a virtual folder to the newly created project. +3. Press **Ctrl + Shift + T** or **Ctrl + Shift + R**. +4. You should now be able to browse the ESP-IDF component files. +5. To search for a specific function or keyword, use the ``Search`` menu in the toolbar. Creating a Virtual Folder ~~~~~~~~~~~~~~~~~~~~~~~~~ -- Navigate to ``New`` > ``Folder``. -- Click on ``Advanced``. -- Select ``Link to alternate Location (Linked Folder)``. -- Click ``Browse`` and select the ``ESP-IDF components`` folder. +1. Navigate to ``New`` > ``Folder``. +2. Click on ``Advanced``. +3. Select ``Link to alternate Location (Linked Folder)``. +4. Click ``Browse`` and select the ``ESP-IDF components`` folder. -It is recommended to always create a new project instead of modifying your current one to avoid unnecessary Git files and error markers created by the indexer for the components folder. Since both projects will be in the same workspace, you should be able to search anywhere within your workspace. +It is recommended to always create a new project instead of modifying your current one to avoid unnecessary Git files and error markers created by the indexer for the ``components`` folder. Since both projects reside in the same workspace, you will still be able to search across your entire workspace. If you have any issues with the Clangd Configuration with the LSP Editor, please refer to the :ref:`Clangd Configuration ` guide. References ---------- + .. toctree:: :maxdepth: 1 Clangd CDT Support and Configuration - Configuring Clang Toolchain \ No newline at end of file + Clang Toolchain Configuration diff --git a/docs/en/additionalfeatures/nvspartitioneditor.rst b/docs/en/additionalfeatures/nvspartitioneditor.rst index e4eef1304..18d78fb5a 100644 --- a/docs/en/additionalfeatures/nvspartitioneditor.rst +++ b/docs/en/additionalfeatures/nvspartitioneditor.rst @@ -1,35 +1,41 @@ NVS Table Editor ================ -The NVS Table Editor helps create a binary file based on key-value pairs provided in a CSV file. The resulting binary file is compatible with the NVS architecture as defined in `ESP-IDF Non Volatile Storage `_. The expected CSV format is: +:link_to_translation:`zh_CN:[中文]` + +The NVS Table Editor helps create a binary file based on key-value pairs provided in a CSV file. The resulting binary file is compatible with the NVS architecture as defined in ESP-IDF `Non-Volatile Storage `_. The expected CSV format is: .. code-block:: text - key,type,encoding,value <-- column header (must be the first line) - namespace_name,namespace,, <-- First entry must be of type "namespace" - key1,data,u8,1 - key2,file,string,/path/to/file + key,type,encoding,value <-- column header (must be the first line) + namespace_name,namespace,, <-- First entry must be of type "namespace" + key1,data,u8,1 + key2,file,string,/path/to/file + +.. note:: -.. note:: This is based on ESP-IDF `NVS Partition Generator Utility `_. + This is based on ESP-IDF `NVS Partition Generator Utility `_. Steps ----- -1. Right-click on a project in the *Project Explorer*. -2. Click on the *ESP-IDF > NVS Table Editor* menu option: +1. Right-click on a project in the Project Explorer. +2. Click on the ``ESP-IDF: NVS Table Editor`` menu option. + + .. image:: https://user-images.githubusercontent.com/24419842/216114697-9f231211-f5dd-431b-9432-93ecc656cfec.png + :alt: NVS Table Editor menu option - .. image:: https://user-images.githubusercontent.com/24419842/216114697-9f231211-f5dd-431b-9432-93ecc656cfec.png - :alt: NVS Table Editor menu option +3. Make desired changes to the CSV data. +4. Save changes by clicking the ``Save`` button. If everything is correct, you will see an information message at the top of the dialog: -3. Make desired changes to the CSV data. -4. Save changes by clicking the *Save* button. If everything is correct, you will see an information message at the top of the dialog: + .. image:: https://user-images.githubusercontent.com/24419842/216115906-9bb4fe55-293b-4c6b-8d22-0aa3520581ab.png + :alt: Save confirmation in NVS Table Editor - .. image:: https://user-images.githubusercontent.com/24419842/216115906-9bb4fe55-293b-4c6b-8d22-0aa3520581ab.png - :alt: Save confirmation in NVS Table Editor +5. Generate the partition binary. Choose ``Encrypt`` to encrypt the binary, and disable the ``Generate Key`` option if you want to use your own key. An information message will appear at the top of the dialog showing the result of the generated binaries. Hover over the message to view the full content if it is truncated: -5. Generate the partition binary (choose *Encrypt* to encrypt the binary, and disable the *Generate Key* option to use your own key if desired). You will see an information message at the top of the dialog about the result of the generated binaries. Hover over the message if it's too long to read fully: + .. image:: https://user-images.githubusercontent.com/24419842/216117261-9bee798a-3a9e-4be5-9466-fc9d3847834b.png + :alt: Binary generation result in NVS Table Editor - .. image:: https://user-images.githubusercontent.com/24419842/216117261-9bee798a-3a9e-4be5-9466-fc9d3847834b.png - :alt: Binary generation result in NVS Table Editor + .. note:: - .. note:: If there are any errors, they will be highlighted. Hover over the error icon to read more about the error. You will also see an error message at the top of + If there are any errors, they will be highlighted. Hover over the error icon to read more about the error. An error message will also appear at the top of the dialog. diff --git a/docs/en/additionalfeatures/partitiontableeditor.rst b/docs/en/additionalfeatures/partitiontableeditor.rst index 018f590cb..2303cb9ac 100644 --- a/docs/en/additionalfeatures/partitiontableeditor.rst +++ b/docs/en/additionalfeatures/partitiontableeditor.rst @@ -1,28 +1,31 @@ -Partition Table Editor UI for ESP-IDF -===================================== +Partition Table Editor +====================== -The Partition Table Editor command allows you to edit your `partition table `_ in a more convenient way, where you can see the supported types and subtypes and monitor the correctness of the entered data. +:link_to_translation:`zh_CN:[中文]` + +The Partition Table Editor command allows you to edit your `partition table `_ in a more convenient way. It provides a view of the supported types and subtypes and helps you verify the correctness of the entered data. Steps ----- -1. Go to *Project Explorer* and open any IDF Project where you want to create a customized partition table. -2. In *Project Explorer*, right-click on the project and select *ESP-IDF > Partition Table Editor*: +1. Go to ``Project Explorer`` and open any IDF Project where you want to create a customized partition table. +2. In ``Project Explorer``, right-click on the project and select ``ESP-IDF: Partition Table Editor``: + + .. image:: https://user-images.githubusercontent.com/24419842/216105408-ca2e73ce-5df3-4bdd-ac61-b7265deb9b44.png + :alt: Partition Table Editor menu option - .. image:: https://user-images.githubusercontent.com/24419842/216105408-ca2e73ce-5df3-4bdd-ac61-b7265deb9b44.png - :alt: Partition Table Editor menu option + When you open the partition table editor for the selected project, you will see the standard editable content. Any errors will be highlighted, and you can hover the mouse over them to see hints about the issues. - When you open the partition table editor for the selected project, you will see the standard editable content. Errors, if any, will be highlighted. You can hover your mouse over them to get hints about the issues: + .. image:: https://user-images.githubusercontent.com/24419842/216106804-703b2eb4-b141-48de-8559-0599f072219f.png + :alt: Error hints in Partition Table Editor - .. image:: https://user-images.githubusercontent.com/24419842/216106804-703b2eb4-b141-48de-8559-0599f072219f.png - :alt: Error hints in Partition Table Editor +3. Click ``Save`` or ``Save and Quit`` to save your changes. -3. Click *Save* or *Save and Quit* to save your changes. To Use a Customized Partition Table ----------------------------------- -1. Go to *sdkconfig* and set *Custom partition table CSV* as shown below: +Go to ``SDK Configuration`` and set ``Custom partition table CSV`` as shown below: - .. image:: https://user-images.githubusercontent.com/24419842/216104107-2844068b-8412-468b-931f-b4778af4417c.png - :alt: Setting custom partition table in sdkconfig +.. image:: https://user-images.githubusercontent.com/24419842/216104107-2844068b-8412-468b-931f-b4778af4417c.png + :alt: Setting custom partition table in sdkconfig diff --git a/docs/en/additionalfeatures/switchlanguage.rst b/docs/en/additionalfeatures/switchlanguage.rst index 38d12f27e..7cf4e79a5 100644 --- a/docs/en/additionalfeatures/switchlanguage.rst +++ b/docs/en/additionalfeatures/switchlanguage.rst @@ -1,5 +1,8 @@ -Switch Between Languages in Espressif IDE -========================================== +Switch Between Languages in the IDE +=================================== + +:link_to_translation:`zh_CN:[中文]` + Espressif IDE supports English and Chinese languages. You can switch between these languages using the following steps: 1. Click on the ``Espressif`` menu from the menu bar. diff --git a/docs/en/additionalfeatures/writebinarytoflash.rst b/docs/en/additionalfeatures/writebinarytoflash.rst index 015db5cea..359e70736 100644 --- a/docs/en/additionalfeatures/writebinarytoflash.rst +++ b/docs/en/additionalfeatures/writebinarytoflash.rst @@ -1,14 +1,16 @@ Write Binary to Flash ====================== -Binary data can be written to the ESP’s flash chip via the *ESP-IDF > Write Binary Data to Flash* command. To access this command, right-click on the project in the Project Explorer: +:link_to_translation:`zh_CN:[中文]` + +Binary data can be written to the ESP's flash chip via the ``ESP-IDF: Write Binary Data to Flash`` command. To access this command, right-click on the project in the Project Explorer: .. image:: https://github.com/espressif/idf-eclipse-plugin/assets/24419842/186c8498-d779-4771-af53-e5bf09e29502 :alt: Write Binary Data to Flash command -After clicking this command, the *Write Binary Data to Flash* dialog box will open. Editable default values are provided for the binary path and offset. You can check the correct offset by viewing the partition table via *ESP-IDF > Partition Table Editor* or by manually opening the `partitions.csv` file. +After clicking this command, the ``Write Binary Data to Flash`` dialog box will open. Editable default values are provided for the binary path and offset. You can check the correct offset by viewing the partition table via ``ESP-IDF: Partition Table Editor`` or by manually opening the ``partitions.csv`` file. .. image:: https://github.com/espressif/idf-eclipse-plugin/assets/24419842/46e24e89-a1ed-4169-8c92-1ba0b0089ea7 :alt: Write Binary Data to Flash dialog -Clicking the *Flash* button will execute the flash command, and the result will be displayed within this dialog. +Clicking the ``Flash`` button will execute the flash command, and the result will be displayed within this dialog. diff --git a/docs/en/buildproject.rst b/docs/en/buildproject.rst index a9e71a74d..2661417b8 100644 --- a/docs/en/buildproject.rst +++ b/docs/en/buildproject.rst @@ -1,23 +1,23 @@ -Build the Project -=============================== +Build Your Project +================== + +:link_to_translation:`zh_CN:[中文]` .. |build_icon| image:: ../../media/icons/build.png :height: 16px :align: middle +Once you have created a project and configured the ESP target and serial port, you can build the project by clicking on |build_icon| in the toolbar. -Once you have created a project and configured the esp target and serial port, you can build the project by clicking on |build_icon| in the toolbar. - -However, below steps will guide you through the process of building the project if you are new to the IDE: +However, the following steps will guide you through the process of building the project if you are new to the IDE: 1. Select a project from the ``Project Explorer``. -2. Select ``Run`` from the first dropdown, which is called `Launch Mode`. -3. Select your application from the second dropdown, which is called `Launch Configuration` (Auto-detected). -4. Select a target from the third dropdown, for example, ``esp32``, which is called `Launch Target`. +2. Select ``Run`` from the first dropdown, which is called **Launch Mode**. +3. Select your application from the second dropdown, which is called **Launch Configuration** (Auto-detected). +4. Select a target from the third dropdown, which is called **Launch Target**. For example, ``esp32``. 5. Now click on the ``Build`` button |build_icon| to start the build process. - - .. image:: ../../media/9_cmake_build.png +.. image:: ../../media/9_cmake_build.png Custom Build Directory ---------------------- @@ -30,16 +30,17 @@ The IDE allows configuring a custom build directory for the project: 4. Click on ``Ok`` and build the project. .. note:: - This configuration changes where all the project build artifacts will be generated. + + This configuration specifies the location where all the project build artifacts will be generated. .. image:: ../../media/custombuilddir.png :alt: Custom Build Directory Configuration References ---------- + .. toctree:: :maxdepth: 1 Configure CDT Build Environment Variables Add a Preview or Custom ESP-IDF Target - \ No newline at end of file diff --git a/docs/en/configureproject.rst b/docs/en/configureproject.rst index 1accf07c9..33498e489 100644 --- a/docs/en/configureproject.rst +++ b/docs/en/configureproject.rst @@ -1,10 +1,13 @@ Configure Your Project -=============================== +====================== -Project configuration is stored in a single file called ``sdkconfig`` located in the root directory of the project. This configuration file can be modified using the ``SDK Configuration Editor``. +:link_to_translation:`zh_CN:[中文]` + +Project configuration is stored in a single file called ``sdkconfig`` located in the root directory of the project. This configuration file can be modified using the SDK Configuration Editor. .. note:: - sdkconfig file is generated only after the build. Hence, it is recommended to build the project once before configuring the project. + + ``sdkconfig`` file is generated only after the build. Hence, it is recommended to build the project once before configuring the project. To launch the SDK Configuration Editor: diff --git a/docs/en/connectdevice.rst b/docs/en/connectdevice.rst index e9428bb35..995510933 100644 --- a/docs/en/connectdevice.rst +++ b/docs/en/connectdevice.rst @@ -1,22 +1,24 @@ Connect Your Device -=============================== -Next, select the ESP target for your project (ignore this step if it was already set during project creation) and the serial port of your device by clicking on the gear icon. By default, the launch target dropdown will display all the supported targets provided by the plugin. +=================== + +:link_to_translation:`zh_CN:[中文]` + +Click the gear icon to select the ESP target for your project and the serial port of your device. Skip this step if these settings were configured during project creation. By default, the launch target dropdown will display all the supported targets provided by the plugin. .. image:: ../../media/target_selection.png -Clicking the gear icon opens the ESP Target Configuration dialog, where you can select the serial port for your device and specify the ESP board. The plugin will automatically detect serial ports connected to your machine. +Clicking the gear icon opens the ``ESP Target`` configuration dialog, where you can select the serial port for your device and specify the ESP board. The plugin will automatically detect serial ports connected to your machine. .. image:: ../../media/8_launch_target.png -Regarding the Serial ports and their patterns, please refer to the `ESP-IDF documentation `_. +Regarding the serial ports and their patterns, please refer to the `ESP-IDF documentation `_. Custom Target ----------------- +------------- + If you need to add a target that is not available in the launch target dropdown, please follow the instructions below: 1. Click on the launch target dropdown. 2. Select ``New Launch Target``. 3. Select ``ESP Target``. -4. Provide properties for the target where you would like to launch the application. Enter a ``Name`` for the target and select the ``Serial Port`` to which your ESP device is connected on your machine. - - +4. Specify the properties of the target device where you want to launch the application. Enter a ``Name`` for the target and select the ``Serial Port`` to which your ESP device is connected on your machine. diff --git a/docs/en/debugproject.rst b/docs/en/debugproject.rst index 5baf9b6ab..7615e4444 100644 --- a/docs/en/debugproject.rst +++ b/docs/en/debugproject.rst @@ -1,5 +1,7 @@ Debug Your Project -=============================== +================== + +:link_to_translation:`zh_CN:[中文]` .. |debug_icon| image:: ../../media/icons/debug.png :height: 16px @@ -7,10 +9,11 @@ Debug Your Project In most cases, only two things are required to start debugging an ESP-IDF project: -1. Create a debug configuration -2. Check whether the board in the created configuration corresponds to the board in use. +1. Create a debug configuration. +2. Check whether the board specified in the created configuration matches the board you are using. + +.. note:: -.. note:: If you're using Windows, you may need to install drivers using Zadig to run a debug session successfully. For detailed instructions, please refer to this `guide `_. The fastest way to create a debug configuration is as follows: diff --git a/docs/en/downloads.rst b/docs/en/downloads.rst index 2c20e47f2..e44d64e1e 100644 --- a/docs/en/downloads.rst +++ b/docs/en/downloads.rst @@ -1,33 +1,39 @@ .. _downloads: Espressif-IDE Downloads -========================= +======================= -You can find the latest Espressif-IDE release notes from `here `_. Provided below are the direct download links for various platforms. +:link_to_translation:`zh_CN:[中文]` -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| OS | Download | -+==============+===========================================================================================================================================+ -| Windows | `Espressif-IDE-win32.win32.x86_64 `_ | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| macOS x86_64 | `Espressif-IDE-macosx-cocoa-x86_64 `_ | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| macOS aarch64| `Espressif-IDE-macosx-cocoa-aarch64 `_ | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| Linux | `Espressif-IDE-linux.gtk.x86_64 `_ | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +You can find the latest Espressif-IDE release notes at `here `_. Direct download links for various platforms are provided below. +.. list-table:: + :header-rows: 1 + :widths: 20 80 -macOS security notice (Applicable only for Nightly Builds) ------------------------------------------------------------- -On macOS, if you download the archive with the browser, the strict security checks on recent macOS will prevent it to run, and complain that the program is damaged. That’s obviously not true, and the fix is simple, you need to remove the `com.apple.quarantine` extended attribute. + * - OS + - Download + * - Windows + - `Espressif-IDE-win32.win32.x86_64 `_ + * - macOS x86_64 + - `Espressif-IDE-macosx-cocoa-x86_64 `_ + * - macOS aarch64 + - `Espressif-IDE-macosx-cocoa-aarch64 `_ + * - Linux + - `Espressif-IDE-linux.gtk.x86_64 `_ + + +macOS Security Notice (Applicable Only for Nightly Builds) +---------------------------------------------------------- + +On macOS, if you download the archive using a web browser, the strict security checks in recent macOS versions will prevent it from running and display a message that the program is damaged. This is not actually true, and the fix is simple: you just need to remove the ``com.apple.quarantine`` extended attribute. .. code-block:: shell $ xattr -d com.apple.quarantine ~/Downloads/Espressif-IDE-x.x.x-macosx.cocoa.x86_64.tar.gz -After un-archiving, if the application still complains, check/remove the attribute from the Espressif-IDE.app folder too: +After unpacking the archive, if the application still shows the same warning, check and remove the attribute from the ``Espressif-IDE.app`` folder as well: .. code-block:: shell - $ xattr -dr com.apple.quarantine ~/Downloads/Espressif-IDE.app \ No newline at end of file + $ xattr -dr com.apple.quarantine ~/Downloads/Espressif-IDE.app diff --git a/docs/en/faqs.rst b/docs/en/faqs.rst index 7e0d5505c..8f27adf7f 100644 --- a/docs/en/faqs.rst +++ b/docs/en/faqs.rst @@ -1,189 +1,209 @@ FAQ ==== +:link_to_translation:`zh_CN:[中文]` + How do I know the installed version of Java in my system? ---------------------------------------------------------- -You can check using `java -version` command from the terminal. + +You can check using ``java -version`` command from the terminal. How to check the Java version used by Eclipse? ---------------------------------------------- -- `Help > About Eclipse > Installation Details > Configuration` -- Look for `-vm` argument. -How to increase the heap memory for Java while working Eclipse IDE? --------------------------------------------------------------------- -- Locate the eclipse.ini or espressif-ide.ini -- Increase the Xmx value under the `-vmargs` args section. For example, you can set to `-Xmx2048m`. +1. Go to ``Help`` > ``About Eclipse`` > ``Installation Details`` > ``Configuration``. +2. Look for ``-vm`` argument. + +How to increase the heap memory for Java while using Eclipse IDE? +----------------------------------------------------------------- + +1. Locate the ``eclipse.ini`` or ``espressif-ide.ini``. +2. Increase the Xmx value under the ``-vmargs`` args section. For example, you can set to ``-Xmx2048m``. What are the operating systems the plugin supports? ----------------------------------------------------- +--------------------------------------------------- + - Windows -- macOSX +- macOS - Linux How do I provide Eclipse environment and plugins information? ------------------------------------------------------------- -`Help > About Eclipse > Installation Details > Configuration > Copy to Clipboard` + +``Help`` > ``About Eclipse`` > ``Installation Details`` > ``Configuration`` > ``Copy to Clipboard`` How do I know the installed IDF Eclipse Plugins version? ---------------------------------------------------------- -- You can check using the menu `Eclipse > About Eclipse > Installation Details > Installed Software` -- Search for `Espressif`. +-------------------------------------------------------- + +1. Go to the menu ``Eclipse`` > ``About Eclipse`` > ``Installation Details`` > ``Installed Software``. +2. Search for "Espressif". How do I uninstall IDF Eclipse Plugins from the Eclipse? ---------------------------------------------------------- -- `Eclipse > About Eclipse > Installation Details > Installed Software` -- Search for `Espressif`. -- Select the Espressif IDF Feature -- `Uninstall..`. +-------------------------------------------------------- + +1. Go to ``Eclipse`` > ``About Eclipse`` > ``Installation Details`` > ``Installed Software``. +2. Search for "Espressif". +3. Select ``Espressif IDF Feature``. +4. Click ``Uninstall..``. Unable to install IDF plugins in Eclipse? ----------------------------------------- -Please check the error log from the main menu, select `Window > Show View > Other`. Then select `General > Error Log`. -Espressif Menu options and Espressif IDF Project menu are not visible in my Eclipse CDT ---------------------------------------------------------------------------------------- -- Make sure you have installed Java 8 and above and Eclipse in the C/C++ perspective. -- Reset the perspective using `Window > Perspective > Reset Perspective..`. +Please check the error log from the main menu: + +1. Go to ``Window`` > ``Show View`` > ``Other``. +2. Then select ``General`` > ``Error Log``. + +Espressif Menu options and Espressif IDF Project menu are not visible in my Eclipse CDT. +---------------------------------------------------------------------------------------- + +1. Make sure you have installed Java 8 and above and Eclipse in the C/C++ perspective. +2. Reset the perspective using ``Window`` > ``Perspective`` > ``Reset Perspective..``. Do IDF Eclipse Plugins support CMake IDF project creation? ---------------------------------------------------------- -Yes, you can create IDF CMake project using `File > New > Espressif IDF Project`. + +Yes, you can create IDF CMake project using ``File`` > ``New`` > ``Espressif IDF Project``. Can I import my existing IDF project into Eclipse? --------------------------------------------------- -Yes, you can import using Import Menu. `Import... > Espressif > Existing IDF Project`. + +Yes, you can import using Import Menu. ``Import...`` > ``Espressif`` > ``Existing IDF Project``. Where can I find the IDF installed tools in my system? ------------------------------------------------------ -Default directory is `$HOME/.espressif` for Linux/MacOS users or `%USER_PROFILE%.espressif` for Windows users. -Why am I getting timeout errors when Installing tools? ------------------------------------------------------- -If you are getting errors when downloading or installing tools this can be due to some issue with the mirrors. You can try to set the mirrors in Eclipse `Preferences > Espressif` you will see two settings for Git and Pip Py Wheels please set these to proper mirror according to your region. Currently, these two mirrors are available. +Default directory is ``$HOME/.espressif`` for Linux/MacOS users or ``%USER_PROFILE%.espressif`` for Windows users. -### Mirror for GIT (IDF_GITHUB_ASSETS) -- dl.espressif.com/github_assets (default) -- dl.espressif.cn/github_assets +Why do deleted C/C++ build environment variables still appear? +-------------------------------------------------------------- -### Mirror for python wheels (PIP_EXTRA_INDEX_URL) -- https://dl.espressif.com/pypi (default) -- https://dl.espressif.cn/pypi +You need to uncheck the preference recorder. This can be performed by the following: -Deleted C/C++ build environment variables still appearing? ----------------------------------------------------------- -- You need to uncheck the preference recorder. This can be performed by following. Eclipse `Preferences > Oomph > Setup Tasks > Preference Recorder`. -- Uncheck `Record into`. +1. Go to ``Preferences`` > ``Oomph`` > ``Setup Tasks`` > ``Preference Recorder``. +2. Uncheck ``Record into``. How can I rollback to old ESP-IDF Eclipse plugin? ------------------------------------------------- -- Open Eclipse IDE and Uninstall the esp-idf plugin. -- Restart Eclipse IDE. -- Download the previous version of the ESP Eclipse Plugin from the release page -- Go to `Help > Install New Software`. -- Press the `Add` button, a window will open with the name of `Add Repository`. -- Press the `Archive` button and select the file downloaded. -- Proceed with the installation. -- Restart Eclipse. - -Where can I find Compiler_commands.json file for the project? --------------------------------------------------------------- -`/projectName/build/compile_commands.json` -compile_commands.json containing the exact compiler calls for all translation units of the project in machine-readable form which is used by the Eclipse CDT indexing for parsing and resolving headers. +1. Open Eclipse IDE and Uninstall the ESP-IDF plugin. +2. Restart Eclipse IDE. +3. Download the previous version of the ESP Eclipse Plugin from the release page. +4. Go to ``Help`` > ``Install New Software``. +5. Press the ``Add`` button, a window will open with the name of ``Add Repository``. +6. Press the ``Archive`` button and select the file downloaded. +7. Proceed with the installation. +8. Restart Eclipse. + +Where can I find the ``compile_commands.json`` file for the project? +-------------------------------------------------------------------- + +You can find it at ``/projectName/build/compile_commands.json``. + +``compile_commands.json`` contains the exact compiler calls for all translation units of the project in machine-readable. It is used by the Eclipse CDT indexer for parsing and resolving headers. How do I access CDT Parser error log? -------------------------------------- -Please follow this menu. `Project > C/C++ Index > Create Parser Log`. + +Please go to ``Project`` > ``C/C++ Index`` > ``Create Parser Log``. How do I access the error log? ------------------------------ -To view the Eclipse error log: From the main menu, select `Window > Show View > Other`. Then select `General > Error Log`. + +From the main menu, select ``Window`` > ``Show View`` > ``Other``. Then select ``General`` > ``Error Log``. How do I report a deadlock or Eclipse hang? ------------------------------------------- + You can find the detailed instructions here: https://wiki.eclipse.org/How_to_report_a_deadlock. -- On the command line, use `jps -v` to find the PIDs of Java processes and `jstack ` to show the stack trace of Java processes. -Here 32308 and 8824 are PIDs of Java processes. 8824 is jps itself and is of no interest for us. 32308 is an Eclipse process judging from the presence of `org.eclipse.equinox.launcher` in its command line. The `jstack` command saves the stack trace of the Eclipse process in a file `/tmp/jstack.txt`, attach the file to the bug report. +On the command line, use ``jps -v`` to find the PIDs of Java processes and ``jstack `` to show the stack trace of Java processes. + +Here 32308 and 8824 are PIDs of Java processes. 8824 is jps itself and is of no interest for us. 32308 is an Eclipse process judging from the presence of ``org.eclipse.equinox.launcher`` in its command line. The ``jstack`` command saves the stack trace of the Eclipse process in a file ``/tmp/jstack.txt``, attach the file to the bug report. -`sun.security.validator.ValidatorException: PKIX path building failed:` error +``sun.security.validator.ValidatorException: PKIX path building failed`` error ------------------------------------------------------------------------------ -This would have been caused by the Java version or Java certificates. Please make sure you've installed `Java 11 and later` to fix this error. -Check below links: + +This issue is likely caused by the Java version or missing Java certificates. Please ensure that **Java 11 or later** is installed to resolve the error. Refer to the links below for more details: + - https://esp32.com/viewtopic.php?f=13&t=12327&start=10#p50137 - https://stackoverflow.com/questions/6908948/java-sun-security-provider-certpath-suncertpathbuilderexception-unable-to-find -Why Java 11 recommended for IDF Eclipse Plugin? ------------------------------------------------ -We recommend using Java 11 (that's the latest LTS version from Oracle) and above while working with IDF Eclipse Plugin considering Eclipse 2020-06 has a requirement for Java 11 to work with the CDT. Here are some important pointers from Eclipse. +Why is Java 11 recommended for the IDF Eclipse Plugin? +------------------------------------------------------ + +We recommend using Java 11 (the latest LTS version from Oracle) or later when working with the IDF Eclipse Plugin. This is because Eclipse 2020-06 requires Java 11 to work properly with the CDT. Here are some important pointers from Eclipse: -### Installing CDT 9.11 on Eclipse 2020-06 and later requires a workaround when using Java 8 -Check this - https://wiki.eclipse.org/CDT/User/NewIn911#Release +- `Installing CDT 9.11 on Eclipse 2020-06 and later requires a workaround when using Java 8 `_. -CDT 9.11 only requires Java 8 to run. However, a new feature in Eclipse 2020-06 and later means that the install wizard may prevent installation. The workaround is to disable "Verify provisioning operation is compatible with the currently running JRE" in Windows -> Preferences -> Install/Update. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=564407#c1. + CDT 9.11 only requires Java 8 to run. However, a new feature in Eclipse 2020-06 and later means that the Install wizard may prevent installation. The workaround is to disable "Verify provisioning operation is compatible with the currently running JRE" in ``Windows`` > ``Preferences`` > ``Install/Update``. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=564407#c1. -### CDT 10.0 required Java 11 or later -Check this - https://wiki.eclipse.org/CDT/User/NewIn100 +- `CDT 10.0 requires Java 11 or later `_. -Starting with CDT 10.0, Java 11 or later is required to run CDT. This aligns with the requirements of Eclipse IDE which also requires Java 11 to run starting in 2020-09. + Starting with CDT 10.0, Java 11 or later is required to run CDT. This aligns with the requirements of Eclipse IDE which also requires Java 11 to run starting in 2020-09. -How to delete Launch Targets from the Eclipse +How to delete launch targets from the Eclipse --------------------------------------------- + There is no UI option to delete launch targets directly from Eclipse, however, this can be achieved by following the below instructions: -- Go to the Eclipse workspace directory. For example: In my case `/Users/myName/myTesteclipseWorkspace`. -- Navigate to `.metadata/.plugins/org.eclipse.core.runtime/.settings` folder in the workspace directory. -- Look for `org.eclipse.launchbar.core.prefs` file and open it in the editor. -- Search for the launch target name you want to delete and remove all those entries from the file. -- Save the file. -- Restart Eclipse. + +1. Go to the Eclipse workspace directory. For example, in my case: ``/Users/myName/myTesteclipseWorkspace``. +2. Navigate to ``.metadata/.plugins/org.eclipse.core.runtime/.settings`` folder in the workspace directory. +3. Look for ``org.eclipse.launchbar.core.prefs`` file and open it in the editor. +4. Search for the launch target name you want to delete and remove all those entries from the file. +5. Save the file. +6. Restart Eclipse. How do I access project build log? ----------------------------------- -- To enable logging, navigate to `Preferences > Project > C/C++ > Build > Logging`. -- Check `Enable global build logging`. -- Build the project. -- Export `global-build.log`. This is the same build console log which appears in the CDT build console, but the build console usually has a limited buffer size, hence it won't display everything. + +1. To enable logging, navigate to ``Preferences`` > ``Project`` > ``C/C++`` > ``Build`` > ``Logging``. +2. Check ``Enable global build logging``. +3. Build the project. +4. Export ``global-build.log``. This is the same build console log which appears in the CDT build console, but the build console usually has a limited buffer size, hence it won't display everything. How do I enable verbose debug output to my project build? ----------------------------------------------------------- +--------------------------------------------------------- + IDF Eclipse plugin uses CMake commands to build the project, so it's possible to pass CMake arguments from the build configuration wizard. To configure this: -- Click on the editor configuration wizard. -- Navigate to `Build Settings` tab. -- Add `--debug-output` or other + +1. Click on the editor configuration wizard. +2. Navigate to ``Build Settings`` tab. +3. Add ``--debug-output`` or other. How do I build multiple configurations in Espressif-IDE? ----------------------------------------------------------- -- Create a new project. -- Open the `Launch Configuration` dialog. -- Navigate to the `Build Settings` tab and enter `-B build_release` in the `Additional CMake Arguments` section. Here, `build_release` is the name of the build folder. -- Click the `OK` button to save the configuration. -- Reopen the `Launch Configuration` dialog. -- Click the `Duplicate` button (located at the bottom left corner). -- Navigate to the `Build Settings` tab and update the `Additional CMake Arguments` section to `-B build_dev`. Here, `build_dev` is the name of the build folder. -- Click the `OK` button to save the configuration. -- Click the Build icon from the toolbar (the leftmost icon) for the selected configuration. This will build the project and create a build folder for that configuration. Repeat the same process for the other configuration by selecting it from the dropdown. - -Can I Use My Old C/C++ Editor Formatter File (.xml) as a .clang-format File? ----------------------------------------------------------------------------- -No, you cannot directly use the old `.xml` (CDT formatter) file with ESP-IDF projects, as these now use the CDT LSP Editor, which relies on Clangd for code formatting. Clangd requires a `.clang-format` file, and there is no official tool to convert `.xml` formatter files to the Clang format. - -However, Clang provides several default formatting styles (such as LLVM, Google, Mozilla, etc.) that you can use as a starting point. You can generate a default `.clang-format` file using the following command: +-------------------------------------------------------- -.. code-block:: none +1. Create a new project. +2. Open the ``Launch Configuration`` dialog. +3. Navigate to the ``Build Settings`` tab and enter ``-B build_release`` in the ``Additional CMake Arguments`` section. Here, ``build_release`` is the name of the build folder. +4. Click the ``OK`` button to save the configuration. +5. Reopen the ``Launch Configuration`` dialog. +6. Click the ``Duplicate`` button at the bottom left corner. +7. Navigate to the ``Build Settings`` tab and update the ``Additional CMake Arguments`` section to ``-B build_dev``. Here, ``build_dev`` is the name of the build folder. +8. Click the ``OK`` button to save the configuration. +9. Click the ``Build`` icon from the toolbar (the leftmost icon) for the selected configuration. This will build the project and create a build folder for that configuration. Repeat the same process for the other configuration by selecting it from the dropdown. + +Can I use my old C/C++ editor formatter file (.xml) as a ``.clang-format`` file? +-------------------------------------------------------------------------------- + +No, you cannot directly use the old ``.xml`` (CDT formatter) file with ESP-IDF projects, as these now use the CDT LSP Editor, which relies on Clangd for code formatting. Clangd requires a ``.clang-format`` file, and there is no official tool to convert ``.xml`` formatter files to the Clang format. - clang-format -style=llvm -dump-config > .clang-format +However, Clang provides several default formatting styles (such as LLVM, Google, Mozilla, etc.) that you can use as a starting point. You can generate a default ``.clang-format`` file using the following command: + +.. code-block:: none -For new ESP-IDF projects, a `.clang-format` file is automatically created in the root directory with default settings. This file is picked up by Clangd automatically—no additional configuration is needed. + clang-format -style=llvm -dump-config > .clang-format -For existing projects, you can create this file manually by right-clicking the project and selecting: +For new ESP-IDF projects, a ``.clang-format`` file is automatically created in the root directory with default settings. This file is picked up by Clangd automatically — no additional configuration is needed. - ESP-IDF > Create Clangd File +For existing projects, you can create this file manually by right-clicking the project and selecting ``ESP-IDF`` > ``Create Clangd File``. If you would like to replicate your old formatter settings, you can either: -- Manually map your `.xml` settings to Clang format using Clang’s formatting guide. -- Or Use an AI tool(e.g: ChatGPT) to assist in converting your old configuration to the new one and then manually adjust if there are any discrepancies. +- Manually map your ``.xml`` settings to Clang format using Clang's formatting guide. +- Or use an AI tool (e.g., ChatGPT) to assist in converting your old configuration to the new one. After that, manually adjust any discrepancies. -More information on the Clang format can be found in the `Clang Format documentation `_ and formatting styles can be found in the `Clang Format Style Options `_. +More information on the Clang format can be found in the `ClangFormat documentation `_. +Formatting styles can be found in the `Clang-Format Style Options `_. diff --git a/docs/en/flashdevice.rst b/docs/en/flashdevice.rst index 24742de29..578fd358a 100644 --- a/docs/en/flashdevice.rst +++ b/docs/en/flashdevice.rst @@ -1,26 +1,26 @@ -Flash onto the Device -=============================== +Flash the Device +================ + +:link_to_translation:`zh_CN:[中文]` .. |run_icon| image:: ../../media/icons/run.png :height: 16px :align: middle -Flash operation can be initiated with just a click of a launch button |run_icon| and it's auto-configured to flash the application with the default flash command, i.e., ``idf.py -p PORT flash``. +You can start the flash operation by clicking the launch button |run_icon|. The process is automatically configured to flash the application using the default command: ``idf.py -p PORT flash``. .. image:: https://github.com/espressif/idf-eclipse-plugin/assets/8463287/3249c01b-af23-4863-811f-c3959008f257 :width: 767px :alt: flash -To provide customized flash arguments, please follow :ref:`this link ` for further instructions. - -To enable flash encryption, please see the :ref:`Flash Encryption guide `. - -To configure flashing via JTAG, please refer to this :ref:`JTAG Flashing guide ` +- To provide customized flash arguments, please refer to :ref:`this guide `. +- To enable flash encryption, please refer to :ref:`Flash Encryption `. +- To configure flashing via JTAG, please refer to :ref:`JTAG Flashing `. .. _customizeLaunchConfig: Customize Flash Arguments -------------------------------- +------------------------- To provide the customized launch configuration and flash arguments, follow the steps below: @@ -28,17 +28,17 @@ To provide the customized launch configuration and flash arguments, follow the s #. Switch to the ``Main`` tab. #. Specify the ``Location`` where this application has to run. Since ``idf.py`` is a Python file, configure the Python system path. Example: ``${system_path:python}``. #. Specify the ``Working directory`` of the application. Example: ``${workspace_loc:/hello_world}``. -#. In the **Arguments** field (see **1** in the image), the default value uses **dynamic variables**: +#. In the ``Arguments`` field (see ``1`` in the image), the default value uses **dynamic variables**: - ``${IDF_PY} -B ${BUILD_DIR} -p ${serial_port} ${flash_command}`` + ``${IDF_PY} -B ${BUILD_DIR} -p ${serial_port} ${flash_command}`` - This default setup automatically adapts to your project and board, so usually no manual changes are needed. + This default setup automatically adapts to your project and board, so usually no manual changes are needed. - - Use the **Preview icon** (see **2**) to switch between showing resolved values and the raw dynamic variables. - - The field is **modifiable only** when dynamic variables are shown (not resolved). - - If you are migrating from an older plugin version and the field does not contain dynamic variables, click **Restore Defaults** (see **3**) to reset it. + - Use the ``Preview`` icon (see ``2`` in the image) to switch between showing resolved values and the raw dynamic variables. + - The field is **modifiable only** when dynamic variables are shown (not resolved). + - If you are migrating from an older plugin version and the field does not contain dynamic variables, click ``Restore defaults`` (see ``3`` in the image) to reset it. -#. Click **OK** to save the settings. +#. Click ``OK`` to save the settings. #. Click on the ``Launch`` icon to flash the application to the selected board. .. image:: ../../media/launch_configuration.png @@ -55,37 +55,35 @@ Flash Encryption .. warning:: - Enabling flash encryption is an **irreversible operation**. - If configured incorrectly, the board may become permanently unusable. - Proceed with caution and only enable this option if you fully understand its implications. + Enabling flash encryption is an **irreversible operation**. If configured incorrectly, the board may become permanently unusable. Proceed with caution and only enable this option if you fully understand its implications. To enable flash encryption in ESP-IDF, follow these steps: -#. Open ``sdkconfig`` and enable the ``Enable flash encryption on boot`` option. +#. Open ``sdkconfig`` and enable the ``Enable flash encryption on boot`` option. -.. image:: ../../media/flash_encryption_1.png - :alt: Flash encryption sdkconfig + .. image:: ../../media/flash_encryption_1.png + :alt: Flash encryption sdkconfig -#. Perform a normal flash of the application. -#. Open the **Launch Configuration** dialog, edit the configuration, and check the **Enable Flash Encryption** box. +#. Perform a normal flash of the application. +#. Open the ``Launch Configuration`` dialog, edit the configuration, and check the ``Enable Flash Encryption`` box. -.. image:: ../../media/flash_encryption_2.png - :alt: Flash encryption checkbox + .. image:: ../../media/flash_encryption_2.png + :alt: Flash encryption checkbox -#. Flash the application again. +#. Flash the application again. Once enabled, flash encryption will automatically secure the contents of the flash memory according to ESP-IDF settings. -For more details, please refer to the official -`ESP-IDF Flash Encryption documentation `_. +For more details, please refer to the official `Flash Encryption `_ documentation. .. _JTAGFlashing: Upload Application via JTAG -------------------------------- +--------------------------- + +The default method for uploading applications is UART. To switch to JTAG, edit the launch configuration of your project and select the appropriate option. -The default option for uploading applications is UART. To change it to JTAG, you need to edit the launch configuration for your project and select the appropriate option. To do so, select your project in the launch configuration bar and click on the gear icon to edit the launch configuration: .. image:: ../../media/JtagFlash_1.png @@ -97,7 +95,7 @@ Then select the ``Flash Over JTAG`` option and complete the ``OpenOCD Setup`` se :width: 986px :alt: Flash over JTAG option -If the ``Flash Over JTAG`` option is not available and you see a message like this: +If the ``Flash Over JTAG`` option is not available, and you see a message like this: .. image:: ../../media/JtagFlash_3.png :alt: OpenOCD update required message @@ -107,15 +105,16 @@ It means that OpenOCD needs to be updated. You can find the latest OpenOCD versi Providing the Right Path for OpenOCD ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -After downloading the necessary `OpenOCD version `_, extract it to a new folder in the `.espressif/tools/openocd-esp32/`. Follow these steps: +After downloading the necessary `OpenOCD version `_, extract it to a new folder in the ``.espressif/tools/openocd-esp32/``. -* Download the required `v0.10.0-esp32-20201202 `_ version or a higher one for JTAG Flashing. -* Go to `.../.espressif/tools/openocd-esp32/`, create a new folder named ``v0.10.0-esp32-20201202``, and extract OpenOCD there. -* The resulting path to OpenOCD might look like: ``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/...`` +Follow these steps: -After completing this, update the ``OPENOCD_SCRIPT`` environment variable in Eclipse: +1. Download the required `v0.10.0-esp32-20201202 `_ version or a higher one for JTAG flashing. +2. Go to ``.../.espressif/tools/openocd-esp32/``, create a new folder named ``v0.10.0-esp32-20201202``, and extract OpenOCD there. +3. The resulting path to OpenOCD might look like: ``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/...``. -* Go to ``Eclipse > Preferences > C/C++ > Build > Environment`` -* Edit the ``OPENOCD_SCRIPTS`` variable by providing the correct path to the ``openocd/scripts`` folder. -* The path to the OpenOCD scripts may look like this: ``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/share/openocd/scripts`` +After completing this, update the ``OPENOCD_SCRIPT`` environment variable in Eclipse: +1. Go to ``Eclipse`` > ``Preferences`` > ``C/C++`` > ``Build`` > ``Environment``. +2. Edit the ``OPENOCD_SCRIPTS`` variable by providing the correct path to the ``openocd/scripts`` folder. +3. The path to the OpenOCD scripts may look like this: ``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/share/openocd/scripts``. diff --git a/docs/en/index.rst b/docs/en/index.rst index a39c38cb6..4e9050c5c 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -1,12 +1,14 @@ Espressif-IDE -========================= +============= + :link_to_translation:`zh_CN:[中文]` Espressif-IDE is an Integrated Development Environment (IDE) based on `Eclipse CDT `_ for developing IoT Applications using the `ESP-IDF `_. It's a standalone and customized IDE built specifically for ESP-IDF. Espressif-IDE comes with the IDF Eclipse plugins, essential Eclipse CDT plugins, and other third-party plugins from the Eclipse platform to support building ESP-IDF applications. -The plug-in runs on `macOS`, `Windows` and `Linux` platforms. +The plug-in runs on **macOS**, **Windows** and **Linux** platforms. + +.. note:: -.. note:: Espressif-IDE version 3.0 and later supports ESP-IDF version 5.x and above. For ESP-IDF version 4.x and earlier, please use Espressif-IDE version `2.12.1 `_. .. image:: ../../media/espressif-ide.png @@ -14,7 +16,7 @@ The plug-in runs on `macOS`, `Windows` and `Linux` platforms. :align: center Features ----------------- +-------- - Auto-configuration of the build environment variables - Integrated toolchain configuration @@ -23,7 +25,7 @@ Features - Pre-built function header and function definition navigation - ESP-IDF and ESP-IDF tools installation and configuration directly from the IDE - SDK configuration editor for project-specific settings -- Integrated CMake editor plug-in for editing CMake files such as CMakeLists.txt +- Integrated CMake editor plug-in for editing CMake files such as ``CMakeLists.txt`` - CMake-based build support - Support for UART and JTAG flashing - Customized ESP-IDF OpenOCD debugging with pre-built configuration and settings @@ -34,23 +36,24 @@ Features - Supports GDB stub debugging and application-level tracing - English and Chinese language support for the IDE -For more about this project please see https://github.com/espressif/idf-eclipse-plugin +For more about this project, please see https://github.com/espressif/idf-eclipse-plugin. Contents ----------------- +-------- + .. toctree:: :maxdepth: 1 Prerequisites Installation - Start a Project - Connect Your Device - Build the Project - Configure Your Project - Flash onto the Device - Monitor the Output - Debug Your Project - Additional IDE Features - Troubleshooting - FAQs - Downloads + Start Your Project + Connect Your Device + Build Your Project + Configure Your Project + Flash the Device + Monitor the Output + Debug Your Project + Additional IDE Features + Troubleshooting + FAQs + Downloads diff --git a/docs/en/installation.rst b/docs/en/installation.rst index e4a484cbc..1896e6b66 100644 --- a/docs/en/installation.rst +++ b/docs/en/installation.rst @@ -1,71 +1,104 @@ Installation -=============================== +============ -Configuring and installing the Espressif-IDE involves two main steps: +:link_to_translation:`zh_CN:[中文]` -1. :ref:`Downloading and Installing the Espressif-IDE ` -2. :ref:`Installing the ESP-IDF and related tools within the Espressif-IDE ` +Configuring and installing the Espressif-IDE involves three main steps: + +1. :ref:`Download and Installing the Espressif-IDE ` +2. :ref:`Install the ESP-IDF and related tools within the Espressif-IDE ` +3. :ref:`Migrate old workspace to new ` .. note:: - For Eclipse CDT users who prefer installing the ESP-IDF Eclipse Plugin via the `Update site `_, please refer to the :ref:`Update Site Installation Guide `. -Espressif-IDE Installation ----------------------------- + For Eclipse CDT users who prefer installing the ESP-IDF Eclipse Plugin via the `update site `_, please refer to the :ref:`Update Site Installation Guide `. + .. _esp-idf-installation: -To begin, navigate to the section corresponding to your operating system below and follow the provided instructions to install the Espressif-IDE. +Espressif-IDE Installation +-------------------------- + +To begin, navigate to the section below corresponding to your operating system, and follow the provided instructions to install the Espressif-IDE. + +Please note that the Espressif-IDE requires that you install ESP-IDF via Espressif Installation Manager (EIM) to manage the ESP-IDF versions and tools. For detailed documentation on using the EIM, please refer to the `official guide `_. Windows ~~~~~~~~ + .. note:: - For Windows users, Espressif-IDE is available with ESP-IDF as an offline installer. - -To download and install it, follow the instructions provided :ref:`here `. This guide will walk you through the installation process for Java, Git, CMake, ESP-IDF, IDF Tools, Device Drivers, and Espressif-IDE to help you get started. + + For Windows users, Espressif-IDE is available with ESP-IDF as an offline installer. macOS/Linux ~~~~~~~~~~~~ + Download the Espressif-IDE for your respective operating system from the :ref:`download section `. After downloading, launch the IDE and proceed to :ref:`install the necessary ESP-IDF and related tools `. Please ensure that Java, Python, and Git are installed as prerequisites and are available in the system path before launching the IDE. -ESP-IDF and Tools Installation -------------------------------- .. _esp-idf-tools-installation: -The Espressif-IDE provides a tool manager to install and manage ESP-IDF and related tools. Please follow the instructions below for installing ESP-IDF in the Espressif-IDE. +ESP-IDF and Tools Installation (New Workspace) +---------------------------------------------- + +The Espressif-IDE provides a tool manager view that allows you to activate available ESP-IDF versions and manage related tools. To install the ESP-IDF and its tools, first download the EIM from the following `link `__. + +After downloading and launching EIM, follow the on-screen instructions to install the required ESP-IDF version and associated tools. Once the installation is complete, you can use the ESP-IDF Manager within the IDE to activate the installed ESP-IDF version in the workspace. The Espressif-IDE allows you to download and launch the EIM directly from the IDE, making it easier to manage your ESP-IDF versions and tools. When you open a workspace created with an old version of Espressif-IDE, the IDE will prompt you to convert its configuration to be compatible with EIM. -1. Go to ``Espressif > ESP-IDF Manager``. The following editor will open: +Follow these steps inside the Espressif-IDE to install the ESP-IDF and related tools: - .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png +1. Go to ``Espressif`` > ``ESP-IDF Manager``. The following editor will open: -2. Click on the ``Add ESP-IDF`` button. + .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png - .. image:: ../../media/ToolsManager/ESP-IDF_Configuration_Download_or_Use_ESP-IDF.png +2. Click the ``Launch EIM`` or ``Download & Launch EIM`` button if you have not downloaded and installed EIM. - From the screen shown above, you can choose an already downloaded ESP-IDF directory or select and download directly from the given dialog. The ``Git`` and ``Python`` tools must be installed, and if they are configured in the system PATH, they will be preloaded in the view. If not, you can browse to the directory and select the proper executables. + You will see the progress of download and installation in the console. Once the EIM is launched, you can use it to install the ESP-IDF and related tools. -3. Click on ``Finish``, which will be enabled after all paths and executables are properly configured. +3. Once you close the EIM, your ESP-IDF Manager editor will be updated with the latest information about the ESP-IDF versions and tools available. + + .. image:: ../../media/ToolsManager/Tool_installed_and_activated.png .. note:: - Please note that the python executable is not the one from the virtual environment created from the installation of the ESP-IDF via other means like from CLI. If you are selecting an already installed ESP-IDF directory IDE will automatically pick up the python once you have installed the tools -After you have clicked ``Finish``, you will see the progress in the console for the tools getting installed. Once the installation is done, and if this is the very first set of ESP-IDF installed in the IDE, it will be activated as well. You will see a similar entry in the editor for ESP-IDF Manager: + Please note that the EIM will be the only tool going forward to manage the ESP-IDF versions and tools. Previous versions of the Espressif-IDE managed tools internally, but now all access to ESP-IDF is handled through the EIM. + +You can add as many versions of ESP-IDF as you want via EIM, but only one version can be set as active, and that version will be used to compile and index projects in your workspace. This feature helps you switch between versions in the workspace easily. + +To activate any specific version, simply click the radio button next to it in the ``Active`` column. + +The refresh button in the last column for the active ESP-IDF version can be used to reload any changes in the ESP-IDF directory you made. + +.. note:: -.. image:: ../../media/ToolsManager/Tool_installed_and_activated.png + Any manual changes made to the ESP-IDF directory will not be reflected in the IDE until you refresh the active ESP-IDF version using the refresh button. However, if you made any changes to the installation of ESP-IDF using the EIM, those changes will be detected and a popup message will be shown to you to update the ESP-IDF version in the IDE. -You can add as many versions of ESP-IDF as you want, but only one version can be set as active, and that version will be used to compile and index projects in your workspace. This feature helps you switch between versions in the workspace easily. +.. image:: ../../media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png -Let's take a look at how multiple versions will look. Follow the same steps as before to add another ESP-IDF version to the IDE. +.. _esp-idf-tools-migration: -.. image:: ../../media/ToolsManager/ESP-IDF_Manager_Multiple_versions.png +Old-to-New Workspace Migration +------------------------------ -To activate any specific version, simply click on the radio button next to it in the ``Active`` column. +If you are migrating from an old version of the Espressif-IDE, you will need to convert your existing workspace to be compatible with the new ESP-IDF Manager. You will need to download and install the EIM from the following `link `__. After installation of the EIM, please follow the steps below: -The refresh button in the last column for the active ESP-IDF version can be used to reload any changes in the directory you made. +1. Place the downloaded EIM executable in the appropriate location according to your operating system: + + - **Windows**: `C:\Users\\.espressif\eim_gui\eim.exe` + - **Linux**: `~/.espressif/eim_gui/eim` + - **macOS**: Copy the ``eim.app`` bundle to your ``Applications`` folder, for example `/Applications/eim.app`. + +2. Open the Espressif-IDE. If it is already running, restart the IDE. +3. After the IDE detects the EIM executable and a valid old workspace, it will prompt you to convert the old workspace to the new format. + + .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Conversion.png + +4. Click the ``Yes`` button to convert the old configuration. +5. Now in Espressif-IDE, go to ``Espressif`` > ``ESP-IDF Manager``. The ESP-IDF Manager editor will open, and you can proceed to select and activate the ESP-IDF version you want. References ---------- + .. toctree:: :maxdepth: 1 - Update Site Installation Guide - Windows Offline Installer - Configure CDT Build Environment Variables \ No newline at end of file + Update Site Installation Guide + Configure CDT Build Environment Variables diff --git a/docs/en/marketplaceupdate.rst b/docs/en/marketplaceupdate.rst index d8b3fb205..4c566a60f 100644 --- a/docs/en/marketplaceupdate.rst +++ b/docs/en/marketplaceupdate.rst @@ -1,37 +1,40 @@ .. _marketplaceupdate: Update Site Installation Guide -====================================== +============================== -The Espressif-IDE Eclipse Plugin can be installed using the update site URL, Eclipse Marketplace, or a local archive. This guide provides instructions for each method. +:link_to_translation:`zh_CN:[中文]` + +The Espressif-IDE Eclipse Plugin can be installed using the following three methods: - :ref:`installUpdateSiteURL` - :ref:`install_idf_eclipse_plugin_marketplace` - :ref:`install_idf_eclipse_plugin_local_archive` -- :ref:`upgradePlugins` -- :ref:`upgradeEspressifIdeDependencies` -- :ref:`troubleshooting_missing_items` .. _installUpdateSiteURL: -Installing IDF Plugin using update site URL --------------------------------------------- +Installing IDF Plugin Using the Update Site URL +----------------------------------------------- + You can install the IDF Eclipse plugin into an existing Eclipse CDT/Espressif-IDE using the update site URL. First, add the release repository URL as follows: -1. Go to ``Help`` > ``Install New Software``. -2. Click `Add…`, and in the pop-up window: - * Enter `Name` as `Espressif IDF Plugin for Eclipse`. - * Enter `Location` of the repository - * For the stable release: ``_. - * Click `Add`. -3. Select all from the list and proceed with the installation. +1. Go to ``Help`` > ``Install New Software``. +2. Click ``Add``, and in the pop-up window: + + * Enter ``Espressif IDF Plugin for Eclipse`` as the ``Name``. + * Enter ``Location`` of the repository. (`Stable release `_) + * Click ``Add``. + +3. Select all items from the list and proceed with the installation. For adding beta and nightly builds, you can use the following update site URLs: - * For Beta version: ``_. - * For Nightly build: ``_. + +* `Beta version `_ +* `Nightly build `_ .. note:: - While the screenshots are captured on macOS, the installation instructions are applicable to Windows, Linux, and macOS. + + Although the following screenshots are captured on macOS, the installation steps are the same for Windows and Linux. .. image:: ../../media/idf_update_site_install.png @@ -43,100 +46,91 @@ Installing IDF Eclipse Plugin from Eclipse Marketplace To install the ESP-IDF Eclipse Plugin from the Eclipse Marketplace, follow these steps: -1. Open Eclipse and go to `Help` > `Eclipse Marketplace...`. - +1. Open Eclipse and go to ``Help`` > ``Eclipse Marketplace...``. 2. In the search box, enter **ESP-IDF Eclipse Plugin** to locate the plugin. - -3. Click **Install** and follow the on-screen instructions to complete the installation. - +3. Click ``Install`` and follow the on-screen instructions to complete the installation. 4. After installation, restart Eclipse to activate the plugin. .. _install_idf_eclipse_plugin_local_archive: Installing IDF Eclipse Plugin from Local Archive ------------------------------------------------------- +------------------------------------------------ To install the ESP-IDF Eclipse Plugin from a local archive, follow these steps: -1. Download the latest update site archive for the IDF Eclipse Plugin from [here](https://github.com/espressif/idf-eclipse-plugin/releases). - -2. In Eclipse, go to `Help` > `Install New Software`. - -3. Click the `Add…` button. - -4. In the **Add Repository** dialog, select **Archive** and choose the file `com.espressif.idf.update-vxxxxxxx.zip`. - -5. Click **Add**. - -6. Select **Espressif IDF** from the list and proceed with the installation. - -7. Restart Eclipse after the installation is complete. - +1. Download the latest update site archive for the IDF Eclipse Plugin from `here `_. +2. In Eclipse, go to ``Help`` > ``Install New Software``. +3. Click the ``Add`` button. +4. In the ``Add Repository`` dialog, select ``Archive`` and choose the file ``com.espressif.idf.update-vxxxxxxx.zip``. +5. Click ``Add``. +6. Select ``Espressif IDF`` from the list and continue with the installation. +7. After the installation is complete, restart Eclipse. .. _upgradePlugins: -How do I upgrade my existing IDF Eclipse Plugin? ------------------------------------------------------- +How to Upgrade Existing IDF Eclipse Plugin +------------------------------------------ + If you are installing the IDF Eclipse Plugin for the first time, follow these steps to add the repository for the new release: -1. Go to `Window` > `Preferences` > `Install/Update` > `Available Software Sites`. -2. Click `Add`. -3. Enter the URL of the new repository: `https://dl.espressif.com/dl/idf-eclipse-plugin/updates/latest/`. -4. Click `Ok`. +1. Go to ``Window`` > ``Preferences`` > ``Install/Update`` > ``Available Software Sites``. +2. Click ``Add``. +3. Enter the `URL `_ of the new repository: . +4. Click ``Ok``. If you have already installed the IDF Eclipse Plugin using the update site URL, you can upgrade to the latest version with the following steps: -1. Go to `Help` > `Check for Updates`. -2. If updates are found, select `Espressif IDF Plugins for Eclipse` and deselect all other items. -3. Click `Next` to proceed with the installation. +1. Go to ``Help`` > ``Check for Updates``. +2. If updates are found, select ``Espressif IDF Plugins for Eclipse`` and deselect all other items. +3. Click ``Next`` to proceed with the installation. .. image:: ../../media/Update_plugins.png - + .. _upgradeEspressifIdeDependencies: - + Upgrading from Espressif-IDE 3.3.0 to 3.4.0 ------------------------------------------------------- +------------------------------------------- + If the next version of the plugin requires updated dependencies (e.g., the minimum CDT version has changed from 11.6 to 12), make sure these dependencies are updated during installation from the update site. .. image:: ../../media/Update_dependencies.png - + If the required dependencies are not updated, the installer will display the following error: -`The installation cannot be completed as requested.` + +``The installation cannot be completed as requested.`` To resolve this: -1. Click **Show original error and build my own solution**. -2. Then select both: +1. Click ``Show original error and build my own solution``. +2. Then select both: -- **Update items already installed** -- **Remove items already installed** + - ``Update items already installed`` + - ``Remove items already installed`` .. image:: ../../media/Resolve_update_error.png -This will allow the installer to update or replace any conflicting components and continue the installation successfully. - - +This ensures that the installer can update or replace any conflicting components, allowing the installation to complete successfully. .. _troubleshooting_missing_items: -Troubleshooting: "Cannot complete the install because one or more required items could not be found" ------------------------------------------------------------------------------------------------------ +Troubleshooting +--------------- +If you encounter the error ``Cannot complete the install because one or more required items could not be found.`` during installation, it usually means that the Eclipse Platform update site is not enabled. -This usually happens when the Eclipse Platform update site is not enabled. To resolve this issue: -1. Go to ``Help`` > ``Install New Software``. -2. Click **Manage**. -3. Make sure the option for the **Eclipse Platform - Latest Release Update Site** is enabled. +1. Go to ``Help`` > ``Install New Software``. +2. Click ``Manage``. +3. Make sure the option for the ``Eclipse Platform - Latest Release Update Site`` is enabled. -.. image:: ../../media/Resolve_update_error_2.png + .. image:: ../../media/Resolve_update_error_2.png -4. Apply the changes and close the dialog. -5. Then go to ``Help`` > ``Check for Updates`` and proceed with updating the IDE and its dependencies. +4. Apply the changes and close the dialog. +5. Then go to ``Help`` > ``Check for Updates`` and proceed with updating the IDE and its dependencies. .. note:: - Enabling the Eclipse Platform update site ensures that all required dependencies can be resolved during installation or upgrade. + Enabling the Eclipse Platform update site ensures that all required dependencies are properly resolved during installation or upgrade. diff --git a/docs/en/monitoroutput.rst b/docs/en/monitoroutput.rst index c3b001d1a..dd4c52c85 100644 --- a/docs/en/monitoroutput.rst +++ b/docs/en/monitoroutput.rst @@ -1,9 +1,11 @@ .. _serialMonitor: Monitor the Output -=============================== +================== -To see the serial output in Eclipse, we need to configure the `ESP-IDF Serial Monitor` to connect to the serial port. This is integrated with the `IDF Monitor `_. +:link_to_translation:`zh_CN:[中文]` + +To view the serial output in Eclipse, you need to configure the ESP-IDF Serial Monitor to connect to the serial port. This is integrated with the `IDF Monitor `_. .. image:: ../../media/monitor.png :alt: Serial Monitor @@ -21,8 +23,9 @@ To launch the serial monitor in the IDE, follow the steps below: ESP-IDF Serial Monitor Settings ------------------------------- + ESP-IDF Serial Monitor will allow you to configure the default settings of the serial monitor character limit and number of lines. -1. Navigate to ``Espressif`` from the Eclipse ``Preferences``. +1. In Eclipse, go to ``Espressif`` > ``Preferences``. 2. Click on ``ESP-IDF Serial Monitor Settings``. -3. Provide ``Console Line Width`` and ``Limit Console Output``. \ No newline at end of file +3. Provide ``Console Line Width`` and ``Limit Console Output``. diff --git a/docs/en/openocddebugging.rst b/docs/en/openocddebugging.rst index 872bb3a56..2a18b1f7b 100644 --- a/docs/en/openocddebugging.rst +++ b/docs/en/openocddebugging.rst @@ -3,110 +3,125 @@ ESP-IDF GDB OpenOCD Debugging ============================= +:link_to_translation:`zh_CN:[中文]` + +Create a New Debug Configuration +-------------------------------- -Create a new debug configuration ---------------------------------- Please follow the below steps to create a new debug configuration: -* Right-click on the project -* ``Debug As`` > ``Debug Configurations...`` This will launch a debug configuration window -* On the left Panel, choose ``ESP-IDF GDB OpenOCD Debugging`` -* Right Click and create ``New Configuration`` This will create a new debug configuration for your project +1. Right-click on the project. +2. Go to ``Debug As`` > ``Debug Configurations...``. This will launch a debug configuration window. +3. On the left panel, choose ``ESP-IDF GDB OpenOCD Debugging``. +4. Right click and create ``New Configuration``. This will create a new debug configuration for your project. Please navigate through each tab and configure project specific settings. -.. note:: +.. note:: + Most of the settings are auto-configured by the plugin. .. image:: ../../media/OpenOCDDebug_4.png The other way to create a debug configuration is from the launch configuration bar: -* Expand list with launch/debug configurations -* Click on ``New Launch Configuration...`` -* Select ``ESP-IDF GDB OpenOCD Debugging`` and double click on it or on ``Next >`` button -* In the ``Debugger`` tab, check if the ``Config options`` is right for your board. -* Click on `Finish` +1. Expand list with launch/debug configurations. +2. Click on ``New Launch Configuration...``. +3. Select ``ESP-IDF GDB OpenOCD Debugging`` and double-click on it or on ``Next >`` button. +4. In the ``Debugger`` tab, check if the ``Config options`` is right for your board. +5. Click on ``Finish``. .. image:: ../../media/OpenOCDDebug_9.png Main Tab -------- + 1. Enter the ``Name`` of this configuration, the default name is "{project_name} Configuration". 2. On the ``Main`` tab below, under ``Project:``, press ``Browse`` button and select the project if it's not selected or you want to change it. -3. In the next line ``C/C++ Application:`` should be a relative path to the elf file, for example, "build\hello_world.elf" for `hello_world` project. If the elf file is not there, then likely this project has not been build yet. After building the project, the elf file will appear there, however, you can change it by pressing "Browse" button. +3. In the next line, ``C/C++ Application:`` should be a relative path to the elf file, for example, ``build/hello_world.elf`` for ``hello_world`` project. If the elf file is not there, then likely this project has not been build yet. After building the project, the elf file will appear there. However, you can change it by pressing ``Browse`` button. -The last section on the ``Main`` tab is ``Build (if required) before launching``. If you don't want to build the project each time you are pressing the ``Debug`` button, click ``Disable auto build``. +The last section on the ``Main`` tab is ``Build (if required) before launching``. If you don't want to build the project each time you click the ``Debug`` button, then select ``Disable auto build``. -Points 1 - 3 are shown below. +Points 1–3 are shown below. .. image:: ../../media/OpenOCDDebug_5.png Debugger Tab ------------ -In the ``Debugger`` tab, all parameters are automatically configured to start debugging, you just need to check if the ``Config options`` line is appropriate for your board. It automatically adjusts based on ``Flash voltage`` and ``Board`` options. If you expand the list of boards, only those that match the selected ``Target`` will appear. So, for example, if the selected target is ``esp32``, you will not see ``ESP32-S2-KALUGA-1`` in the list, to see it there, you need to change the target to ``esp32s2`` first. The second option in the debugger tab, which depends on the target, is the `gdb executable`, which is also automatically and dynamically configured based on the target you choose. -Let's take a look at some other options, that you need to check if they auto configured correctly for you: +In the ``Debugger`` tab, all parameters are automatically configured to start debugging, you just need to check if the ``Config options`` line is appropriate for your board. It automatically adjusts based on ``Flash voltage`` and ``Board`` options. If you expand the list of boards, only those that match the selected ``Target`` will appear. So, for example, if the selected target is ``esp32``, you will not see ``ESP32-S2-KALUGA-1`` in the list. To make it appear, you need to change the target to ``esp32s2`` first. The second option in the Debugger tab is ``GDB executable``, which also depends on the selected target and is automatically configured based on it. + +Let's take a look at some other options, that you need to check if they auto-configured correctly for you: -4. The "Executable path" for OpenOCD is based on eclipse preferences, which are configured after tools installation. Check if the "Actual executable" is correct and if it's not, then likely the tools installation went wrong, so you need to check if tools installed correctly to avoid possible problems. If it's still not correct after tools installation, click on "Browse" and select the path to `openocd.exe` manually. -5. In the next step, please make sure that the GDB port is 3333 if you want to use an internal gdb client and the Tcl port is 6666 if you want to use [Application Level Tracing](https://github.com/espressif/idf-eclipse-plugin#application-level-tracing). Also, check `Config options` as described above. -6. In the `GDB Client Setup` section as described above, the gdb executable should be automatically and dynamically configured based on the target you choose. You can change it, by clicking "Browse" button and selecting the path to the gdb executable. By default, the "Commands" line should be `set mem inaccessible-by-default off`. +4. The ``Executable path`` for OpenOCD is based on Eclipse preferences, which are configured after tools installation. Check if the ``Actual executable`` is correct. If it is not, the tools installation likely failed, so make sure tools are installed properly to avoid potential problems. If ``Actual executable`` is still not correct after tools installation, click on ``Browse`` and select the path to ``openocd.exe`` manually. -Points 4 - 6 are shown below. +5. In the next step, please make sure that the GDB port is 3333 if you want to use an internal GDB client, and the TCL port is 6666 if you want to use :doc:`additionalfeatures/appleveltracing`. Also, check ``Config options`` as described above. + +6. In the ``GDB Client Setup`` section as described above, the GDB executable should be automatically and dynamically configured based on the target you choose. You can change it, by clicking ``Browse`` button and selecting the path to the GDB executable. By default, the ``Commands`` line should be ``set mem inaccessible-by-default off``. + +Points 4-6 are shown below. .. image:: ../../media/OpenOCDDebug_6.png -.. note:: - Update the OpenOCD Config options based on the esp board you've choosen. Please check this `here `_. +.. note:: + + Update the OpenOCD ``Config options`` based on the ESP board you've chosen. See details `here `_. Startup Tab ----------- -7. By default, the binaries will be uploaded to your board before joining a debug session, so there is no need to flash them to the target separately. If for some reason you don't want to do that, you can uncheck the ``Flash every time with application binaries`` option. Also, you can check ``Enable verbose output`` option, this will enable debug level 3 - '-d3'. -8. Under ``Initialization Commands``, “Initial Reset.” and “Enable ARM semihosting” are enabled by default. Then, in entry field below, must be the following lines: - .. code-block:: text +7. By default, the binaries will be uploaded to your board before joining a debug session, so there is no need to flash them to the target separately. If for some reason you don't want to do that, you can uncheck the ``Flash every time with application binaries`` option. Also, you can check ``Enable verbose output`` option, which will enable debug level 3 - ``-d3``. + +8. Under ``Initialization Commands``, ``Initial Reset.`` and ``Enable ARM semihosting`` are enabled by default. Then, the following lines must be entered in the field below: - mon reset halt - flushregs - set remote hardware-watchpoint-limit 2 + .. code-block:: text -Points 7 - 8 are shown below. + mon reset halt + flushregs + set remote hardware-watchpoint-limit 2 + +Points 7-8 are shown below. .. image:: ../../media/OpenOCDDebug_7.png 9. Options ``Load Symbols`` and ``Use project binary`` are selected. -10. Further down on the same tab, establish an initial breakpoint to halt CPUs after they are reset by debugger. The plugin will set this breakpoint at the beginning of the function entered under ``Set break point at:``. Checkout this option and enter the name of the main function e.g. app_main in provided field. -11. Checkout ``Continue`` option. This will make the program to resume after ``mon reset halt`` is invoked per point 8. The program will then stop at breakpoint inserted at app_main. -Points 9 - 11 are shown below. +10. Further down on the same tab, establish an initial breakpoint to halt CPUs after they are reset by debugger. The plugin will set this breakpoint at the beginning of the function specified under ``Set break point at:``. Checkout this option and enter the name of the main function, e.g., ``app_main`` in provided field. + +11. Check the ``Continue`` option. This will make the program resume after ``mon reset halt`` is invoked as described in point 8. The program will then stop at breakpoint inserted at ``app_main``. + +Points 9-11 are shown below. .. image:: ../../media/OpenOCDDebug_8.png Common Tab ---------- -You can save your debug logs to an external file. To do this: -* Goto ``Common`` tab. -* Under ``Standard Input and Output`` section: Select Output file checkbox, enter log file name and path where you want logs to be redirected. -* Apply changes and run your application. +You can save your debug logs to an external file. To do this: -.. note:: - Path to the file can be relative if it's located in the workspace (see screenshot below) +1. Go to ``Common`` tab. +2. Under ``Standard Input and Output`` section, select the ``Output File`` checkbox, then enter the log file name and path where you want logs to be redirected. +3. Apply changes and run your application. .. note:: - When specifying a directory path (ending with a separator like ``/`` or ``\``), the system will automatically append ``openocd.log`` as the filename. For example, entering ``/tmp/logs/`` will create the file as ``/tmp/logs/openocd.log``. - .. image:: ../../media/OpenOCDDebug_13.png + - The path can be relative if the file is located in the workspace (see the screenshot below). + - When specifying a directory path (ending with a separator like ``/`` or ``\``), the system will automatically append ``openocd.log`` as the filename. For example, entering ``/tmp/logs/`` will create the file ``/tmp/logs/openocd.log``. + + +.. image:: ../../media/OpenOCDDebug_13.png Preferences for OpenOCD Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + OpenOCD path is auto-configured based on the ``OPENOCD_SCRIPTS`` path defined in the CDT Build environment variables. .. image:: ../../media/OpenOCDDebug_2.png Start Debugging --------------- -To start debugging, you need to select your debug configuration, change mode from ``Run`` to ``Debug`` and click on launch icon (bug icon). + +To start debugging, you need to select your debug configuration, change mode from ``Run`` to ``Debug`` and click on launch icon (i.e., bug icon). .. image:: ../../media/OpenOCDDebug_10.png @@ -114,18 +129,19 @@ After stopping the target at the default breakpoint, you will be suggested to sw .. image:: ../../media/OpenOCDDebug_11.png -You can customize the ``Debug perspective`` in your own way, for example, move some tabs, add additional views that you might find useful, or remove them. To add a view, follow these steps: +You can customize the ``Debug perspective`` to suit your preferences. For example, you can move some tabs, add additional views that you may find useful, or remove the ones you do not need. To add a view, follow these steps: -* On the top panel of the Eclipse click on ``Window`` -* ``Show View`` -* Select the view you want to add +1. On the top panel of the Eclipse, click on ``Window``. +2. Select ``Show View``. +3. Select the view you want to add. .. image:: ../../media/OpenOCDDebug_12.png Troubleshooting --------------- -* Please make sure you always have the latest `Espressif-IDE `_ . -* Please check `this `_ if the board has JTAG enabled. + +* Please make sure you always have the latest `Espressif-IDE `_. +* If your board supports JTAG, see `this page `_ for more details. * If there is any OpenOCD timeout issue, please increase the GDB server timeout value ``_ from the preferences. Usually, this happens while working with large-size applications. -* If you see any error while debugging, please check this OpenOCD troubleshooting `FAQ guide `_ and see if that helps to resolve the issue. -* If you have any issue and want to enable OpenOCD debugging verbose, please check Enable verbose output option from the startup tab. +* If you encounter any errors while debugging, please refer to the OpenOCD `Troubleshooting FAQ `_ to see if it helps resolve the issue. +* If you have any issue and want to enable OpenOCD debugging verbose, please check the ``Enable verbose output`` option from the ``Startup`` tab. diff --git a/docs/en/prerequisites.rst b/docs/en/prerequisites.rst index 7fbfd7e54..e14204275 100644 --- a/docs/en/prerequisites.rst +++ b/docs/en/prerequisites.rst @@ -1,26 +1,31 @@ Prerequisites -=============================== +============= + +:link_to_translation:`zh_CN:[中文]` + This document outlines the necessary requirements for installing and running Espressif-IDE to build applications with ESP-IDF. -Hardware Prerequisites ------------------------ +Hardware +-------- + - A computer running Windows, Linux, or macOS - An ESP32 development board with a USB to serial interface and/or debug port - A USB cable (data + power) compatible with your development board .. Note:: - Currently, some of the development boards are using USB Type C connectors. Be sure you have the correct cable to connect your board! -Software Prerequisites ------------------------ -The minimum requirements for running the Espressif-IDE are listed below. + Currently, some development boards are using USB Type-C connectors. Be sure you have the correct cable to connect your board. -- `Java 21 `_ and above. -- `Python 3.12 `_ and above. -- `Git `_. -- `ESP-IDF Prerequisites `_ based on your Operating System. +Software +-------- -.. note:: - Ensure that Java, Python, and Git are correctly set up and available in the system's PATH environment variable. +The minimum requirements for running the Espressif-IDE are listed below: + +- `Java 21 `_ and above +- `Python 3.12 `_ and above +- `Git `_ +- `ESP-IDF Prerequisites `_ based on your operating system +.. note:: + Ensure that Java, Python, and Git are correctly set up and available in the system's PATH environment variable. diff --git a/docs/en/startproject.rst b/docs/en/startproject.rst index df41d5384..e2426b7df 100644 --- a/docs/en/startproject.rst +++ b/docs/en/startproject.rst @@ -1,54 +1,64 @@ .. _startproject: -Start a Project -=============================== +Start Your Project +================== + +:link_to_translation:`zh_CN:[中文]` To get started with the Espressif-IDE, you can create a new project or import an existing project. -1. :ref:`Create a New Project ` -2. :ref:`Create a New Project Using ESP-IDF Templates ` -3. :ref:`Import an Existing Project ` +- :ref:`Create a New Project ` +- :ref:`Create a New Project Using ESP-IDF Templates ` +- :ref:`Import an Existing Project ` .. _newproject: Create a New Project ---------------------- +-------------------- + To create a new Project in the Espressif-IDE, follow the steps below: -#. Go to ``File`` > ``New`` > ``Espressif IDF Project``. -#. Provide the ``Project name`` -#. Click ``Finish``. +#. Go to ``File`` > ``New`` > ``Espressif IDF Project``. + + .. image:: ../../media/newproject_menu.png + :alt: New Project Menu + +#. Provide the ``Project name``. +#. Click ``Finish``. .. Note:: + The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects. -.. image:: ../../media/newproject_menu.png .. _newprojecttemplate: Create a New Project Using ESP-IDF Templates ---------------------------------------------- -Espressif-IDE also offers the ability to create a project using the ESP-IDF templates, which can be accessed by following the steps below: +-------------------------------------------- + +Espressif‑IDE also allows you to create a project from ESP‑IDF templates, which can be accessed by following the steps below: #. Go to ``File`` > ``New`` > ``Espressif IDF Project``. #. Choose a target board from the ``Select Project Target`` dropdown. -#. Click on ``Create a project using one of the templates`` from the Templates section. +#. Click on ``Create a project using one of the templates`` from the ``Template Selection`` section. #. Select the template you want to use and that automatically fills the project name based on the template selected. #. Click ``Finish``. - .. image:: ../../media/3_new_project_default.png - +.. image:: ../../media/3_new_project_default.png .. note:: - You may see numerous unresolved headers and symbols errors in the editor, and these will only be resolved after the build process. + + You may see numerous unresolved header and symbol errors in the editor. These will be resolved only after the build process. + .. _importproject: Import an Existing Project ---------------------------- +-------------------------- + To import an existing project into the Espressif-IDE, please make sure that is a CMake project. Follow the steps below: -#. Right-click in the ``Project Explorer``. +#. Right-click the ``Project Explorer``. #. Select ``Import..`` Menu. #. Select ``Existing IDF Project`` from ``Espressif`` import wizard menu list. #. Click ``Next``. @@ -57,6 +67,3 @@ To import an existing project into the Espressif-IDE, please make sure that is a #. Click ``Finish`` to import the selected project into Eclipse workspace as a CMake project. .. image:: ../../media/5_import_project.png - - - diff --git a/docs/en/troubleshooting.rst b/docs/en/troubleshooting.rst index 1bd9027c9..fa297e283 100644 --- a/docs/en/troubleshooting.rst +++ b/docs/en/troubleshooting.rst @@ -3,6 +3,8 @@ Troubleshooting =============== +:link_to_translation:`zh_CN:[中文]` + - :ref:`suggestions_for_build_errors` - :ref:`error_log` - :ref:`console_view_log` @@ -11,54 +13,58 @@ Troubleshooting .. _suggestions_for_build_errors: -Suggestions for Build Errors using Hints Viewer ------------------------------------------------- -If you encounter a problem during a build, there may be a hint for this error in the ESP-IDF hint database, located at ``tools/idf_py_actions/hints.yml`` in ESP-IDF. The ESP-IDF Eclipse plugin provides a hint viewer where you can type an error message to find a hint for it. +Suggestions for Build Errors Using Hints View +--------------------------------------------- + +If you encounter a problem during a build, there may be a hint for this error in the ESP-IDF hint database, located at ``tools/idf_py_actions/hints.yml`` in ESP-IDF. The ESP-IDF Eclipse plugin provides a Hints View where you can type an error message to find a hint for it. **Prerequisites:** The ``hints.yml`` file is available from ESP-IDF v5.0 and higher. If you are using an older version, you can manually download the ``hints.yml`` file from `here `_ and save it to ``esp-idf/tools/idf_py_actions/``. To download the file, right-click the ``Raw`` button and select ``Save as...``. -To open the hints viewer: -1. Navigate to ``Windows`` -> ``Show View`` -> ``Other...`` -> ``Espressif`` -> ``Hints``. +To open the Hints View, go to ``Windows`` > ``Show View`` > ``Other...`` > ``Espressif`` > ``Hints``. .. image:: https://user-images.githubusercontent.com/24419842/189666994-78cc8b24-b934-426f-9df5-79af28c50c55.png - :alt: Hints Viewer + :alt: Hints View Now you can type or paste an error from the build log, such as: + ``ccache error: Failed to create temporary file for esp-idf/libsodium/CMakeFiles/..../....: No such file or directory`` .. image:: https://user-images.githubusercontent.com/24419842/189672552-994624f3-c0c5-48e6-aa2c-61e4ed8915e5.png - :alt: Example Error in Hints Viewer + :alt: Example Error in Hints View -Double-clicking on the row will display the hint message if it doesn't fully fit on your screen. +Double-clicking the row will display the hint message if it doesn't fully fit on your screen. .. image:: https://user-images.githubusercontent.com/24419842/189673174-8ce40cda-6933-4dc4-a555-5d2ca617256e.png - :alt: Hint Message + :alt: Hint Message .. _error_log: Error Log --------- -The Error Log view captures warnings and errors logged by plug-ins. The log file is stored in the ``.log`` file within the ``.metadata`` subdirectory of the workspace. -To open the Error Log view: -- Go to ``Window`` > ``Show View`` > ``Error Log``. +The Error Log View captures warnings and errors logged by plug-ins. The log file is stored in the ``.log`` file within the ``.metadata`` subdirectory of the workspace. + +To open the Error Log View, go to ``Window`` > ``Show View`` > ``Error Log``. To export the current log view content: -1. Press the ``Export Log`` toolbar button or select ``Export Log...`` from the context menu. -2. Enter a file name. -It's recommended to include an error log when reporting an issue. +1. Press the ``Export Log`` toolbar button or select ``Export Log...`` from the context menu. + + .. image:: ../../media/export_log.png + :alt: Export Log -.. image:: ../../media/export_log.png - :alt: Export Log +2. Enter a file name. + +It's recommended to include an error log when reporting an issue. .. _console_view_log: Console View Log ---------------- -The Console View shows warnings and errors related to the current running process or build. To access the Console View: -- From the menu bar, select ``Window`` > ``Show View`` > ``Console``. +The Console View shows warnings and errors related to the current running process or build. + +To access the Console View, go to ``Window`` > ``Show View`` > ``Console``. .. image:: ../../media/CDT_Build_Console.png :alt: Console View @@ -67,18 +73,19 @@ The Console View shows warnings and errors related to the current running proces CDT Global Build Log -------------------- -To enable global build logging: -- Go to ``Preferences`` > ``C/C++`` > ``Build`` > ``Logging``. + +To enable global build logging, go to ``Preferences`` > ``C/C++`` > ``Build`` > ``Logging``. .. _espressif_idf_tools_console: Espressif IDF Tools Console ---------------------------- -The Espressif IDF Tools Console is part of the Console view and opens during the installation of IDF tools from Eclipse. + +The Espressif IDF Tools Console is part of the Console View and opens during the installation of IDF tools from Eclipse. If you encounter any issues during installation of IDF tools via ``Espressif`` > ``ESP-IDF Tools Manager`` > ``Install tools``, check the Espressif IDF Tools Console for errors. -If this console is not active, switch to it by clicking on the ``Display Selected Console`` icon in the console view. +If this console is not active, switch to it by clicking the ``Display Selected Console`` icon in the Console View. .. image:: ../../media/IDF_tools_console.png :alt: Espressif IDF Tools Console diff --git a/docs/en/windowsofflineinstaller.rst b/docs/en/windowsofflineinstaller.rst deleted file mode 100644 index bcb9bc7dc..000000000 --- a/docs/en/windowsofflineinstaller.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _windowsofflineinstaller: - -Installing Espressif-IDE by Windows Offline Installer -====================================================== - -`Espressif-IDE with ESP-IDF Windows Offline Installer` is an offline installer that includes all the required components for ESP-IDF application development. - -The installer deploys the following components: - -- Embedded Python -- Cross-compilers -- OpenOCD -- CMake and Ninja build tools -- ESP-IDF -- Espressif-IDE -- Amazon Corretto OpenJDK - -As Installer bundles, all the required components and tools including stable esp-idf so people behind corporate firewalls can use the whole solution out-of-box. This also configures all the required build environment variables and tool paths as you launch the IDE. All you could do is to get started with your project directly without manually configuring anything. This will give you a big boost to your productivity! - - -Download --------- - -You can download the latest version of the installer from `this `_ and run the installer. You can find installer name with ``Espressif-IDE-3.1.1 with ESP-IDF v5.3.1`` or similar name based on the version of the IDE and the version of the ESP-IDF. - -Choose the Installer as shown below. - -.. image:: ../../media/windows-installation/ide_windows_installer_0.png - -Installation ------------- - -The installer is an executable file with .exe extension. You can run the installer by double-clicking on it. - -The installer will guide you through the installation process. Please find the step-by-step guide below. - -Step 1: Choose Language -~~~~~~~~~~~~~~~~~~~~~~~~ - -Select language for the installer and click Ok. - -.. image:: ../../media/windows-installation/ide_windows_installer_1.png - :alt: drawing - -Step 2: Accept the product license agreement -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Read through the product license agreement, and then select `I accept the agreement`. You must accept the product license in order to continue with the installation. Continue by clicking Next. - -.. image:: ../../media/windows-installation/ide_windows_installer_2.png - :alt: drawing - -Step 3: Pre-installation checks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: ../../media/windows-installation/ide_windows_installer_3.png - :alt: drawing - -Step 4: Choose the installation directory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: ../../media/windows-installation/ide_windows_installer_4.png - :alt: drawing - -Step 5: Select Components to Install -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -By default all the components are selected. You can deselect any component if you don't want to install it. - -.. image:: ../../media/windows-installation/ide_windows_installer_5.png - :alt: drawing - -Step 6: Review the installation summary -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A review summary is presented before the Espressif-IDE and others are installed. - -.. image:: ../../media/windows-installation/ide_windows_installer_6.png - :alt: drawing -.. image:: ../../media/windows-installation/ide_windows_installer_7.png - :alt: drawing - -Step 6: Finalize the installation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: ../../media/windows-installation/ide_windows_installer_8.png - :alt: drawing -.. image:: ../../media/windows-installation/ide_windows_installer_9.png - :alt: drawing - -Step 7: Launch Espressif-IDE -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Launch Espressif-IDE by double-clicking on the icon. - -.. image:: ../../media/windows-installation/ide_windows_installer_10.png - :alt: drawing - -Step 8: Choose Espressif-IDE Workspace -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -It's advised to select a workspace directory outside the Espressif-IDE Installer folder. - -.. image:: ../../media/windows-installation/ide_windows_installer_11.png - :alt: drawing - -Step 9: Espressif-IDE Workbench -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As soon as you launch the Espressif-IDE, it will automatically configure the required environment variables and launch the Welcome page. You can close the Welcome page. You don't need to run any additional install tools from the IDE. - -.. image:: ../../media/windows-installation/ide_windows_installer_12.png - :alt: drawing - -You can verify the CDT Build environment variables from the Eclipse Preferences. - -.. image:: ../../media/windows-installation/ide_windows_installer_13.png - :alt: drawing - -Step 10: Build Your First Project -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As IDE already configured with all the required environment variables, you can start with your project. - -You can find more details for creating a project in the :ref:`New Project ` section of the documentation. - -.. image:: ../../media/windows-installation/ide_windows_installer_14.png - :alt: drawing - :width: 400 \ No newline at end of file diff --git a/docs/zh_CN/additionalfeatures.rst b/docs/zh_CN/additionalfeatures.rst new file mode 100644 index 000000000..973d09afb --- /dev/null +++ b/docs/zh_CN/additionalfeatures.rst @@ -0,0 +1,24 @@ +其他 IDE 功能 +============= + +:link_to_translation:`en:[English]` + +.. toctree:: + :maxdepth: 1 + + LSP C/C++ 编辑器 + CMake 编辑器 + ESP-IDF 应用程序大小分析 + ESP-IDF 终端 + 安装 ESP-IDF 组件 + 堆跟踪 + ESP-IDF OpenOCD 调试 + GDB stub 调试 + 核心转储调试 + 应用级跟踪 + 分区表编辑器 + NVS 分区编辑器 + 将二进制文件写入 flash + DFU 烧录 + Wokwi 仿真器 + 切换语言 diff --git a/docs/zh_CN/additionalfeatures/appleveltracing.rst b/docs/zh_CN/additionalfeatures/appleveltracing.rst new file mode 100644 index 000000000..476dd0073 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/appleveltracing.rst @@ -0,0 +1,50 @@ +应用级跟踪 +========== + +:link_to_translation:`en:[English]` + +ESP-IDF 提供了一项用于程序行为分析的实用功能,称为 `应用级跟踪库 `_。IDF-Eclipse 插件提供了 UI 界面,可用于启动和停止跟踪命令并处理接收的数据。如需熟悉该库,你可以参考 `app_trace_to_host `_ 示例项目,或者 `app_trace_basic `_ 示例项目(要求使用 ESP-IDF 5.1 及以上)。这些示例项目可以直接通过插件创建。 + +.. image:: ../../../media/AppLvlTracing_1.png + :alt: 应用级跟踪项目创建 + +在使用应用级跟踪之前,需要为项目创建调试配置,并选择所用的开发板,以便成功启动 OpenOCD 服务器。 + +.. image:: ../../../media/AppLvlTracing_3.png + :alt: 调试配置设置 + +创建好调试配置后,在项目管理器中右键单击项目并选择 ``ESP-IDF: Application Level Tracing``。 + +.. image:: ../../../media/AppLvlTracing_2.png + :alt: 上下文菜单中的应用级跟踪选项 + +打开应用级跟踪对话框可能需要一些时间,因为需要先启动 OpenOCD 服务器。对话框顶部有一些预配置的字段,这些字段用于启动跟踪命令,并可根据需要进行调整。 + +**启动命令:** + +- 语法:``start [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]`` +- 参数: + + - ``outfile``:保存来自两个 CPU 的数据的文件路径,格式为 ``file://path/to/file``。 + - ``poll_period``:数据轮询周期(单位:毫秒)。如果大于 0,则以非阻塞模式运行。默认值:1。 + - ``trace_size``:可收集的最大数据量(单位:字节)。在接收到指定的数据量后停止跟踪。默认值:-1(不设限)。 + - ``stop_tmo``:空闲超时时间(单位:秒)。在指定时间段内无数据则停止跟踪。默认值:-1(不设限)。 + - ``wait4halt``:为 0 时立即开始跟踪,否则等待目标暂停后再开始。默认值:0。 + - ``skip_size``:开始时要跳过的字节数。默认值:0。 + +更多信息请参阅 `此处 `_。 + +.. image:: ../../../media/AppLvlTracing_4.png + :alt: 应用级跟踪对话框 + +接下来的两个字段 ``Trace Processing Script`` 和 ``Start Parsing Command`` 用于解析输出文件。 + +- ``Trace Processing Script``:解析脚本的路径,默认使用 ESP-IDF 提供的 ``logtrace_proc.py``。 +- ``Start Parsing Command``:用于在需要时检查并编辑解析命令。默认配置为:``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py/path/to/trace/file/path/to/program/elf/file``。 + +在生成转储文件之前,``Start parse`` 按钮处于禁用状态。要生成转储文件,请单击对话框底部的 ``Start`` 按钮。开始跟踪后,该按钮会变为 ``Stop``,点击即可停止跟踪。 + +输出文件生成后,可单击 ``Start parse``,在 Eclipse 控制台中查看解析脚本的输出。 + +.. image:: ../../../media/AppLvlTracing_5.png + :alt: Eclipse 控制台中的解析脚本输出 diff --git a/docs/zh_CN/additionalfeatures/application-size-analysis.rst b/docs/zh_CN/additionalfeatures/application-size-analysis.rst new file mode 100644 index 000000000..9eddbb34a --- /dev/null +++ b/docs/zh_CN/additionalfeatures/application-size-analysis.rst @@ -0,0 +1,27 @@ +ESP-IDF 应用程序大小分析 +======================== + +:link_to_translation:`en:[English]` + +应用程序大小分析编辑器可用于分析应用的静态内存占用情况。该编辑器包含两个部分: + +- ``Overview``:总结应用程序的内存使用情况。 +- ``Details``:显示组件级和符号级的详细内存信息,并提供搜索和排序功能。 + +可参照下列步骤启动应用程序大小分析编辑器: + +#. 右键单击你的项目。 +#. 选择 ``ESP-IDF: Application Size Analysis`` 菜单选项以启动编辑器。 + +.. figure:: ../../../media/sizeanalysis_overview.png + :align: center + :alt: 应用大小分析 — 概览 + + 应用程序大小分析 – 概览 + + +.. figure:: ../../../media/sizeanalysis_details.png + :align: center + :alt: 应用大小分析 — 详细信息 + + 应用程序大小分析 – 详细信息 diff --git a/docs/zh_CN/additionalfeatures/clangd_cdt_support.rst b/docs/zh_CN/additionalfeatures/clangd_cdt_support.rst new file mode 100644 index 000000000..318ab6cc3 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/clangd_cdt_support.rst @@ -0,0 +1 @@ +.. include:: ../../en/additionalfeatures/clangd_cdt_support.rst diff --git a/docs/zh_CN/additionalfeatures/clangtoolchain.rst b/docs/zh_CN/additionalfeatures/clangtoolchain.rst new file mode 100644 index 000000000..69f4793e4 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/clangtoolchain.rst @@ -0,0 +1,18 @@ +配置 Clang 工具链 +================= + +:link_to_translation:`en:[English]` + +1. 创建新项目后,编辑项目配置。 + + .. image:: https://user-images.githubusercontent.com/24419842/194882285-9faadb5d-0fe2-4012-bb6e-bc23dedbdbd2.png + :alt: 项目配置 + +2. 前往 ``Build Settings`` 选项卡并选择 Clang 工具链。 + + .. image:: https://user-images.githubusercontent.com/24419842/194882462-3c0fd660-b223-4caf-964d-58224d91b518.png + :alt: 选择 Clang 工具链 + +.. note:: + + Clang 工具链目前处于实验阶段,使用时可能会因为与 ESP-IDF 不兼容而遇到构建问题。以下内容说明了如何解决当前 ESP-IDF master 分支 (ESP-IDF v5.1-dev-992-gaf28c1fa21-dirty) 上最常见的构建问题。若遇到 Clang 构建错误,请参考此 `变通方法指南 `_。 diff --git a/docs/zh_CN/additionalfeatures/cmakeeditor.rst b/docs/zh_CN/additionalfeatures/cmakeeditor.rst new file mode 100644 index 000000000..0be238048 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/cmakeeditor.rst @@ -0,0 +1,14 @@ +CMake 编辑器 +============ + +:link_to_translation:`zh_CN:[中文]` + +CMake 编辑器插件与 IDF 插件集成,可用于编辑 CMake 文件(例如 ``CMakeLists.txt``)。该插件提供语法高亮、CMake 命令自动补全和代码模板等功能。 + +.. image:: ../../../media/cmake_editor_ca.png + :alt: 带内容提示的 CMake 编辑器 + +CMake 编辑器的首选项可通过 ``Eclipse`` > ``Preferences`` > ``CMakeEd`` 进行设置。 + +.. image:: ../../../media/cmake_editor_preferences.png + :alt: CMake 编辑器首选项 diff --git a/docs/zh_CN/additionalfeatures/configureenvvariables.rst b/docs/zh_CN/additionalfeatures/configureenvvariables.rst new file mode 100644 index 000000000..9ad681a81 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/configureenvvariables.rst @@ -0,0 +1,9 @@ +配置环境变量 +============ + +:link_to_translation:`en:[English]` + +通过 `EIM `_ 安装 ESP-IDF 后,在 ``Espressif`` > ``ESP-IDF Manager`` 中激活 ESP-IDF 时,IDE 会自动配置所有必需的环境变量。你可以在 ``Preferences`` 页面前往 ``C/C++`` > ``Build`` > ``Environment``,查看这些变量。 + +.. image:: ../../../media/2_environment_pref.png + :alt: 环境首选项 diff --git a/docs/zh_CN/additionalfeatures/configuretoolchain.rst b/docs/zh_CN/additionalfeatures/configuretoolchain.rst new file mode 100644 index 000000000..e788a3326 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/configuretoolchain.rst @@ -0,0 +1,71 @@ +在 IDE 中添加预览版或自定义 ESP-IDF 目标 +======================================== + +:link_to_translation:`zh_CN:[中文]` + +若想添加预览版或自定义的 ESP-IDF 目标(例如 ESP32-C5 或 IDE 中未默认列出的目标),请按以下步骤操作: + +步骤 1:配置工具链 +------------------ + +1. 前往 ``Preferences`` > ``C/C++`` > ``Core Build Toolchain``。 +2. 在 ``User Defined Toolchains`` 部分,点击 ``Add``。 +3. 选择 ``GCC``,并按如下配置: + + - **编译器**:目标所用工具链编译器的路径,例如 ``/Users/testuser/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc`` + - **操作系统**:例如 ``esp32c5``,用于 ESP32-C5 + - **CPU 架构**:例如 ``riscv32``,用于 ESP32-C5 + +4. 点击 ``Finish``。 + +.. figure:: ../../../media/toolchain/toolchain_1.png + :align: center + :alt: 核心构建工具链首选项(添加自定义目标) + + 核心构建工具链:添加自定义或预览版目标工具链(示例:ESP32-C5) + +步骤 2:配置 CMake 工具链 +------------------------- + +1. 前往 ``Preferences`` > ``C/C++`` > ``CMake``。 +2. 点击 ``Add``。 +3. 浏览并选择目标的 CMake 工具链文件(例如 ``toolchain-esp32c5.cmake``)。 +4. 选择步骤 1 中创建的相应工具链条目。 +5. 点击 ``Finish``。 + +.. figure:: ../../../media/toolchain/toolchain_2.png + :align: center + :alt: CMake 工具链首选项(添加自定义目标) + + CMake 工具链首选项:添加自定义或预览版目标工具链文件(示例:ESP32-C5) + +步骤 3:添加启动目标 +-------------------- + +1. 在 IDE 顶部工具栏的目标列表中,点击 ``New Launch Target``。 +2. 选择 ``ESP Target``。 +3. 填写如下信息: + + - ``Name``:例如, esp32c5 + - ``IDF Target``:例如, esp32c5 + +4. 点击 ``Finish``。 + +.. figure:: ../../../media/toolchain/toolchain_3.png + :align: center + :alt: 新建乐鑫目标对话框(自定义目标示例) + + 新建乐鑫目标对话框:为自定义或预览版目标创建启动目标(示例:ESP32-C5) + +步骤 4:构建项目 +---------------- + +- 新建或打开项目。 +- 在目标列表中选择自定义或预览版目标。 +- 构建项目。 + +.. figure:: ../../../media/toolchain/toolchain_4.png + :align: center + :alt: 自定义目标项目的构建输出 + + 构建输出:成功为自定义或预览版目标构建项目(示例:ESP32-C5) diff --git a/docs/zh_CN/additionalfeatures/coredumpdebugging.rst b/docs/zh_CN/additionalfeatures/coredumpdebugging.rst new file mode 100644 index 000000000..501debb02 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/coredumpdebugging.rst @@ -0,0 +1,21 @@ +.. _coredumpdebugging: + +核心转储调试 +============ + +:link_to_translation:`en:[English]` + +在完成相关配置的前提下,IDF-Eclipse 插件可以在芯片发生崩溃时调试核心转储。目前,仅支持通过 UART 捕获和调试核心转储。 + +可参照以下步骤为项目启用核心转储调试: + +1. 先在 ``sdkconfig`` 中启用该功能。在项目根目录中双击 ``sdkconfig``,打开配置编辑器。 +2. 在左侧设置中点击 ``Core Dump``,并将 ``Data Destination`` 设置为 ``UART``。 + +.. image:: ../../../media/CoreDumpDebugging/sdkconfig_editor.png + +上述步骤将启用核心转储调试。为项目连接串口监视器时,如发生崩溃,则将加载转储并在 Eclipse 中打开调试透视图,以便查看核心转储包含的所有信息。 + +你可以查看寄存器、栈回溯,甚至查看栈帧中的变量值。 + +若想退出调试会话,只需点击 ``stop`` 按钮。 diff --git a/docs/zh_CN/additionalfeatures/dfu.rst b/docs/zh_CN/additionalfeatures/dfu.rst new file mode 100644 index 000000000..1d85ea065 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/dfu.rst @@ -0,0 +1 @@ +.. include:: ../../en/additionalfeatures/dfu.rst diff --git a/docs/zh_CN/additionalfeatures/esp-terminal.rst b/docs/zh_CN/additionalfeatures/esp-terminal.rst new file mode 100644 index 000000000..c38c41214 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/esp-terminal.rst @@ -0,0 +1,16 @@ +ESP-IDF 终端 +============ + +:link_to_translation:`en:[English]` + +该功能会启动一个本地终端,其中配置了在 ``Preferences`` > ``C/C++`` > ``Build`` > ``Environment`` 下的所有环境变量。默认工作目录为当前选中的项目;如果没有选中项目,则为 ``IDF_PATH``。 + +该终端的 ``PATH`` 还配置了 ``esptool``、``espcoredump``、``partition_table`` 和 ``app_update`` 组件的路径,便于在 ESP-IDF 终端中直接访问这些组件。 + +可参照下列步骤启动 ESP-IDF 终端: + +1. 在工具栏中点击 ``Open a Terminal`` 图标。 +2. 在终端下拉菜单中选择 ``ESP-IDF Terminal``,然后点击 ``OK`` 启动终端。 + +.. image:: ../../../media/idf_terminal.png + :alt: ESP-IDF 终端 diff --git a/docs/zh_CN/additionalfeatures/gdbstubdebugging.rst b/docs/zh_CN/additionalfeatures/gdbstubdebugging.rst new file mode 100644 index 000000000..cacb0e1f5 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/gdbstubdebugging.rst @@ -0,0 +1,50 @@ +.. _gdbstubdebugging: + +GDBStub 调试 +============ + +:link_to_translation:`en:[English]` + +你可以在 Eclipse 插件中使用 GDBStub 调试功能,在芯片进入 panic 模式时诊断和调试相关问题。 + +可参照下列步骤为项目启用 GDBStub 调试: + +1. 在项目根目录中双击 ``sdkconfig``,打开配置编辑器。 + + .. image:: ../../../media/GDBStubDebugging/sdkconfig_editor.png + +2. 展开 ``Component Config`` 部分并选择 ``ESP System Settings``。在右侧设置中,将 ``Panic handler behaviour`` 设为列表中的 ``GDBStub on Panic`` 选项。 + + .. image:: ../../../media/GDBStubDebugging/sdkconfig_editor_panic_behavior.png + +当连接串口监视器且此示例发生 panic 时,将自动进入 GDBStub 调试器。 + +参照下列步骤在项目中使用 GDBStub 调试: + +1. 创建 ``hello_world`` 模板项目,并在 ``main.c`` 文件中加入以下内容: + + .. code-block:: c + + // 这是一个全局变量 + COREDUMP_DRAM_ATTR uint8_t global_var; + +2. 现在在 ``esp_restart()`` 函数的上方加入下面两行代码: + + .. code-block:: c + + global_var = 25; + assert(0); + +最终生成的文件应如下所示: + +.. image:: ../../../media/GDBStubDebugging/code_example.png + +构建并烧录项目,然后启动串口监视器。在第 45 行,会触发一个失败的断言,导致芯片进入 panic 模式。当程序执行到该行时,IDE 会提示你切换到调试模式,并暂停芯片执行。 + +此时芯片处于 panic 模式,无法继续执行程序。必须通过 IDF 命令停止并重启芯片,或者直接重启串口监视器。 + +.. image:: ../../../media/GDBStubDebugging/debug_panic_mode.png + +你可以查看寄存器、栈回溯以及栈帧中的变量值。 + +若要退出调试会话,只需点击 ``stop`` 按钮。 diff --git a/docs/zh_CN/additionalfeatures/heaptracing.rst b/docs/zh_CN/additionalfeatures/heaptracing.rst new file mode 100644 index 000000000..4ecfb8985 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/heaptracing.rst @@ -0,0 +1,95 @@ +.. _heap_tracing: + +堆跟踪 +====== + +:link_to_translation:`en:[English]` + +你可以使用堆跟踪生成并分析 ``svdat`` 转储文件,持续监控内存使用情况。IDF Eclipse 插件支持通过设置特定断点来生成堆跟踪文件。有关 SDK 级配置和跟踪功能的更多信息,请参阅官方 `ESP-IDF 文档 `_。 + +生成转储文件 +------------ + +1. **打开 sysview_heap_log.c 文件** + + 在资源管理器中找到并打开 **系统** 模板项目中的 ``sysview_heap_log.c`` 文件。 + + .. image:: ../../../media/HeapTracing/sysview_heap_log_file.PNG + :alt: sysview_heap_log.c 文件 + +2. **添加断点并配置属性** + + 在所需的代码行添加一个断点,然后在编辑器中右键单击断点图标,选择 ``Breakpoint Properties``。 + + .. image:: ../../../media/HeapTracing/breakpoint_properties_popup.png + :alt: 断点属性 + +3. **定义堆跟踪操作** + + 在 ``Breakpoint Properties`` 窗口中,前往 ``Actions``,单击 ``New``,并在 ``Action Type`` 下拉列表中选择 ``Heap Tracing``。 + + 对于初始断点,在 ``Action`` 一栏选择 ``Start Heap Trace``,并指定转储文件的保存位置(建议存放在项目目录)。为该操作设置一个有意义的名称,然后单击 ``OK``。 + + .. image:: ../../../media/HeapTracing/heap_tracing_action.png + :alt: 堆跟踪操作 + +4. **将该操作附加至断点** + + 创建操作后,单击 ``Attach`` 将其链接至断点。绑定成功后,该操作会显示在 ``Actions for this breakpoint`` 一栏。 + + .. image:: ../../../media/HeapTracing/breakpoint_properties_actions_start_attached.png + :alt: 附加操作 + +5. **应用并创建另一个断点** + + 现在你已有一个会开始跟踪并生成转储文件的断点。要停止跟踪,请再创建一个断点(例如在代码的第 102 行),设置其属性,并在操作设置中选择 ``Stop Heap Trace`` 选项。按下图所示,将此操作附加至断点。 + + .. image:: ../../../media/HeapTracing/breakpoint_properties_actions_stop_attached.png + :alt: 停止堆跟踪操作 + +6. **启动调试配置** + + 在 IDE 中启动开发板的调试配置。当程序运行至断点时,IDE 会提示你切换到调试器视图。在每个断点处继续执行程序,以开始或停止跟踪。然后在资源管理器中刷新项目,即可在指定位置查看生成的转储文件。 + +分析转储文件 +------------ + +IDF Eclipse 插件可用于分析生成的 ``svdat`` 转储文件。右键单击该转储文件,并在上下文菜单中选择 ``ESP-IDF: Heap Dump Analysis``。 + +.. note:: + + 确保项目使用合适的符号文件进行构建,以便启用分析。 + +.. image:: ../../../media/HeapTracing/analysis_context_menu.png + :alt: 堆转储分析的上下文菜单 + +``Overview`` 标签页 +------------------- + +``Overview`` 标签页以曲线图形式显示内存消耗的变化情况。默认情况下,图表会显示所有上下文的内存信息,你也可以选择只显示与特定堆事件相关的上下文。 + +.. image:: ../../../media/HeapTracing/overview_tab_tracing.png + :alt: 内存消耗图 + +例如,选择多个上下文时,曲线图会分别显示每个上下文的内存使用情况。 + +.. image:: ../../../media/HeapTracing/overview_tab_tracing_contexts.png + :alt: 图表中已选的上下文 + +``Details`` 标签页 +------------------ + +``Details`` 标签页提供更详细的信息,显示堆跟踪中的每个事件。浅橙色高亮的行表示潜在的内存泄漏,因为跟踪可能在释放事件被检测到之前就已结束。绿色高亮的行表示已释放的堆事件。 + +.. image:: ../../../media/HeapTracing/details_tab_tracing.png + :alt: 详细信息标签页 + +要筛选可能的内存泄漏条目,请勾选 ``View Possible Memory Leaks`` 复选框。右键单击任意条目可查看其调用者,这会打开 ``Callers View``,显示该堆事件的调用栈。 + +.. image:: ../../../media/HeapTracing/show_callers_context_menu.png + :alt: 显示调用者 + +在 ``Callers View`` 中单击某个条目将跳转到源文件中的相应代码行。 + +.. image:: ../../../media/HeapTracing/callers_view.png + :alt: 调用者视图 diff --git a/docs/zh_CN/additionalfeatures/install-esp-components.rst b/docs/zh_CN/additionalfeatures/install-esp-components.rst new file mode 100644 index 000000000..2ed401c2b --- /dev/null +++ b/docs/zh_CN/additionalfeatures/install-esp-components.rst @@ -0,0 +1,15 @@ +安装 ESP-IDF 组件 +================= + +:link_to_translation:`en:[English]` + +可以从 `ESP-IDF 组件注册表 `_ 提供的可用组件中,选择 ESP-IDF 组件安装至你的项目。请按照以下步骤操作: + +1. 在 ``Project Explorer`` 中,右键点击要添加组件的项目,然后选择 ``ESP-IDF: Install ESP-IDF Components``。 +2. 界面中出现一个新窗口,显示所有可安装的组件。 +3. 在该窗口中,可点击 ``Install`` 按钮将所选组件添加到项目。要查看组件的 README 文件,点击 ``More Info``,浏览器会打开该 README。 + +.. image:: ../../../media/ESP-IDF_Components/components_window.png + :alt: ESP-IDF 组件窗口 + +已添加的组件也会在此显示,但 ``Install`` 按钮的文字会变为 ``Already Added`` 并被禁用。 diff --git a/docs/zh_CN/additionalfeatures/lspeditor.rst b/docs/zh_CN/additionalfeatures/lspeditor.rst new file mode 100644 index 000000000..11d71df87 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/lspeditor.rst @@ -0,0 +1,89 @@ +LSP C/C++ 编辑器 +================ + +:link_to_translation:`en:[English]` + +从 Espressif IDE 3.0.0 开始,LSP 编辑器成为默认的代码编辑器,其行为与之前的默认编辑器存在显著差异,主要区别如下所示。 + +格式化 +------ + +如需自定义格式化,请打开项目中的 ``.clang-format`` 文件。默认情况下,文件包含以下内容: + +.. code-block:: none + + BasedOnStyle: LLVM + UseTab: Always + IndentWidth: 4 + TabWidth: 4 + PackConstructorInitializers: NextLineOnly + BreakConstructorInitializers: AfterColon + IndentAccessModifiers: false + AccessModifierOffset: -4 + +也可以使用 ``DisableFormat: true`` 选项对特定文件夹禁用格式化。例如,如果希望在如下结构的项目中为 ``managed_components`` 文件夹禁用格式化: + +.. code-block:: none + + project + ├── managed_components + │ └── .clang-format + ├── main + └── .clang-format + +在 ``managed_components`` 文件夹中的 ``.clang-format`` 文件中添加 ``DisableFormat: true`` 选项。该选项会指示 ClangFormat 完全忽略此 ``.clang-format`` 文件及其在 ``managed_components`` 目录下定义的所有格式化规则。 + +有关可用风格选项的更多信息,请参阅 `可配置的格式化风格选项 `_。 + +搜索 +---- + +在基于 LSP 的 C/C++ 编辑器中,右键菜单里的 ``Search Text`` 选项目前不可用。不过,你可以暂时通过工具栏菜单中的 ``Search`` > ``Text`` > ``Workspace`` 来实现相同的功能。 + +内联提示 +-------- + +LSP 编辑器默认启用内联提示。如果你不想使用此功能,可通过编辑 ``.clangd`` 文件将其禁用: + +.. code-block:: none + + CompileFlags: + CompilationDatabase: build + Remove: + - -m* + - -f* + + InlayHints: + Enabled: No + +搜索 ESP-IDF 组件 +----------------- + +如需浏览 ESP-IDF 组件,请执行以下步骤: + +1. 创建一个新项目。 +2. 将 ESP-IDF 组件文件夹作为虚拟文件夹添加到新建项目中。 +3. 使用快捷键 **Ctrl + Shift + T** 或 **Ctrl + Shift + R**。 +4. 现在可以浏览 ESP-IDF 组件文件。 +5. 若要搜索特定函数或关键字,请使用工具栏中的 ``Search`` 菜单。 + +创建虚拟文件夹 +~~~~~~~~~~~~~~ + +1. 前往 ``New`` > ``Folder``。 +2. 点击 ``Advanced``。 +3. 选择 ``Link to alternate Location (Linked Folder)``。 +4. 点击 ``Browse`` 并选择 ``ESP-IDF components`` 文件夹。 + +建议始终创建一个新项目,而不是修改现有项目,从而避免索引器在 ``components`` 文件夹中生成不必要的 Git 文件和错误标记。由于两个项目都位于同一个工作区中,你仍然可以在整个工作区范围内进行搜索。 + +如果在 LSP 编辑器中使用 Clangd 配置时遇到任何问题,请参阅 :ref:`Clangd 配置 ` 指南。 + +参考文档 +-------- + +.. toctree:: + :maxdepth: 1 + + Clangd CDT 支持与配置 + 配置 Clang 工具链 diff --git a/docs/zh_CN/additionalfeatures/nvspartitioneditor.rst b/docs/zh_CN/additionalfeatures/nvspartitioneditor.rst new file mode 100644 index 000000000..20ebfe492 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/nvspartitioneditor.rst @@ -0,0 +1,41 @@ +NVS 表格编辑器 +============== + +:link_to_translation:`en:[English]` + +NVS 表格编辑器可根据 CSV 文件中的键值对创建二进制文件。生成的二进制文件与 ESP-IDF `非易失性存储库 `_ 中定义的 NVS 架构兼容。CSV 格式应如下所示: + +.. code-block:: text + + key,type,encoding,value <-- 列标题,必须是第一行 + namespace_name,namespace,, <-- 第一条目类型必须为 "namespace" + key1,data,u8,1 + key2,file,string,/path/to/file + +.. note:: + + 此功能基于 ESP-IDF `NVS 分区生成程序 `_。 + +操作步骤 +-------- + +1. 在资源管理器中右键单击某个项目。 +2. 点击 ``ESP-IDF: NVS Table Editor`` 菜单选项。 + + .. image:: https://user-images.githubusercontent.com/24419842/216114697-9f231211-f5dd-431b-9432-93ecc656cfec.png + :alt: NVS 表格编辑器菜单选项 + +3. 按需修改 CSV 数据。 +4. 点击 ``Save`` 按钮保存更改。若配置正确,则将在对话框顶部看到一条信息提示: + + .. image:: https://user-images.githubusercontent.com/24419842/216115906-9bb4fe55-293b-4c6b-8d22-0aa3520581ab.png + :alt: 在 NVS 表格编辑器中的保存确认 + +5. 生成分区二进制文件。可选择 ``Encrypt`` 以加密该二进制文件。如需使用自定义密钥,可禁用 ``Generate Key`` 选项。文件生成后,对话框顶部会显示生成结果的信息提示。如果提示内容过长无法完全显示,可将鼠标悬停其上以查看全文: + + .. image:: https://user-images.githubusercontent.com/24419842/216117261-9bee798a-3a9e-4be5-9466-fc9d3847834b.png + :alt: 在 NVS 表格编辑器中的二进制文件生成结果 + + .. note:: + + 如果出现错误,将会高亮显示。将鼠标悬停在错误图标上可以查看错误详情,同时在对话框顶部也会显示错误信息。 diff --git a/docs/zh_CN/additionalfeatures/partitiontableeditor.rst b/docs/zh_CN/additionalfeatures/partitiontableeditor.rst new file mode 100644 index 000000000..4cec4d5b1 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/partitiontableeditor.rst @@ -0,0 +1,31 @@ +分区表编辑器 +============ + +:link_to_translation:`zh_CN:[中文]` + +可以使用分区表编辑器命令更快捷地编辑 `分区表 `_。你可以在编辑器中查看受支持的类型和子类型,并检查输入数据的正确性。 + +步骤 +---- + +1. 进入 ``Project Explorer``,打开任意希望创建自定义分区表的 IDF 工程。 +2. 在 ``Project Explorer`` 中,右键单击该项目并选择 ``ESP-IDF: Partition Table Editor``: + + .. image:: https://user-images.githubusercontent.com/24419842/216105408-ca2e73ce-5df3-4bdd-ac61-b7265deb9b44.png + :alt: 分区表编辑器菜单选项 + + 为所选项目打开分区表编辑器时,能看到标准可编辑的内容。若存在错误,则会高亮显示。你可以将鼠标悬停在错误之上以查看相关提示: + + .. image:: https://user-images.githubusercontent.com/24419842/216106804-703b2eb4-b141-48de-8559f072219f.png + :alt: 分区表编辑器中的错误提示 + +3. 单击 ``Save`` 或 ``Save and Quit`` 以保存更改。 + + +使用自定义分区表 +---------------- + +进入 ``SDK Configuration``,并按下图所示设置 ``Custom partition table CSV``: + +.. image:: https://user-images.githubusercontent.com/24419842/216104107-2844068b-8412-468b-931f-b4778af4417c.png + :alt: 在 sdkconfig 中设置自定义分区表 diff --git a/docs/zh_CN/additionalfeatures/switchlanguage.rst b/docs/zh_CN/additionalfeatures/switchlanguage.rst new file mode 100644 index 000000000..af4a72054 --- /dev/null +++ b/docs/zh_CN/additionalfeatures/switchlanguage.rst @@ -0,0 +1,14 @@ +在 IDE 中切换语言 +================= + +:link_to_translation:`zh_CN:[中文]` + +乐鑫 IDE 支持英文和中文。可参照以下步骤在两种语言之间进行切换: + +1. 在菜单栏中点击 ``Espressif``。 +2. 从下拉菜单中选择 ``Change Language``。 +3. 在子菜单中选择需要的语言。 +4. IDE 将重新启动并切换至所选语言界面。 + +.. image:: ../../../media/change_language.png + :alt: 切换语言菜单 diff --git a/docs/zh_CN/additionalfeatures/wokwisimulator.rst b/docs/zh_CN/additionalfeatures/wokwisimulator.rst new file mode 100644 index 000000000..4216a061c --- /dev/null +++ b/docs/zh_CN/additionalfeatures/wokwisimulator.rst @@ -0,0 +1 @@ +.. include:: ../../en/additionalfeatures/wokwisimulator.rst diff --git a/docs/zh_CN/additionalfeatures/writebinarytoflash.rst b/docs/zh_CN/additionalfeatures/writebinarytoflash.rst new file mode 100644 index 000000000..9e2e9f61c --- /dev/null +++ b/docs/zh_CN/additionalfeatures/writebinarytoflash.rst @@ -0,0 +1,16 @@ +将二进制数据写入 flash +====================== + +:link_to_translation:`en:[English]` + +可以通过 ``ESP-IDF: Write Binary Data to Flash`` 命令将二进制数据写入乐鑫的 flash 芯片。要访问此命令,请在项目资源管理器中右键单击该项目: + +.. image:: https://github.com/espressif/idf-eclipse-plugin/assets/24419842/186c8498-d779-4771-af53-e5bf09e29502 + :alt: 将二进制数据写入 flash 的命令 + +点击此命令后,将打开 ``Write Binary Data to Flash`` 对话框,为二进制路径和偏移地址提供了可编辑的默认值。可以使用 ``ESP-IDF: Partition Table Editor`` 命令或手动打开 ``partitions.csv`` 文件查看分区表,确认正确的偏移地址。 + +.. image:: https://github.com/espressif/idf-eclipse-plugin/assets/24419842/46e24e89-a1ed-4169-8c92-1ba0b0089ea7 + :alt: 将二进制数据写入 flash 的对话框 + +点击 ``Flash`` 按钮将执行烧录命令,并在此对话框中显示结果。 diff --git a/docs/zh_CN/buildproject.rst b/docs/zh_CN/buildproject.rst new file mode 100644 index 000000000..2b6c6fc2c --- /dev/null +++ b/docs/zh_CN/buildproject.rst @@ -0,0 +1,46 @@ +构建项目 +======== + +:link_to_translation:`en:[English]` + +.. |build_icon| image:: ../../media/icons/build.png + :height: 16px + :align: middle + +创建项目并配置好乐鑫目标设备及串口后,可在工具栏中点击 |build_icon| 图标来构建项目。 + +如果你是初次使用 IDE,请参照下列步骤,完成项目的构建流程: + +1. 在 ``Project Explorer`` 中选择一个项目。 +2. 在第一个下拉菜单 **启动模式** 中选择 ``Run``。。 +3. 在第二个下拉菜单 **启动配置** 中选择你的应用程序(该程序会被自动检测)。 +4. 在第三个下拉菜单 **启动目标** 中选择目标芯片,如 ``esp32``。 +5. 点击 ``Build`` 按钮 |build_icon|,开始构建流程。 + +.. image:: ../../media/9_cmake_build.png + +自定义构建目录 +-------------- + +IDE 允许为项目配置自定义构建目录: + +1. 选择一个项目,在顶部工具栏中点击启动配置的 ``Edit`` 按钮,打开 ``Edit Configuration`` 窗口。 +2. 前往 ``Build Settings`` 选项卡。 +3. 在 ``Build folder location`` 部分填写自定义的构建目录。该自定义目录路径可以位于项目内,也可以位于文件系统中的任意位置。 +4. 点击 ``Ok`` 并构建项目。 + +.. note:: + + 此配置指定了项目生成的所有构建产物的存放位置。 + +.. image:: ../../media/custombuilddir.png + :alt: 自定义构建目录配置 + +参考文档 +-------- + +.. toctree:: + :maxdepth: 1 + + 配置 CDT 构建环境变量 + 添加预览或自定义 ESP-IDF 目标 diff --git a/docs/zh_CN/conf.py b/docs/zh_CN/conf.py new file mode 100644 index 000000000..933b8ef0e --- /dev/null +++ b/docs/zh_CN/conf.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# English Language RTD & Sphinx config file +# +# Uses ../conf_common.py for most non-language-specific settings. + +# Importing conf_common adds all the non-language-specific +# parts to this conf module + +try: + from conf_common import * # noqa: F403,F401 +except ImportError: + import os + import sys + sys.path.insert(0, os.path.abspath('../')) + from conf_common import * # noqa: F403,F401 + +# General information about the project. +project = u'Espressif-IDE' +copyright = u'2016 - 2024, 乐鑫信息科技(上海)股份有限公司' +pdf_title = u'Espressif-IDE 指南' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'zh_CN' diff --git a/docs/zh_CN/configureproject.rst b/docs/zh_CN/configureproject.rst new file mode 100644 index 000000000..3866e6b6c --- /dev/null +++ b/docs/zh_CN/configureproject.rst @@ -0,0 +1,20 @@ +配置项目 +======== + +:link_to_translation:`en:[English]` + +项目配置保存在项目根目录下一个名为 ``sdkconfig`` 的文件中。可以使用 SDK 配置编辑器修改该配置文件。 + +.. note:: + + ``sdkconfig`` 文件仅在构建之后才会生成。因此,建议在配置项目之前先构建一次项目。 + +可参照下列步骤,启动 SDK 配置编辑器: + +#. 找到 ``sdkconfig`` 文件。 +#. 双击该文件以启动 SDK 配置编辑器。 +#. 根据操作系统使用 ``Ctrl+S`` 或 ``Command+S`` 保存更改。也可以使用 Eclipse 工具栏中的 ``Save`` 按钮来保存。 +#. 若想撤销在 SDK 配置编辑器中所做的更改,可以在不保存的情况下关闭编辑器,或右键单击 ``sdkconfig`` 文件并选择 ``Load sdkconfig``,在编辑器中还原更改。 + +.. image:: ../../media/13_sdkconfig_editor.png + :alt: SDK 配置编辑器 diff --git a/docs/zh_CN/connectdevice.rst b/docs/zh_CN/connectdevice.rst new file mode 100644 index 000000000..ef2b643b3 --- /dev/null +++ b/docs/zh_CN/connectdevice.rst @@ -0,0 +1,24 @@ +连接设备 +======== + +:link_to_translation:`en:[English]` + +点击齿轮图标,选择项目的目标芯片以及设备的串口。如果在创建项目时已完成设置,则忽略此步。默认情况下,启动目标下拉菜单会显示插件支持的所有目标芯片。 + +.. image:: ../../media/target_selection.png + +点击齿轮图标可以打开 ``ESP Target`` 配置对话框,选择设备的串口并指定乐鑫开发板。插件会自动检测连接到电脑的串口。 + +.. image:: ../../media/8_launch_target.png + +关于串口及其命名规则,请参考 `ESP-IDF 文档 `_。 + +自定义目标 +---------- + +如果需要添加不在启动目标下拉菜单中的目标,请参照以下步骤: + +1. 点击启动目标下拉菜单。 +2. 选择 ``New Launch Target``。 +3. 选择 ``ESP Target``。 +4. 指定要启动应用程序的目标设备属性。为该目标输入 ``Name``,并选择电脑上乐鑫设备所连接的 ``Serial Port``。 diff --git a/docs/zh_CN/debugproject.rst b/docs/zh_CN/debugproject.rst new file mode 100644 index 000000000..6481034c4 --- /dev/null +++ b/docs/zh_CN/debugproject.rst @@ -0,0 +1,35 @@ +调试项目 +======== + +:link_to_translation:`en:[English]` + +.. |debug_icon| image:: ../../media/icons/debug.png + :height: 16px + :align: middle + +在大多数情况下,开始调试 ESP-IDF 项目前只需要完成以下两步: + +1. 创建调试配置。 +2. 检查已创建配置中指定的开发板是否与实际使用的开发板一致。 + +.. note:: + + 如果使用 Windows 操作系统,可能需要通过 Zadig 安装驱动程序,才能成功运行调试会话。有关详细说明,请参考此 `指南 `_。 + +创建调试配置的最快方式如下: + +1. 在启动栏中展开配置列表并点击 ``New Launch Configuration...``。 +2. 选择 ``ESP-IDF GDB OpenOCD Debugging``,然后双击该选项或点击 ``Next``。 +3. 上述选项会打开新的调试配置预览界面,用于查看开发板设置。 + +创建调试配置后,即可继续调试该项目: + +1. 选择刚才创建的配置。 +2. 选择 ``Debug`` 模式。 +3. 点击 ``Debug`` 图标 |debug_icon| 以开始调试。 + + +.. image:: https://github.com/espressif/idf-eclipse-plugin/assets/24419842/1fb0fb9b-a02a-4ed1-bdba-b4b4d36d100f + :alt: 调试过程 + +要了解更多有关调试配置的内容,请参阅 :ref:`ESP-IDF OpenOCD 调试 `。 diff --git a/docs/zh_CN/downloads.rst b/docs/zh_CN/downloads.rst new file mode 100644 index 000000000..05f8ed2f2 --- /dev/null +++ b/docs/zh_CN/downloads.rst @@ -0,0 +1,39 @@ +.. _downloads: + +下载 Espressif-IDE +=================== + +:link_to_translation:`en:[English]` + +点击 `此处 `_ 可查看最新的 Espressif-IDE 发行说明。下面提供了各平台的直接下载链接。 + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - 操作系统 + - 下载链接 + * - Windows + - `Espressif-IDE-win32.win32.x86_64 `_ + * - macOS x86_64 + - `Espressif-IDE-macosx-cocoa-x86_64 `_ + * - macOS aarch64 + - `Espressif-IDE-macosx-cocoa-aarch64 `_ + * - Linux + - `Espressif-IDE-linux.gtk.x86_64 `_ + + +macOS 安全注意事项(仅适用于每日自动构建的测试版本) +---------------------------------------------------- + +在 macOS 上,如果通过浏览器下载压缩包,则新版的 macOS 会严格进行安全检查,阻止其运行并提示程序已损坏。该提示并不属实,解决方法很简单:只需移除 ``com.apple.quarantine`` 扩展属性即可。 + +.. code-block:: shell + + $ xattr -d com.apple.quarantine ~/Downloads/Espressif-IDE-x.x.x-macosx.cocoa.x86_64.tar.gz + +解压缩文件后,如果应用程序仍然出现相同的警告,请检查 ``Espressif-IDE.app`` 文件夹并删除该属性: + +.. code-block:: shell + + $ xattr -dr com.apple.quarantine ~/Downloads/Espressif-IDE.app diff --git a/docs/zh_CN/faqs.rst b/docs/zh_CN/faqs.rst new file mode 100644 index 000000000..fd9819956 --- /dev/null +++ b/docs/zh_CN/faqs.rst @@ -0,0 +1,209 @@ +常见问题 +======== + +:link_to_translation:`en:[English]` + +如何查看系统中已安装的 Java 版本? +------------------------------------ + +可以在终端使用 ``java -version`` 命令进行检查。 + +如何查看 Eclipse 使用的 Java 版本? +------------------------------------- + +1. 前往 ``Help`` > ``About Eclipse`` > ``Installation Details`` > ``Configuration``。 +2. 查找 ``-vm`` 参数。 + +使用 Eclipse IDE 时,如何增大 Java 的堆内存? +---------------------------------------------- + +1. 找到 ``eclipse.ini`` 或 ``espressif-ide.ini``。 +2. 在 ``-vmargs`` 参数部分增大 Xmx 值。 例如,可以设置为 ``-Xmx2048m``。 + +该插件支持哪些操作系统? +------------------------ + +- Windows +- macOS +- Linux + +如何提供 Eclipse 环境与插件信息? +--------------------------------- + +``Help`` > ``About Eclipse`` > ``Installation Details`` > ``Configuration`` > ``Copy to Clipboard`` + +如何查看已安装的 IDF Eclipse 插件版本? +---------------------------------------- + +1. 前往菜单栏 ``Eclipse`` > ``About Eclipse`` > ``Installation Details`` > ``Installed Software`` 查看。 +2. 搜索 Espressif。 + +如何从 Eclipse 卸载 IDF Eclipse 插件? +-------------------------------------- + +1. 前往菜单栏 ``Eclipse`` > ``About Eclipse`` > ``Installation Details`` > ``Installed Software``。 +2. 搜索 Espressif。 +3. 选择 ``Espressif IDF Feature``。 +4. 点击 ``Uninstall..``。 + +为什么在 Eclipse 中无法安装 IDF 插件? +--------------------------------------- + +请从主菜单检查错误日志: + +1. 前往 ``Window`` > ``Show View`` > ``Other``。 +2. 选择 ``General`` > ``Error Log``。 + +为什么在我的 Eclipse CDT 中看不到 Espressif 菜单选项和 Espressif IDF Project 菜单? +--------------------------------------------------------------------------------------- + +1. 请确保已安装 Java 8 及以上版本,并在 Eclipse 中切换到 C/C++ 布局模式。 +2. 前往 ``Window`` > ``Perspective`` > ``Reset Perspective..`` 可重置布局模式。 + +IDF Eclipse 插件是否支持创建 CMake IDF 项目? +---------------------------------------------------------- + +可以通过 ``File`` > ``New`` > ``Espressif IDF Project`` 创建 IDF CMake 项目。 + +是否可以将现有的 IDF 项目导入 Eclipse? +---------------------------------------- + +可以通过导入菜单进行导入:``Import...`` > ``Espressif`` > ``Existing IDF Project``。 + +系统中 IDF 安装的工具位于哪里? +---------------------------------- + +Linux/MacOS 用户的默认目录为 ``$HOME/.espressif``,Windows 用户为 ``%USER_PROFILE%.espressif``。 + +为什么删除的 C/C++ 构建环境变量仍然显示? +------------------------------------------ + +你需要取消勾选首选项记录器。步骤如下: + +1. 在 Eclipse 中前往 ``Preferences`` > ``Oomph`` > ``Setup Tasks`` > ``Preference Recorder``。 +2. 取消勾选 ``Record into``。 + +如何回退到旧版 ESP-IDF Eclipse 插件? +----------------------------------------- + +1. 打开 Eclipse IDE 并卸载 ESP-IDF 插件。 +2. 重启 Eclipse IDE。 +3. 从发布页面下载旧版 ESP Eclipse 插件。 +4. 前往 ``Help`` > ``Install New Software``。 +5. 点击 ``Add`` 按钮,会弹出名为 ``Add Repository`` 的窗口。 +6. 点击 ``Archive`` 按钮并选择已下载的文件。 +7. 继续安装。 +8. 重启 Eclipse。 + +在项目中哪里可以找到 ``compile_commands.json`` 文件? +-------------------------------------------------------------- + +该文件存储在 ``/projectName/build/compile_commands.json``。 + +``compile_commands.json`` 以机器可读的格式记录了项目中所有翻译单元的完整编译器调用信息。Eclipse CDT 的索引器会使用该文件来解析代码并定位头文件。 + +如何访问 CDT 解析器的错误日志? +----------------------------------- + +前往 ``Project`` > ``C/C++ Index`` > ``Create Parser Log``。 + +如何查看错误日志? +------------------- + +在主菜单中选择 ``Window`` > ``Show View`` > ``Other``,然后选择 ``General`` > ``Error Log``。 + +如何报告死锁或 Eclipse 卡死? +------------------------------------------- + +详细说明请参阅:https://wiki.eclipse.org/How_to_report_a_deadlock。 + +在命令行中,使用 ``jps -v`` 查找 Java 进程的 PID;使用 ``jstack `` 显示 Java 进程的堆栈跟踪。 + +此处 32308 和 8824 是 Java 进程的 PID。8824 是 jps 本身,与我们无关。根据其命令行中包含 ``org.eclipse.equinox.launcher`` 可以判断 32308 是一个 Eclipse 进程。``jstack`` 命令会将该 Eclipse 进程的堆栈跟踪保存到文件 ``/tmp/jstack.txt``,请将该文件附在问题报告中。 + +为什么会出现 ``sun.security.validator.ValidatorException: PKIX path building failed`` 报错? +-------------------------------------------------------------------------------------------- + +这通常是由错误的 Java 版本或缺失的 Java 证书导致。请确保已安装 **Java 11 或更高版本** 以修复该问题。详情请查看以下链接: + +- https://esp32.com/viewtopic.php?f=13&t=12327&start=10#p50137 +- https://stackoverflow.com/questions/6908948/java-sun-security-provider-certpath-suncertpathbuilderexception-unable-to-find + +为何建议在 IDF Eclipse 插件中使用 Java 11? +--------------------------------------------- + +我们建议在使用 IDF Eclipse 插件时采用 Java 11 及以上版本(这是 Oracle 最新的 LTS 版本),因为 Eclipse 2020-06 要求使用 Java 11 才能运行 CDT。以下是来自 Eclipse 的一些重要提示: + +- `在 Eclipse 2020-06 及之后版本上使用 Java 8 安装 CDT 9.11 时需要变通办法 `_。 + + 运行 CDT 9.11 仅需 Java 8。不过,Eclipse 2020-06 及之后版本中的一个新功能可能会阻止安装向导执行安装操作。变通办法是在 ``Windows`` > ``Preferences`` > ``Install/Update`` 中关闭 "Verify provisioning operation is compatible with the currently running JRE"。参见 https://bugs.eclipse.org/bugs/show_bug.cgi?id=564407#c1。 + +- `CDT 10.0 需要 Java 11 或更高版本 `_。 + + 从 CDT 10.0 开始,运行 CDT 需要 Java 11 或更高版本。这与 Eclipse IDE 的要求一致,后者自 2020-09 起也需要 Java 11 才能运行。 + +如何在 Eclipse 中删除运行目标? +-------------------------------- + +Eclipse 中没有直接删除运行目标 (launch target) 的 UI 选项,不过可以参照以下步骤实现: + +1. 前往 Eclipse 工作区目录。 例如,我的路径是 ``/Users/myName/myTesteclipseWorkspace``。 +2. 在工作区目录中,进入 ``.metadata/.plugins/org.eclipse.core.runtime/.settings`` 文件夹。 +3. 找到 ``org.eclipse.launchbar.core.prefs`` 文件并在编辑器中打开。 +4. 搜索要删除的运行目标名称,并从文件中删除其对应的所有条目。 +5. 保存文件。 +6. 重启 Eclipse。 + +如何获取项目构建日志? +---------------------- + +1. 若想启用日志记录,请前往 ``Preferences`` > ``Project`` > ``C/C++`` > ``Build`` > ``Logging``。 +2. 勾选 ``Enable global build logging``。 +3. 构建项目。 +4. 导出 ``global-build.log``。该日志与 CDT 构建控制台中显示的构建控制台日志相同,但构建控制台通常有 buffer 大小限制,因此不会显示全部内容。 + +如何为项目构建启用详细调试输出? +-------------------------------- + +IDF Eclipse 插件使用 CMake 命令来构建项目,因此可以通过构建配置向导传递 CMake 参数。配置方法如下: + +1. 点击编辑器配置向导。 +2. 切换到 ``Build Settings`` 选项卡。 +3. 添加 ``--debug-output`` 或其他参数。 + +如何在 Espressif-IDE 中构建多个配置? +---------------------------------------- + +1. 创建一个新项目。 +2. 打开 ``Launch Configuration`` 对话框。 +3. 进入 ``Build Settings`` 选项卡,在 ``Additional CMake Arguments`` 中输入 ``-B build_release``。其中,``build_release`` 是构建文件夹的名称。 +4. 点击 ``OK`` 按钮保存该配置。 +5. 重新打开 ``Launch Configuration`` 对话框。 +6. 点击左下角的 ``Duplicate`` 按钮。 +7. 进入 ``Build Settings`` 选项卡,将 ``Additional CMake Arguments`` 更新为 ``-B build_dev``。其中,``build_dev`` 是构建文件夹的名称。 +8. 点击 ``OK`` 按钮保存该配置。 +9. 在工具栏中点击所选配置的 ``Build`` 图标(最左侧图标),这将为该配置构建项目并创建一个构建文件夹。然后在下拉菜单中选择另一配置,重复相同的步骤。 + +可以将我之前的 C/C++ 编辑器格式化文件 (.xml) 用作 ``.clang-format`` 文件吗? +---------------------------------------------------------------------------- + +不可以。不能在 ESP-IDF 项目中直接使用旧的 ``.xml`` (CDT 格式化工具)文件,因为目前使用的是 CDT LSP 编辑器,其代码格式化依赖 Clangd。Clangd 需要 ``.clang-format`` 文件,而且没有官方工具可以将 ``.xml`` 格式化文件转换为 Clang 格式。 + +不过,你可以参考 Clang 提供的若干默认的格式化风格(例如 LLVM、Google、Mozilla 等)。使用以下命令可以生成默认的 ``.clang-format`` 文件: + +.. code-block:: none + + clang-format -style=llvm -dump-config > .clang-format + +新建 ESP-IDF 项目时,根目录会自动创建带默认设置的 ``.clang-format`` 文件。Clangd 会自动识别该文件,无需额外配置。 + +对于现有项目,可以右键点击项目并选择 ``ESP-IDF`` > ``Create Clangd File``,手动创建 ``.clang-format`` 文件。 + +如果想复现旧的格式化设置,可以: + +- 手动依据 Clang 的格式化指南,将 ``.xml`` 设置映射到 Clang 格式。 +- 或者使用 AI 工具(例如 ChatGPT)将旧配置转换为新配置,然后再手动调整差异。 + +更多有关 Clang 格式的信息请参阅 `ClangFormat 文档 `_。 + +关于格式化风格,请参阅 `Clang-Format 风格选项 `_。 diff --git a/docs/zh_CN/flashdevice.rst b/docs/zh_CN/flashdevice.rst new file mode 100644 index 000000000..a3cf45744 --- /dev/null +++ b/docs/zh_CN/flashdevice.rst @@ -0,0 +1,120 @@ +烧录项目 +======== + +:link_to_translation:`en:[English]` + +.. |run_icon| image:: ../../media/icons/run.png + :height: 16px + :align: middle + +只需点击启动按钮 |run_icon| 即可开始烧录,该过程会自动使用默认命令 ``idf.py -p PORT flash`` 来烧录应用程序。 + +.. image:: https://github.com/espressif/idf-eclipse-plugin/assets/8463287/3249c01b-af23-4863-811f-c3959008f257 + :width: 767px + :alt: 烧录 + +- 如需自定义烧录参数,请参照 :ref:`本指南 ` 中的说明。 +- 如需启用 flash 加密,请参阅 :ref:`flash 加密 `。 +- 如需通过 JTAG 进行烧录,请参阅 :ref:`JTAG 烧录 `。 + +.. _customizeLaunchConfig: + +自定义烧录参数 +-------------- + +如需提供自定义的启动配置和烧录参数,请按以下步骤操作: + +#. 点击 ``Launch Configuration`` 编辑按钮。 +#. 切换到 ``Main`` 选项卡。 +#. 指定应用需运行的 ``Location``。``idf.py`` 是一个 Python 文件,所以请配置 Python 系统路径。例如:``${system_path:python}``。 +#. 指定应用的 ``Working directory``。例如:``${workspace_loc:/hello_world}``。 +#. 在 ``Arguments`` 字段中(见图片中的 ``1``),默认使用 **动态变量**: + + ``${IDF_PY} -B ${BUILD_DIR} -p ${serial_port} ${flash_command}`` + + 该默认设置会基于项目和开发板自动适配,通常无需手动更改。 + + - 点击 ``Preview`` 图标(见图片中的 ``2``)可在显示已解析的值与原始动态变量之间切换。 + - **仅在** 显示动态变量(未解析)时,此字段才可修改。 + - 如果从旧版本的插件迁移至新版本,则该字段不包含动态变量,请点击 ``Restore defaults`` (见图片中的 ``3``)进行重置。 + +#. 点击 ``OK`` 保存设置。 +#. 点击 ``Launch`` 图标,将应用烧录至所选开发板。 + +.. image:: ../../media/launch_configuration.png + :alt: 启动配置 + +.. image:: ../../media/12_flashing.png + :alt: 烧录过程 + + +.. _flashEncryption: + +flash 加密 +---------- + +.. warning:: + + 启用 flash 加密是 **不可逆的操作**。若配置不当,开发板可能会永久无法使用。请谨慎操作,仅在完全理解其影响时才启用该选项。 + +如需在 ESP‑IDF 中启用 flash 加密,请按以下步骤操作: + +#. 打开 ``sdkconfig``,启用 ``Enable flash encryption on boot`` 选项。 + + .. image:: ../../media/flash_encryption_1.png + :alt: flash 加密 sdkconfig + +#. 先正常烧录一次应用。 +#. 打开 ``Launch Configuration`` 对话框,编辑该配置,并勾选 ``Enable Flash Encryption`` 复选框。 + + .. image:: ../../media/flash_encryption_2.png + :alt: flash 加密复选框 + +#. 再次烧录应用。 + +启用该选项后,系统将根据 ESP‑IDF 设置自动对 flash 内容进行加密保护。 + +详情请参阅官方的 `flash 加密文档 `_。 + + +.. _JTAGFlashing: + +通过 JTAG 上传应用 +------------------ + +上传应用程序的默认方式是使用 UART。若要改用 JTAG,请编辑项目的启动配置并选择相应选项。 + +具体做法是,在启动配置栏中选择项目,点击齿轮图标以编辑启动配置: + +.. image:: ../../media/JtagFlash_1.png + :alt: 编辑启动配置 + +然后选择 ``Flash Over JTAG`` 选项,并完成 ``OpenOCD Setup`` 部分的配置。 + +.. image:: https://user-images.githubusercontent.com/24419842/226183857-f9d8569b-05b0-4b52-b0b2-293aac493020.png + :width: 986px + :alt: 通过 JTAG 烧录选项 + +如果没有 ``Flash Over JTAG`` 选项,并看到如下提示: + +.. image:: ../../media/JtagFlash_3.png + :alt: 需要更新 OpenOCD 的提示 + +这表示需要更新 OpenOCD。可在 `openocd-esp32 GitHub 页面 `_ 获取最新的 OpenOCD 版本。 + +为 OpenOCD 提供正确的路径 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +下载所需的 `OpenOCD 版本 `_,并将其解压到 ``.espressif/tools/openocd-esp32/`` 下的新文件夹中。 + +请参照以下步骤进行操作: + +1. 下载 JTAG 烧录所需的 `v0.10.0-esp32-20201202 `_ 版本或更高版本。 +2. 进入 ``.../.espressif/tools/openocd-esp32/`` 文件夹,并创建名为 ``v0.10.0-esp32-20201202`` 的新文件夹,将 OpenOCD 解压至此处。 +3. 最终的 OpenOCD 路径类似:``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/...``。 + +完成上述操作后,在 Eclipse 中更新 ``OPENOCD_SCRIPT`` 环境变量: + +1. 前往 ``Eclipse`` > ``Preferences`` > ``C/C++`` > ``Build`` > ``Environment``。 +2. 编辑 ``OPENOCD_SCRIPTS`` 变量,填入指向 ``openocd/scripts`` 文件夹的正确路径。 +3. OpenOCD 脚本的路径类似:``.../.espressif/tools/openocd-esp32/v0.10.0-esp32-20201202/openocd-esp32/share/openocd/scripts``。 diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst new file mode 100644 index 000000000..43ef60c7a --- /dev/null +++ b/docs/zh_CN/index.rst @@ -0,0 +1,59 @@ +Espressif-IDE +============= + +:link_to_translation:`en:[English]` + +Espressif-IDE 是基于 `Eclipse CDT `_ 的集成开发环境 (IDE),用于开发 `ESP-IDF `_ 物联网应用。该独立 IDE 专为 ESP-IDF 打造,内置了 ESP-IDF 的 Eclipse 插件、Eclipse CDT 的基本插件,以及其他辅助开发的第三方插件,可支持 ESP-IDF 应用的构建。 + +该插件可在 **macOS**、**Windows** 和 **Linux** 平台上运行。 + +.. note:: + + Espressif-IDE 3.0 及以上版本支持 ESP-IDF 5.x 及以上版本。对于 ESP-IDF 4.x 及更早版本,请使用 Espressif-IDE `2.12.1 版本 `_。 + +.. image:: ../../media/espressif-ide.png + :alt: Espressif-IDE + :align: center + +功能 +---- + +- 自动配置构建环境的变量 +- 配置集成的工具链 +- 新建项目向导与 ESP-IDF 入门示例 +- 基于 LSP 的编辑器,提供高级编辑、编译及语法高亮功能 +- 自动生成函数声明与快速跳转到函数定义 +- 可在 IDE 中直接安装和配置 ESP-IDF 及 ESP-IDF 工具 +- 用于项目专属设置的 SDK 配置编辑器 +- 集成的 CMake 编辑器插件,用于编辑 CMake 文件,例如 ``CMakeLists.txt`` +- 基于 CMake 的构建支持 +- 支持通过 UART 与 JTAG 烧录 +- ESP-IDF 专用 OpenOCD 调试功能,且内置预设配置 +- 集成的 ESP-IDF 串口监视器 +- 已预先配置好 ESP-IDF 构建环境的 ESP-IDF 专用终端 +- 应用大小分析编辑器,用于分析应用的静态内存占用情况 +- 支持堆分析,用于内存使用情况分析和内存泄漏检测 +- 支持 GDB stub 调试与应用级跟踪 +- IDE 支持中英双语界面 + +更多有关该项目的信息请参阅 https://github.com/espressif/idf-eclipse-plugin。 + +目录 +---- + +.. toctree:: + :maxdepth: 1 + + 准备工作 + 安装 + 启动项目 + 连接设备 + 构建项目 + 配置项目 + 烧录设备 + 监视输出 + 调试项目 + 其他 IDE 功能 + 故障排查 + 常见问题 + 下载 diff --git a/docs/zh_CN/installation.rst b/docs/zh_CN/installation.rst new file mode 100644 index 000000000..e8e501391 --- /dev/null +++ b/docs/zh_CN/installation.rst @@ -0,0 +1,104 @@ +安装 +==== + +:link_to_translation:`en:[English]` + +配置和安装 Espressif-IDE 包括三个主要步骤: + +1. :ref:`下载并安装 Espressif-IDE ` +2. :ref:`在 Espressif-IDE 中安装 ESP-IDF 及相关工具 ` +3. :ref:`将旧工作区迁移到新工作区 ` + +.. note:: + + 对于喜欢通过 `更新站点 `_ 安装 ESP-IDF Eclipse 插件的 Eclipse CDT 用户,请参考 :ref:`更新站点安装指南 `。 + +.. _esp-idf-installation: + +安装 Espressif-IDE +------------------ + +首先,请根据你的操作系统查看下方对应的章节,并参照说明安装 Espressif-IDE。 + +请注意,Espressif-IDE 要求通过乐鑫安装管理器 (Espressif Installation Manager, EIM) 安装 ESP-IDF,从而管理 ESP-IDF 版本和所需工具。有关使用 EIM 的详细文档,请参考 `官方指南 `_。 + +Windows +~~~~~~~ + +.. note:: + + 对于 Windows 用户,Espressif-IDE 提供带有 ESP-IDF 的离线安装包。 + +macOS/Linux +~~~~~~~~~~~ + +找到 :ref:`下载章节 ` 中适用于你操作系统的 Espressif-IDE。下载完成后,启动 IDE 并继续 :ref:`安装所需的 ESP-IDF 及相关工具 `。请确保在启动 IDE 之前已安装 Java、Python 和 Git,并且其在系统路径中可用。 + +.. _esp-idf-tools-installation: + +安装 ESP-IDF 及相关工具(新工作区) +----------------------------------- + +Espressif-IDE 提供了工具管理视图,可用来激活可用的 ESP-IDF 版本并管理相关工具。若要安装 ESP-IDF 及其工具,首先点击 `此链接 `__ 下载 EIM。 + +下载并启动 EIM 后,按照屏幕提示安装所需的 ESP-IDF 版本及相关工具。安装完成后,你可以在 IDE 内使用 ESP-IDF 管理器激活工作区中的 ESP-IDF 版本。你可以直接从 IDE 下载并启动 EIM,便于管理 ESP-IDF 版本和工具。如果你在旧版本的 Espressif-IDE 中打开工作区,系统会提示你将旧版本的配置转换为与 EIM 兼容的格式。 + +参照下列步骤,在 Espressif-IDE 中安装 ESP-IDF 及相关工具: + +1. 前往 ``Espressif`` > ``ESP-IDF Manager``,将打开如下编辑器: + + .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png + +2. 如果尚未下载和安装 EIM,请点击 ``Launch EIM`` 或 ``Download & Launch EIM`` 按钮。 + + 你可以在控制台查看下载和安装进度。EIM 启动后,可以用来安装 ESP-IDF 及相关工具。 + +3. 关闭 EIM 后,ESP-IDF 管理器编辑器将更新可用的 ESP-IDF 版本及工具的最新信息。 + + .. image:: ../../media/ToolsManager/Tool_installed_and_activated.png + +.. note:: + + 注意,早期版本的 Espressif-IDE 在内部管理工具,但现在对 ESP-IDF 的所有访问都由 EIM 统一处理。 + +你可以通过 EIM 添加任意数量的 ESP-IDF 版本,但只能激活一个版本,并将其用于编译和索引工作区中的项目。使用此功能,你可以在工作区中轻松切换 IDF 版本。 + +只需点击 ``Active`` 列旁的单选按钮即可激活特定版本。 + +最后一列的刷新按钮可用于重新加载 ESP-IDF 目录中的更改。 + +.. note:: + + 对 ESP-IDF 目录所做的任何手动更改,只有点击刷新按钮后,IDE 才会更新激活版本并显示最新内容。但如果是通过 EIM 修改了 ESP-IDF 的安装,IDE 会自动检测到,并弹出提示要求更新 ESP-IDF 版本。 + +.. image:: ../../media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png + +.. _esp-idf-tools-migration: + +迁移旧工作区到新工作区 +---------------------- + +如果你从旧版本的 Espressif-IDE 进行迁移,需要转换现有工作区,使其兼容新的 ESP-IDF 管理器。点击 `此链接 `__,下载并安装 EIM。安装 EIM 后,请按照以下步骤操作: + +1. 将下载的 EIM 可执行文件放置到适合你操作系统的位置: + + - **Windows**: `C:\Users\\.espressif\eim_gui\eim.exe` + - **Linux**: `~/.espressif/eim_gui/eim` + - **macOS**: 将 ``eim.app`` 应用包复制到 ``Applications`` 文件夹,例如 `/Applications/eim.app`. + +2. 打开 Espressif-IDE。如果 IDE 已运行,请重启。 +3. IDE 检测到 EIM 可执行文件和有效的旧工作区后,会提示你将旧工作区转换为新格式: + + .. image:: ../../media/ToolsManager/ESP-IDF_Manager_Conversion.png + +4. 点击 ``Yes`` 按钮转换旧配置。 +5. 在 Espressif-IDE 中,前往 ``Espressif`` > ``ESP-IDF Manager``。在打开的 ESP-IDF 管理器编辑器中选择并激活所需版本。 + +参考文档 +-------- + +.. toctree:: + :maxdepth: 1 + + 更新站点安装指南 + 配置 CDT 构建环境变量 diff --git a/docs/zh_CN/marketplaceupdate.rst b/docs/zh_CN/marketplaceupdate.rst new file mode 100644 index 000000000..0e210496a --- /dev/null +++ b/docs/zh_CN/marketplaceupdate.rst @@ -0,0 +1,136 @@ +.. _marketplaceupdate: + +更新站点安装指南 +================ + +:link_to_translation:`en:[English]` + +可通过以下三种方式安装 Espressif-IDE Eclipse 插件: + +- :ref:`installUpdateSiteURL` +- :ref:`install_idf_eclipse_plugin_marketplace` +- :ref:`install_idf_eclipse_plugin_local_archive` + +.. _installUpdateSiteURL: + +使用更新站点 URL 安装 IDF 插件 +------------------------------ + +可以使用更新站点 URL 将 IDF Eclipse 插件安装到现有的 Eclipse CDT 或 Espressif-IDE 中。首先,按如下方式添加发布仓库的 URL: + +1. 进入 ``Help`` > ``Install New Software``。 +2. 点击 ``Add``,在弹出窗口中: + + * 在 ``Name`` 一栏填写 ``Espressif IDF Plugin for Eclipse``。 + * 在 ``Location`` 一栏,填写插件更新站点的 URL.(`稳定版 `_) + * 点击 ``Add``。 + +3. 全选列表中的组件并继续安装。 + +若要添加测试版和每日构建版插件,可以使用以下的更新站点 URL: + +* `测试版本 `_ +* `每日构建版本 (Nightly Build) `_ + +.. note:: + + 尽管本文中的截图来自 macOS 系统中的操作,但安装说明同样适用于 Windows 和 Linux。 + +.. image:: ../../media/idf_update_site_install.png + + +.. _install_idf_eclipse_plugin_marketplace: + +通过 Eclipse 市场安装 IDF Eclipse 插件 +-------------------------------------- + +要通过 Eclipse 市场安装 ESP-IDF Eclipse 插件,请按以下步骤操作: + +1. 打开 Eclipse,前往 ``Help`` > ``Eclipse Marketplace...``。 +2. 在搜索框中输入 **ESP‑IDF Eclipse Plugin** 找到该插件。 +3. 点击 ``Install``,按照屏幕上的提示完成安装。 +4. 安装完成后,重启 Eclipse 以启用插件。 + + +.. _install_idf_eclipse_plugin_local_archive: + +通过本地压缩包安装 IDF Eclipse 插件 +----------------------------------- + +要通过本地压缩包安装 ESP-IDF Eclipse 插件,请按以下步骤操作: + +1. 点击 `此处 `_ 下载 IDF Eclipse 插件的最新更新站点压缩包。 +2. 在 Eclipse 中,进入 ``Help`` > ``Install New Software``。 +3. 点击 ``Add`` 按钮。 +4. 在 ``Add Repository`` 对话框中,选择 ``Archive`` 并选择文件 ``com.espressif.idf.update-vxxxxxxx.zip``。 +5. 点击 ``Add``。 +6. 在列表中选择 ``Espressif IDF``,然后继续安装。 +7. 完成安装后重启 Eclipse。 + +.. _upgradePlugins: + +如何升级现有的 IDF Eclipse 插件 +------------------------------- + +如果你是首次安装 IDF Eclipse 插件,请按以下步骤添加新版本的仓库: + +1. 前往 ``Window`` > ``Preferences`` > ``Install/Update`` > ``Available Software Sites``。 +2. 点击 ``Add``。 +3. 输入新仓库的 `URL `_。 +4. 点击 ``Ok``。 + +如果已经通过更新站点 URL 安装了 IDF Eclipse 插件,可按以下步骤升级到最新版本: + +1. 进入 ``Help`` > ``Check for Updates``。 +2. 如果发现有可用更新版本,选择 ``Espressif IDF Plugins for Eclipse``,并取消选择所有其他项目。 +3. 点击 ``Next`` 继续安装。 + +.. image:: ../../media/Update_plugins.png + + +.. _upgradeEspressifIdeDependencies: + +从 Espressif-IDE 3.3.0 升级到 3.4.0 +----------------------------------- + +如果插件的新版本需要更新依赖项(例如最低 CDT 版本从 11.6 更新到 12),请在通过更新站点安装插件时一并更新这些依赖项。 + +.. image:: ../../media/Update_dependencies.png + +如果所需依赖项未更新,安装程序会显示如下错误: + +``The installation cannot be completed as requested.`` + +解决方法: + +1. 点击 ``Show original error and build my own solution``。 +2. 然后勾选以下两项: + + - ``Update items already installed`` + - ``Remove items already installed`` + +.. image:: ../../media/Resolve_update_error.png + +这样可以确保安装程序更新或替换任何存在冲突的组件,从而顺利完成安装。 + +.. _troubleshooting_missing_items: + +故障排查 +-------- + +如果在安装过程中遇到错误提示 ``Cannot complete the install because one or more required items could not be found.``,通常是因为未启用 Eclipse 更新站点。 + +解决方法: + +1. 进入 ``Help`` > ``Install New Software``。 +2. 点击 ``Manage``。 +3. 确保已启用 ``Eclipse Platform - Latest Release Update Site`` 选项。 + + .. image:: ../../media/Resolve_update_error_2.png + +4. 应用更改并关闭对话框。 +5. 前往 ``Help`` > ``Check for Updates``,继续更新 IDE 及其依赖项。 + +.. note:: + + 启用 Eclipse Platform 更新站点可确保在安装或升级过程中解析所有必要的依赖项。 diff --git a/docs/zh_CN/monitoroutput.rst b/docs/zh_CN/monitoroutput.rst new file mode 100644 index 000000000..31aa385fd --- /dev/null +++ b/docs/zh_CN/monitoroutput.rst @@ -0,0 +1,31 @@ +.. _serialMonitor: + +监视输出 +======== + +:link_to_translation:`en:[English]` + +要在 Eclipse 中查看串口输出,需要将 ESP-IDF 串口监视器连接到串口。该监视器已与 `IDF 监视器 `_ 集成。 + +.. image:: ../../media/monitor.png + :alt: 串口监视器 + +要在 IDE 中启动串口监视器,请按以下步骤操作: + +1. 单击顶部工具栏中的 ``Open a Terminal`` 图标。 +2. 在终端下拉菜单中选择 ``ESP-IDF Serial Monitor``。 +3. 如果 IDE 未自动检测到你的开发版,则为其选择 ``Serial Port``。 +4. 配置串口监视器的 ``Filter Options`` 以过滤输出。 +5. 单击 ``OK`` 以启动监视器,监听 USB 端口。 + +.. image:: ../../media//10_serial_terminal.png + + +ESP-IDF 串口监视器设置 +----------------------- + +你可以自定义 ESP-IDF 串口监视器的默认字符数限制和行数。 + +1. 在 Eclipse 中,前往 ``Preferences`` > ``Espressif``。 +2. 单击 ``ESP-IDF Serial Monitor Settings``。 +3. 设置 ``Console Line Width`` 和 ``Limit Console Output``。 diff --git a/docs/zh_CN/openocddebugging.rst b/docs/zh_CN/openocddebugging.rst new file mode 100644 index 000000000..dc3a2bdee --- /dev/null +++ b/docs/zh_CN/openocddebugging.rst @@ -0,0 +1,147 @@ +.. _OpenOCDDebugging: + +ESP-IDF GDB OpenOCD 调试 +======================== + +:link_to_translation:`en:[English]` + +创建新的调试配置 +---------------- + +请按照以下步骤创建新的调试配置: + +1. 右键点击项目。 +2. 前往 ``Debug As`` > ``Debug Configurations...``,打开调试配置窗口。 +3. 在左侧面板中选择 ``ESP-IDF GDB OpenOCD Debugging``。 +4. 点击右键并创建 ``New Configuration``,为项目创建新的调试配置。 + +请逐个查看标签页并配置项目专属设置。 + +.. note:: + + 插件能自动配置大多数设置。 + +.. image:: ../../media/OpenOCDDebug_4.png + +也可以通过启动配置栏来创建调试配置: + +1. 展开启动或调试配置的列表。 +2. 点击 ``New Launch Configuration...``。 +3. 选择 ``ESP-IDF GDB OpenOCD Debugging`` 并双击此选项,也可以点击 ``Next >`` 按钮。 +4. 在 ``Debugger`` 标签页中,检查 ``Config options`` 是否适用于你的开发板。 +5. 点击 ``Finish``。 + +.. image:: ../../media/OpenOCDDebug_9.png + +Main 标签页 +------------ + +1. 输入此配置的 ``Name``,默认名称为 "{project_name} Configuration"。 +2. 在 ``Main`` 标签页中,找到 ``Project:`` 一栏,点击 ``Browse`` 按钮来选择或更改当前项目。 +3. 下一行的 ``C/C++ Application:`` 是指向 elf 文件的相对路径,例如 ``build/hello_world.elf``,对应 ``hello_world`` 项目。若不存在 elf 文件,则此项目可能尚未构建。构建项目后,该 elf 文件会出现,也可以点击 ``Browse`` 按钮进行更改。 + +``Main`` 标签页中的最后一栏是 ``Build (if required) before launching``。如果不想在每次点击 ``Debug`` 按钮时都构建项目,则选择 ``Disable auto build`` 选项。 + +上述第 1 至 3 点如下图所示。 + +.. image:: ../../media/OpenOCDDebug_5.png + +Debugger 标签页 +--------------- + +在 ``Debugger`` 标签页中,所有参数都会自动配置以开始调试,你只需检查 ``Config options`` 是否适用于你的开发板即可。该选项会根据 ``Flash voltage`` 和 ``Board`` 选项自动调整。展开开发板列表时,只会显示与所选 ``Target`` 相匹配的条目。举例来说,如果所选目标芯片是 ``esp32``,列表中不会显示 ``ESP32-S2-KALUGA-1``。若希望显示该开发版,需要先将目标芯片改为 ``esp32s2``。``Debugger`` 标签页中的第二个选项是 ``GDB executable``,该选项同样依赖于所选目标芯片,并会根据目标自动进行配置 + +还有一些其他选项,建议检查这些选项是否已自动正确配置: + +4. OpenOCD 的 ``Executable path`` 基于 Eclipse 的首选项,该路径会在安装工具后配置。请检查 ``Actual executable`` 是否正确,如果不正确,很可能是工具安装有问题,因此需要检查工具是否正确安装以避免潜在问题。若在安装工具后 ``Actual executable`` 仍不正确,则点击 ``Browse`` 并手动选择 ``openocd.exe`` 的路径。 + +5. 接下来,如果要使用内置 GDB 客户端,请确保 GDB 端口为 3333;如果要使用 :doc:`additionalfeatures/appleveltracing`,请确保 TCL 端口为 6666。另请按前文所述检查 ``Config options``。 + +6. 如上所述,在 ``GDB Client Setup`` 部分中,GDB 可执行文件会根据所选目标自动配置。你也可以点击 ``Browse`` 按钮,手动更改为 GDB 可执行文件的路径。默认情况下,``Commands`` 一行应为 ``set mem inaccessible-by-default off``。 + +上述第 4 至 6 点如下图所示。 + +.. image:: ../../media/OpenOCDDebug_6.png + +.. note:: + + 请根据已选择的乐鑫开发板更新 OpenOCD 的 ``Config options``。详情请参考 `此处 `_。 + +Startup 标签页 +-------------- + +7. 默认情况下,在加入调试会话前会将二进制文件烧录至开发板,因此无需单独将其烧录到目标芯片上。若出于某些原因不想自动烧录,可以取消勾选 ``Flash every time with application binaries`` 选项。也可以勾选 ``Enable verbose output`` 选项,启用第三调试等级 – ``-d3``。 + +8. 在 ``Initialization Commands`` 栏目下,``Initial Reset.`` 和 ``Enable ARM semihosting`` 已默认启用,且在输入框中必须填写如下几行内容: + + .. code-block:: text + + mon reset halt + flushregs + set remote hardware-watchpoint-limit 2 + +上述第 7 至 8 点如下图所示。 + +.. image:: ../../media/OpenOCDDebug_7.png + +9. 勾选 ``Load Symbols`` 和 ``Use project binary`` 选项。 + +10. 在 ``Startup`` 标签页中向下滚动,设置初始断点,以便在调试器复位 CPU 之后暂停 CPU 的运行。插件会在 ``Set break point at:`` 中指定的函数开头设置此断点。勾选该选项,并在输入框中输入主函数名,例如 ``app_main``。 + +11. 勾选 ``Continue`` 选项。这样,当按照第 8 步调用 ``mon reset halt`` 命令后,程序将自动继续执行,并在 ``app_main`` 函数的断点处停止。 + +上述第 9 至 11 点如下图所示。 + +.. image:: ../../media/OpenOCDDebug_8.png + +Common 标签页 +------------- + +可以将调试日志保存为外部文件。操作步骤如下所示: + +1. 打开 ``Common`` 标签页。 +2. 在 ``Standard Input and Output`` 部分,勾选 ``Output File`` 复选框,然后输入希望重定向日志的文件名和路径。 +3. 保存更改并运行应用程序。 + +.. note:: + + - 如果文件位于工作区中,则文件路径可以使用相对路径(见下方截图)。 + - 指定目录路径(以 ``/`` 或 ``\`` 等分隔符结尾)时,系统会自动追加 ``openocd.log`` 为文件名。例如输入 ``/tmp/logs/`` 将会创建 ``/tmp/logs/openocd.log``。 + + +.. image:: ../../media/OpenOCDDebug_13.png + +OpenOCD 配置首选项 +~~~~~~~~~~~~~~~~~~ + +OpenOCD 路径会根据 CDT 构建环境变量中定义的 ``OPENOCD_SCRIPTS`` 路径进行自动配置。 + +.. image:: ../../media/OpenOCDDebug_2.png + +开始调试 +-------- + +要开始调试,需要选择调试配置,将模式从 ``Run`` 改为 ``Debug``,并点击启动图标(即小甲虫图标)。 + +.. image:: ../../media/OpenOCDDebug_10.png + +当目标在断点处暂停后,系统会建议切换为 ``Debug perspective``。 + +.. image:: ../../media/OpenOCDDebug_11.png + +你可以根据个人偏好自定义 ``Debug perspective``。例如,你可以移动选项卡、添加你认为有用的其他视图,或移除不需要的视图。可参照以下步骤添加视图: + +1. 在 Eclipse 顶部菜单栏中点击 ``Window``。 +2. 选择 ``Show View``。 +3. 选择要添加的视图。 + +.. image:: ../../media/OpenOCDDebug_12.png + +故障排查 +-------- + +* 请确保你使用的是最新版 `Espressif-IDE `_。 +* 如果你的开发板支持或启用了 JTAG,请参考 `此文 `_ 了解更多信息。 +* 如果出现 OpenOCD 超时问题,请在首选项中增大 GDB 服务器超时设置值 ``_。通常在处理较大的应用时会出现超时问题。 +* 如果调试时遇到错误,可以参考 OpenOCD `故障排查 FAQ `_,尝试解决问题。 +* 如果你遇到问题,并希望启用 OpenOCD 调试的详细日志,请在 ``Startup`` 标签页中勾选 ``Enable verbose output`` 选项。 diff --git a/docs/zh_CN/prerequisites.rst b/docs/zh_CN/prerequisites.rst new file mode 100644 index 000000000..3f9d2fd68 --- /dev/null +++ b/docs/zh_CN/prerequisites.rst @@ -0,0 +1,31 @@ +准备工作 +======== + +:link_to_translation:`en:[English]` + +本文档概述了安装和运行 Espressif-IDE 所需的基本要求,从而实现使用 ESP-IDF 构建应用程序。 + +硬件 +---- + +- 一台使用 Windows、Linux 或 macOS 操作系统的计算机 +- 一块带有 USB 转串口接口/调试端口,或两者兼有的 ESP32 开发板 +- 一根与开发板兼容的 USB 线缆(数据与供电) + +.. Note:: + + 目前,部分开发板使用 USB Type-C 连接器。请确保准备的 USB 线可正确连接开发板。 + +软件 +---- + +运行 Espressif-IDE 的最低要求如下: + +- `Java 21 `_ 及以上 +- `Python 3.12 `_ 及以上 +- `Git `_ +- `ESP-IDF 依赖项 `_,取决于所使用的操作系统 + +.. note:: + + 请确保已正确安装并配置 Java、Python 和 Git,且已在系统的 PATH 环境变量中可用。 diff --git a/docs/zh_CN/startproject.rst b/docs/zh_CN/startproject.rst new file mode 100644 index 000000000..2d37df3ab --- /dev/null +++ b/docs/zh_CN/startproject.rst @@ -0,0 +1,69 @@ +.. _startproject: + +开始项目 +======== + +:link_to_translation:`en:[English]` + +要开始使用 Espressif-IDE,可以创建一个新项目或导入现有项目。 + +- :ref:`创建新项目 ` +- :ref:`使用 ESP-IDF 模板创建新项目 ` +- :ref:`导入现有项目 ` + +.. _newproject: + +创建新项目 +---------- + +要在 Espressif-IDE 中创建新项目,请按以下步骤操作: + +#. 依此选择 ``File`` > ``New`` > ``Espressif IDF Project``。 + + .. image:: ../../media/newproject_menu.png + :alt: 新项目菜单栏 + +#. 填写 ``Project name``。 +#. 点击 ``Finish``。 + +.. Note:: + + ESP-IDF 构建系统不支持在 ESP-IDF 或项目的路径中使用空格。 + + +.. _newprojecttemplate: + +使用 ESP-IDF 模板创建新项目 +----------------------------- + +Espressif-IDE 还提供使用 ESP-IDF 模板创建项目的功能,按以下步骤操作: + +#. 依次选择 ``File`` > ``New`` > ``Espressif IDF Project``。 +#. 在 ``Select Project Target`` 下拉列表中选择目标开发板。 +#. 在 ``Template Selection`` 部分勾选 ``Create a project using one of the templates``。 +#. 选择要使用的模板,项目名称会根据所选模板自动填写。 +#. 点击 ``Finish``。 + +.. image:: ../../media/3_new_project_default.png + +.. note:: + + 你可能会在编辑器中看到大量未解析的头文件或符号错误,这些错误会在构建完成后被解析。 + + +.. _importproject: + +导入现有项目 +------------ + +要将现有项目导入到 Espressif-IDE,请确保它是一个 CMake 项目。按以下步骤操作: + +#. 右键点击 ``Project Explorer``。 +#. 选择 ``Import..`` 菜单。 +#. 从 ``Espressif`` 导入向导菜单列表中选择 ``Existing IDF Project``。 +#. 点击 ``Next``。 +#. 点击 ``Browse...`` 选择现有项目所在目录。 +#. 如果希望使用不同的名称,请填写 ``Project name``。 +#. 点击 ``Finish``,将所选项目作为 CMake 项目导入到 Eclipse 工作区。 + +.. image:: ../../media/5_import_project.png diff --git a/docs/zh_CN/troubleshooting.rst b/docs/zh_CN/troubleshooting.rst new file mode 100644 index 000000000..5eee60b95 --- /dev/null +++ b/docs/zh_CN/troubleshooting.rst @@ -0,0 +1,91 @@ +.. _troubleshooting: + +故障排查 +========= + +:link_to_translation:`en:[English]` + +- :ref:`suggestions_for_build_errors` +- :ref:`error_log` +- :ref:`console_view_log` +- :ref:`cdt_global_build_log` +- :ref:`espressif_idf_tools_console` + +.. _suggestions_for_build_errors: + +使用提示查看器解决构建错误 +-------------------------- + +如果在构建过程中遇到问题,ESP-IDF 的提示数据库(位于 ESP-IDF 的 ``tools/idf_py_actions/hints.yml``)中可能存在该错误的提示。ESP-IDF Eclipse 插件提供了提示查看器,你可以在其中输入错误信息以查找对应提示。 + +**前提条件:** ESP-IDF v5.0 及以上版本提供 ``hints.yml`` 文件。如果你使用的是旧版本的 IDF,可以点击 `此链接 `_ 手动下载 ``hints.yml`` 文件,并保存到 ``esp-idf/tools/idf_py_actions/``。若需下载文件,请右键点击 ``Raw`` 按钮并选择 ``Save as...``。 + +要打开提示查看器,请依次前往 ``Windows`` > ``Show View`` > ``Other...`` > ``Espressif`` > ``Hints``。 + +.. image:: https://user-images.githubusercontent.com/24419842/189666994-78cc8b24-b934-426f-9df5-79af28c50c55.png + :alt: 提示查看器 + +现在你可以在查看器中输入或粘贴构建日志中的错误,例如: + +``ccache error: Failed to create temporary file for esp-idf/libsodium/CMakeFiles/..../....: No such file or directory`` + +.. image:: https://user-images.githubusercontent.com/24419842/189672552-994624f3-c0c5-48e6-aa2c-61e4ed8915e5.png + :alt: 提示查看器中的示例错误 + +如果提示信息未在屏幕上完整显示,可双击此行查看完整提示。 + +.. image:: https://user-images.githubusercontent.com/24419842/189673174-8ce40cda-6933-4dc4-a555-5d2ca617256e.png + :alt: 提示信息 + +.. _error_log: + +错误日志 +-------- + +错误日志视图记录插件发出的警告和错误提示。日志文件存储在工作区 ``.metadata`` 子目录下的 ``.log`` 文件中。 + +要打开错误日志视图,请依次前往 ``Window`` > ``Show View`` > ``Error Log``。 + +若想导出当前日志内容: + +1. 点击工具栏的 ``Export Log`` 按钮,或从右键菜单中选择 ``Export Log...``。 + + .. image:: ../../media/export_log.png + :alt: 导出日志 + +2. 输入文件名。 + +建议在报告问题时附上错误日志。 + +.. _console_view_log: + +控制台视图日志 +-------------- + +控制台视图能显示与当前运行进程或构建相关的警告和错误。 + +要访问控制台视图,前往 ``Window`` > ``Show View`` > ``Console``。 + +.. image:: ../../media/CDT_Build_Console.png + :alt: 控制台视图 + +.. _cdt_global_build_log: + +CDT 全局构建日志 +---------------- + +要启用全局构建日志,前往 ``Preferences`` > ``C/C++`` > ``Build`` > ``Logging``。 + +.. _espressif_idf_tools_console: + +乐鑫 IDF 工具控制台 +------------------- + +乐鑫 IDF 工具控制台是控制台视图的一部分,从 Eclipse 安装 IDF 工具时会自动打开。 + +如果在通过 ``Espressif`` > ``ESP-IDF Tools Manager`` > ``Install tools`` 安装 IDF 工具过程中遇到问题,请检查乐鑫 IDF 工具控制台中的错误信息。 + +如果该控制台未激活,可在控制台视图中点击 ``Display Selected Console`` 图标切换到该控制台。 + +.. image:: ../../media/IDF_tools_console.png + :alt: 乐鑫 IDF 工具控制台 diff --git a/docs_readme/images/ToolsManager/ESP-IDF_Manager_Conversion.png b/docs_readme/images/ToolsManager/ESP-IDF_Manager_Conversion.png new file mode 100644 index 000000000..61400d55e Binary files /dev/null and b/docs_readme/images/ToolsManager/ESP-IDF_Manager_Conversion.png differ diff --git a/docs_readme/images/ToolsManager/ESP-IDF_Manager_Editor_Screen.png b/docs_readme/images/ToolsManager/ESP-IDF_Manager_Editor_Screen.png index a94e900ab..d5bb98c13 100644 Binary files a/docs_readme/images/ToolsManager/ESP-IDF_Manager_Editor_Screen.png and b/docs_readme/images/ToolsManager/ESP-IDF_Manager_Editor_Screen.png differ diff --git a/features/com.espressif.idf.feature/feature.xml b/features/com.espressif.idf.feature/feature.xml index f5bb959cb..744d08491 100644 --- a/features/com.espressif.idf.feature/feature.xml +++ b/features/com.espressif.idf.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/media/ToolsManager/ESP-IDF_Configuration_Download_or_Use_ESP-IDF.png b/media/ToolsManager/ESP-IDF_Configuration_Download_or_Use_ESP-IDF.png deleted file mode 100644 index 888dca0fc..000000000 Binary files a/media/ToolsManager/ESP-IDF_Configuration_Download_or_Use_ESP-IDF.png and /dev/null differ diff --git a/media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png b/media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png new file mode 100644 index 000000000..b2d931047 Binary files /dev/null and b/media/ToolsManager/ESP-IDF_Manager_Changed_Installation_Message.png differ diff --git a/media/ToolsManager/ESP-IDF_Manager_Conversion.png b/media/ToolsManager/ESP-IDF_Manager_Conversion.png new file mode 100644 index 000000000..61400d55e Binary files /dev/null and b/media/ToolsManager/ESP-IDF_Manager_Conversion.png differ diff --git a/media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png b/media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png index a94e900ab..ded2983de 100644 Binary files a/media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png and b/media/ToolsManager/ESP-IDF_Manager_Editor_Screen.png differ diff --git a/media/ToolsManager/ESP-IDF_Manager_Multiple_versions.png b/media/ToolsManager/ESP-IDF_Manager_Multiple_versions.png deleted file mode 100644 index 77fba0f43..000000000 Binary files a/media/ToolsManager/ESP-IDF_Manager_Multiple_versions.png and /dev/null differ diff --git a/releng/com.espressif.idf.configuration/pom.xml b/releng/com.espressif.idf.configuration/pom.xml index 27472cd84..aa3713c1e 100644 --- a/releng/com.espressif.idf.configuration/pom.xml +++ b/releng/com.espressif.idf.configuration/pom.xml @@ -10,7 +10,7 @@ 4.0.12 ${tycho-version} UTF-8 - 3.7.0 + 4.0.0 diff --git a/releng/com.espressif.idf.product/idf.product b/releng/com.espressif.idf.product/idf.product index 1e4fc08f9..d17d57ec7 100644 --- a/releng/com.espressif.idf.product/idf.product +++ b/releng/com.espressif.idf.product/idf.product @@ -1,7 +1,7 @@ - + diff --git a/releng/com.espressif.idf.target/com.espressif.idf.target.target b/releng/com.espressif.idf.target/com.espressif.idf.target.target index cbe98dd3b..fe4ecae40 100644 --- a/releng/com.espressif.idf.target/com.espressif.idf.target.target +++ b/releng/com.espressif.idf.target/com.espressif.idf.target.target @@ -81,7 +81,7 @@ - + diff --git a/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/util/test/IDFUtilTest.java b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/util/test/IDFUtilTest.java index 0833ff5e3..e8b69002e 100644 --- a/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/util/test/IDFUtilTest.java +++ b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/util/test/IDFUtilTest.java @@ -259,18 +259,21 @@ public void testGetIDFExtraPaths_WhenIDFPathIsSet_ShouldReturnExpectedPaths() } @Test - public void testGetIDFExtraPaths_WhenIDFPathIsEmpty_ShouldReturnEmptyString() + void testGetIDFExtraPaths_WhenIDFPathIsEmpty_ShouldReturnEmptyString() { - try (MockedConstruction mocked = mockConstruction(IDFEnvironmentVariables.class, - (mock, context) -> when(mock.getEnvValue(IDFEnvironmentVariables.IDF_PATH)).thenReturn(""))) //$NON-NLS-1$ + try (MockedStatic mockedStatic = mockStatic(IDFUtil.class, CALLS_REAL_METHODS)) { + + mockedStatic.when(IDFUtil::getIDFPath).thenReturn(""); //$NON-NLS-1$ + String result = IDFUtil.getIDFExtraPaths(); + assertEquals("", result); //$NON-NLS-1$ } } @Test - public void testGetOpenOCDLocation_ShouldReturnOpenOCDScriptsLocationFromIdfEnvVar() + void testGetOpenOCDLocation_ShouldReturnOpenOCDScriptsLocationFromIdfEnvVar() { String openocdScriptsLoc = "openocd_path" + File.separator + "share" + File.separator + "openocd" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + File.separator + "scripts"; //$NON-NLS-1$ diff --git a/tests/com.espressif.idf.ui.test/configs/default-test-linux.properties b/tests/com.espressif.idf.ui.test/configs/default-test-linux.properties index 4cef675fc..05338624f 100644 --- a/tests/com.espressif.idf.ui.test/configs/default-test-linux.properties +++ b/tests/com.espressif.idf.ui.test/configs/default-test-linux.properties @@ -7,7 +7,7 @@ default.project.copy.wait=7000 # Default paths for esp env configs (These may need to be updated as per Automation requirements and the env being used) #Github Actions Path -default.env.esp.idf.path=/opt/actions-runner/_work/idf-eclipse-plugin/idf-eclipse-plugin/dependencies/idf-tools +default.env.esp.idf.path=/opt/actions-runner/_work/idf-eclipse-plugin/idf-eclipse-plugin/dependencies/idf-tools/v5.3/esp-idf default.env.esp.git.path=git default.env.esp.python.version=3.9 default.env.esp.python.path=python3 diff --git a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectTest.java b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectTest.java index 3c08982d6..dfb24db40 100644 --- a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectTest.java +++ b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectTest.java @@ -121,55 +121,6 @@ public void givenNewIDFProjectIsCreatedAndBuiltUsingToolbarButtonThenProjectIsBu // Fixture.thenConsoleShowsBuildSuccessful(); // } -// @Test -// public void givenNewProjectCreatedDfuBuiltThenHasDfuBin() throws Exception -// { -// Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project"); -// Fixture.givenProjectNameIs("NewProjectTestDFU"); -// Fixture.whenNewProjectIsSelected(); -// Fixture.thenLaunchTargetIsSelectedFromLaunchTargets("esp32s2"); -// Fixture.turnOnDfu(); -// Fixture.whenProjectIsBuiltUsingContextMenu(); -// Fixture.thenProjectHasTheFile("dfu.bin", "/build"); -// Fixture.turnOffDfu(); -// } - - @Test - public void givenNewProjectCreatedThenInstallNewComponent() throws Exception - { - Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project"); - Fixture.givenProjectNameIs("NewProjectForInstallNewComponentTest"); - Fixture.whenNewProjectIsSelected(); - Fixture.whenProjectIsBuiltUsingContextMenu(); - Fixture.whenInstallNewComponentUsingContextMenu(); - Fixture.whenRefreshProject(); - Fixture.checkIfNewComponentIsInstalledUsingContextMenu(); - } - -// @Test -// public void givenNewProjectCreatedBuiltAndThenProjectCleanUsingContextMenu() throws Exception -// { -// Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project"); -// Fixture.givenProjectNameIs("NewProjectCleanTest"); -// Fixture.whenNewProjectIsSelected(); -// Fixture.whenProjectIsBuiltUsingContextMenu(); -// Fixture.whenProjectCleanUsingContextMenu(); -// Fixture.whenRefreshProject(); -// Fixture.checkIfProjectCleanedFilesInBuildFolder(); -// } - - @Test - public void givenNewProjectCreatedBuiltAndThenProjectFullCleanUsingContextMenu() throws Exception - { - Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project"); - Fixture.givenProjectNameIs("NewProjectFullCleanTest"); - Fixture.whenNewProjectIsSelected(); - Fixture.whenProjectIsBuiltUsingContextMenu(); - Fixture.whenProjectFullCleanUsingContextMenu(); - Fixture.whenRefreshProject(); - Fixture.checkIfProjectFullCleanedFilesInBuildFolder(); - } - @Test public void givenNewProjectCreatedBuiltAndThenProjectPythonCleanUsingContextMenu() throws Exception { diff --git a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/EnvSetupOperations.java b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/EnvSetupOperations.java index 1f165485c..a85e0dad5 100644 --- a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/EnvSetupOperations.java +++ b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/EnvSetupOperations.java @@ -5,6 +5,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.ui.PlatformUI; @@ -43,6 +44,17 @@ public static void setupEspressifEnv(SWTWorkbenchBot bot) throws Exception { view.close(); } + + SWTBotEditor espIdfManagerView = bot.editorByTitle("ESP-IDF Manager"); + espIdfManagerView.bot().radio(0).click(); + + SWTBotView consoleView = bot.viewById("org.eclipse.ui.console.ConsoleView"); + consoleView.show(); + consoleView.setFocus(); + TestWidgetWaitUtility.waitUntilViewContains(bot, "Tools Setup complete", consoleView, 99000000); + bot.cTabItem("ESP-IDF Manager").activate(); + bot.cTabItem("ESP-IDF Manager").close(); + bot.menu("Window").menu("Perspective").menu("Open Perspective").menu("Other...").click(); bot.table().select("C/C++"); bot.button("Open").click(); @@ -71,30 +83,6 @@ public static void setupEspressifEnv(SWTWorkbenchBot bot) throws Exception bot.text().setText("progress"); bot.button("Open").click(); bot.viewByTitle("Progress").show(); - - TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot); - bot.activeShell(); - - bot.menu("Espressif").menu("ESP-IDF Manager").click(); - bot.activeShell().activate(); - bot.button("Add ESP-IDF").click(); - SWTBotShell espIdfConfigShell = bot.shell("ESP-IDF Configuration"); - espIdfConfigShell.setFocus(); - espIdfConfigShell.bot().checkBox("Use an existing ESP-IDF directory from file system").click(); - espIdfConfigShell.bot().textWithLabel("Choose existing ESP-IDF directory:") - .setText(DefaultPropertyFetcher.getStringPropertyValue(ESP_IDF_PATH_PROPERTY, "")); - espIdfConfigShell.bot().textWithLabel("Git: ") - .setText(DefaultPropertyFetcher.getStringPropertyValue(GIT_PATH_PROPERTY, "")); - espIdfConfigShell.bot().textWithLabel("Python: ") - .setText(DefaultPropertyFetcher.getStringPropertyValue(PYTHON_PATH_PROPERTY, "")); - espIdfConfigShell.bot().button("Finish").click(); - - SWTBotView consoleView = bot.viewById("org.eclipse.ui.console.ConsoleView"); - consoleView.show(); - consoleView.setFocus(); - TestWidgetWaitUtility.waitUntilViewContains(bot, "Tools Activated", consoleView, 99000000); - bot.cTabItem("ESP-IDF Manager").activate(); - bot.cTabItem("ESP-IDF Manager").close(); SETUP = true; } diff --git a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java index 2e4cff321..341624956 100644 --- a/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java +++ b/tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java @@ -703,7 +703,7 @@ public static void findInConsole(SWTWorkbenchBot bot, String consoleName, String SWTBotView consoleView = viewConsole(consoleName, bot); consoleView.show(); consoleView.setFocus(); - TestWidgetWaitUtility.waitUntilViewContains(bot, findText, consoleView, 3000); + TestWidgetWaitUtility.waitUntilViewContains(bot, findText, consoleView, 30000); } public static boolean checkShellContent(SWTWorkbenchBot bot, String shellName, String expectedText) diff --git a/tests/pom.xml b/tests/pom.xml index 965e0deaa..550801bd9 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -30,7 +30,7 @@ false org.eclipse.ui.ide.workbench - -Xms4096m -Xmx8192m + -Xms4096m -Xmx8192m -DtestRun=true ${skipTests} true ${testWorkspace}