From 4c513931e9608967a24b79fa4b6b30854a953586 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:43:53 +0200 Subject: [PATCH 01/22] IEP-1334: EIM Integration (#1116) * Initial integration Initial integration for the eim starting from the start to handle the empty workspace. Tools activation is still to be done along with code cleanup. Just the basic display is working which will also be enhanced. * Initial first flow with successful installation and loading of env in IDE with EIM * constants moved to single place and added refresh function * minor cleanup and logging for user * IEP-1334: code cleanup (Active Review) (#1125) * cleanup of unused classes and code * String internalization * update to ci file * ci error fixed * ci error fix * ci fix * fixing ci error * ci error fix * ci error fix * ci syntax fix * ci syntax indentation fix * ci syntax fix * ci syntax fix * ci fixed * ci fixed2 * ci trigger * workflow trigger fix * cleanup * ci deps isntalled * eim fix * using eim action to install * using Petr's fork * switched back to official action repo * Revert "switched back to official action repo" This reverts commit f8cd7a7a9c733d90e9960da0667aa1b37fe15773. * trying to fix action for eim * trying with petrs fork again * ci fix * back to espressif * name fixed * updated url for eim * old config export handling * fixing tests env setup * logging to verify skip tests * fixing POSIX path resolution * activation script properly sourced * added test run variable in test pom directly * adding cache option for the maven * file name updated * increasing timeout for tests * test fixes and removing redundant and outdated tests * cleanup and update for user messages * updated to handle activation of single esp-idf from eim * removing unwanted test for fixing failures * increased timeout for tests * ci updated for the release branch trigger as well * ci error fix * fix for sdkconfig server * cleaning up the idf_tools_path configuration in the IDE * added the option to include homebrew paths on macos * changes for guide link * Guidance link added to NLS * fix: Launch ESP-IDF Manager view even there is no eim_idf.json file found * fix: Don't launch multiple ESP-IDF Manager editors * fix: Update the msg and convert it to MessageDialog * fix: notify IDF not found while opening Manager view * fix: java.lang.UnsupportedOperationException * fix: File Not found issue and others * updated code for eim watcher added Next commits will do some refactoring and then implement the logic to handle these changes * refactored startup classes * initial base level logic for file watcher So this is very basic first level of file watcher service that watches the file and then also takes care that the file is wasnt changes since last startup. Initial changes only take that the file last modified is verified and just any change in file simply will give you a message box telling that something changed. More advanced and robust checks in upcoming commits * missing copyright added --------- Co-authored-by: Kondal Kolipaka --- .../idf/core/build/messages.properties | 2 +- .../com/espressif/idf/core/util/IDFUtil.java | 24 +++++++++++++++++++ .../idf/ui/tools/messages.properties | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) 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 a101c23f5..c14929c96 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 @@ -38,4 +38,4 @@ OldConfigExportDirectorSelectionDialogInfo=Choose a directory to save the export OldConfigExportCompleteSuccessMsgTitle=Import Successful OldConfigExportCompleteSuccessMsg=The configuration has been successfully Imported OldConfigExportCompleteFailMsgTitle=Conversion Failed -OldConfigExportCompleteFailMsg=An error occurred while converting old configuration. \ No newline at end of file +OldConfigExportCompleteFailMsg=An error occurred while converting old configuration. 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 91d1208d8..4f00c4b90 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 @@ -191,6 +191,30 @@ public static String getIDFPythonEnvPath() return idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PYTHON_EXE_PATH); } + + 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() { 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 025d33362..21a1684a8 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 @@ -9,5 +9,5 @@ IDFGuideLinkLabel_Text=Select the version of ESP-IDF you want to use. Click the 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 \ No newline at end of file +MsgYes=Yes +MsgNo=No From afe3d38a8568a8e3d1da071e476bb937d3c8a751 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 16 Jun 2025 15:27:32 +0200 Subject: [PATCH 02/22] IEP-1554: initial commit for the download and install logic for eim --- .../idf/core/IDFEnvironmentVariables.java | 2 + .../idf/core/tools/DownloadListener.java | 9 + .../idf/core/tools/EimDownloader.java | 200 +++++++++++ .../tools/watcher/EimJsonChangeListener.java | 2 +- .../tools/watcher/EimJsonWatchService.java | 40 ++- .../idf/ui/tools/EimButtonLaunchListener.java | 337 ++++++++++++++++++ .../idf/ui/tools/EspressifToolStartup.java | 5 + .../manager/pages/ESPIDFMainTablePage.java | 10 +- .../tools/watcher/EimJsonUiChangeHandler.java | 7 +- 9 files changed, 605 insertions(+), 7 deletions(-) create mode 100644 bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/DownloadListener.java create mode 100644 bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java create mode 100644 bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java 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 12867f621..ab53817bc 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 @@ -52,6 +52,8 @@ 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$ /** * @param variableName Environment variable Name 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..871bb3441 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/DownloadListener.java @@ -0,0 +1,9 @@ +package com.espressif.idf.core.tools; + +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/EimDownloader.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java new file mode 100644 index 000000000..ac07804fa --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java @@ -0,0 +1,200 @@ +package com.espressif.idf.core.tools; + +import java.io.FileInputStream; +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.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; + +import com.espressif.idf.core.util.StringUtil; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class EimDownloader +{ + 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; + DownloadListener listener; + + public EimDownloader(DownloadListener listener) + { + os = Platform.getOS(); + arch = Platform.getOSArch(); + this.listener = listener; + } + + public void downloadEim(IProgressMonitor monitor) + { + try + { + monitor.beginTask("Downloading EIM GUI...", IProgressMonitor.UNKNOWN); //$NON-NLS-1$ + 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); + Path downloadPath = DOWNLOAD_DIR.resolve(name); + + downloadFile(downloadUrl, downloadPath, listener, monitor); + + if (name.endsWith(".zip")) //$NON-NLS-1$ + { + Path extracted = unzip(downloadPath, DOWNLOAD_DIR.resolve("unzipped")); //$NON-NLS-1$ + listener.onCompleted(extracted.toAbsolutePath().toString()); + } + else + { + listener.onCompleted(downloadPath.toAbsolutePath().toString()); + } + } + catch (Exception e) + { + listener.onError("Download failed", e); //$NON-NLS-1$ + } finally + { + monitor.done(); + } + + } + + 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 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/watcher/EimJsonChangeListener.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/watcher/EimJsonChangeListener.java index 37d12f78d..3a8810fac 100644 --- 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 @@ -13,5 +13,5 @@ */ public interface EimJsonChangeListener { - void onJsonFileChanged(Path file); + void onJsonFileChanged(Path file, boolean paused); } 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 index 9d751b0db..64f777119 100644 --- 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 @@ -26,7 +26,9 @@ public class EimJsonWatchService extends Thread private final Path watchDirectoryPath; private final List eimJsonChangeListeners = new CopyOnWriteArrayList<>(); private volatile boolean running = true; - + private volatile boolean paused = false; + + private EimJsonWatchService() throws IOException { String directoryPathString = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_DIR @@ -73,11 +75,43 @@ public void addEimJsonChangeListener(EimJsonChangeListener listener) 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(); + } + } + + private void pauseListeners() + { + Logger.log("Listeners are paused"); //$NON-NLS-1$ + paused = true; + } + + private void unpauseListeners() + { + Logger.log("Listeners are resumed"); //$NON-NLS-1$ + paused = false; + } @Override public void run() @@ -113,7 +147,7 @@ public void run() Path fullPath = watchDirectoryPath.resolve(path); for (EimJsonChangeListener listener : eimJsonChangeListeners) { - listener.onJsonFileChanged(fullPath); + listener.onJsonFileChanged(fullPath, paused); } } } 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..e5c8763a6 --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java @@ -0,0 +1,337 @@ +package com.espressif.idf.ui.tools; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +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.jobs.Job; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.console.MessageConsoleStream; +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.EimDownloader; +import com.espressif.idf.core.tools.ToolInitializer; +import com.espressif.idf.core.tools.watcher.EimJsonWatchService; +import com.espressif.idf.ui.UIPlugin; +import com.espressif.idf.ui.tools.manager.pages.ESPIDFMainTablePage; + +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 EimDownloader eimDownloader; + + 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); + } + + @Override + public void widgetSelected(SelectionEvent selectionEvent) + { + if (!isEimInstalled()) + { + Job downloadJob = new Job("Download and Launch EIM") + { + + @Override + protected IStatus run(IProgressMonitor monitor) + { + eimDownloader = new EimDownloader(new EimDownlaodListener()); + eimDownloader.downloadEim(monitor); + return Status.OK_STATUS; + } + }; + downloadJob.setUser(true); + downloadJob.schedule(); + } + else + { + EimJsonWatchService.withPausedListeners(() -> { + try + { + Process process = launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); + new Thread(() -> { + try + { + process.waitFor(); + display.asyncExec(() -> { + try + { + standardConsoleStream.write("EIM has been closed.\n"); + refreshAfterEimClose(); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + catch (InterruptedException e) + { + Logger.log(e); + } + }).start(); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + } + + private boolean isEimInstalled() + { + return false; // toolInitializer.isEimInstalled(); + } + + private void installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException + { + standardConsoleStream.write("Mounting DMG...\n"); + ProcessBuilder mountBuilder = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()); + Process mountProcess = mountBuilder.start(); + + String volumePath = null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()))) + { + String line; + while ((line = reader.readLine()) != null) + { + if (line.contains("/Volumes/")) + { + String[] parts = line.split("\t"); + for (String part : parts) + { + if (part.startsWith("/Volumes/")) + { + volumePath = part.trim(); + break; + } + } + } + } + } + + if (volumePath == null) + throw new IOException("Failed to mount DMG: Volume path not found."); + + File[] apps = new File(volumePath).listFiles((dir, name) -> name.endsWith(".app")); + if (apps == null || apps.length == 0) + throw new FileNotFoundException("No .app found inside DMG."); + + File appBundle = apps[0]; + Path targetAppPath = Paths.get("/Applications", appBundle.getName()); + + standardConsoleStream.write("Copying app to /Applications...\n"); + + // Copy to /Applications + ProcessBuilder copyBuilder = new ProcessBuilder("cp", "-R", appBundle.getAbsolutePath(), + targetAppPath.toString()); + copyBuilder.inheritIO().start().waitFor(); + + standardConsoleStream.write("Unmounting DMG...\n"); + new ProcessBuilder("hdiutil", "detach", volumePath).start().waitFor(); + + standardConsoleStream.write("Launching app from /Applications...\n"); + + Process openProcess = new ProcessBuilder("open", "-W", "-a", targetAppPath.toString()).start(); + new Thread(() -> { + try + { + openProcess.waitFor(); + display.asyncExec(() -> { + try + { + standardConsoleStream.write("EIM has been closed.\n"); + refreshAfterEimClose(); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + catch (InterruptedException e) + { + Logger.log(e); + } + }).start(); + } + + private void refreshAfterEimClose() + { + display.asyncExec(() -> { + try + { + standardConsoleStream.write("Refreshing UI after EIM closed...\n"); + espidfMainTablePage.refreshEditorUI(); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + + private Process launchEim(String eimPath) throws IOException + { + if (!Files.exists(Paths.get(eimPath))) + throw new FileNotFoundException("EIM path not found: " + eimPath); + + String os = Platform.getOS(); + List command; + + if (os.equals(Platform.OS_WIN32)) + { + // Windows .exe or .msi + command = List.of("cmd.exe", "/c", eimPath.toString()); + } + else if (os.equals(Platform.OS_MACOSX)) + { + command = List.of("open", "-a", eimPath.toString()); + } + else if (os.equals(Platform.OS_LINUX)) + { + command = List.of("bash", "-c", "\"" + eimPath.toString() + "\""); + } + else + { + throw new UnsupportedOperationException("Unsupported OS: " + os); + } + + Process process = new ProcessBuilder(command).redirectErrorStream(true).start(); + + standardConsoleStream.write("Launched EIM application: " + eimPath + "\n"); + + return process; + } + + 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) + { + EimJsonWatchService.withPausedListeners(() -> { + display.syncExec(() -> { + try + { + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + if (filePath.endsWith(".dmg")) + { + try + { + installAndLaunchDmg(Paths.get(filePath)); + } + catch ( + IOException + | InterruptedException e) + { + Logger.log(e); + } + } + else + { + Process process; + try + { + process = launchEim(filePath); + new Thread(() -> { + try + { + process.waitFor(); + display.asyncExec(() -> { + try + { + standardConsoleStream.write("EIM has been closed.\n"); + } + catch (IOException e) + { + Logger.log(e); + } + refreshAfterEimClose(); + }); + } + catch (Exception ex) + { + Logger.log(ex); + } + }).start(); + } + 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 index 830e6922e..ffb2fb6e6 100644 --- 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 @@ -19,6 +19,7 @@ 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.EimConstants; @@ -77,6 +78,10 @@ public void earlyStartup() { return; } + + // Set EimPath on every startup to ensure proper path in configurations + IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); if (!toolInitializer.isEspIdfSet()) { 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 3e27a4c43..9a1c3dff9 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 @@ -45,6 +45,7 @@ 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.tools.EimButtonLaunchListener; import com.espressif.idf.ui.tools.Messages; import com.espressif.idf.ui.tools.SetupToolsJobListener; @@ -63,6 +64,7 @@ public class ESPIDFMainTablePage private TableViewerColumn activateColumn; private TableViewerColumn removeColumn; private TableViewerColumn nameColumn; + private Button eimLaunchBtn; private TableColumnLayout tableColumnLayout; private Composite tableComposite; @@ -98,12 +100,12 @@ public Composite createPage(Composite composite) final int numColumns = 2; GridLayout gridLayout = new GridLayout(numColumns, false); container.setLayout(gridLayout); - createGuideLink(container); + createButtonAndGuideLink(container); createIdfTable(container); return container; } - private void createGuideLink(Composite composite) + private void createButtonAndGuideLink(Composite composite) { Link guideLink = new Link(composite, SWT.WRAP); guideLink.setText(Messages.IDFGuideLinkLabel_Text); @@ -119,6 +121,10 @@ private void createGuideLink(Composite composite) Logger.log(ex); } }); + + eimLaunchBtn = new Button(composite, SWT.PUSH); + eimLaunchBtn.setText("Launch EIM"); + eimLaunchBtn.addSelectionListener(new EimButtonLaunchListener(espidfMainTablePage, Display.getDefault(), getConsoleStream(false), getConsoleStream(true))); } public void setupInitialEspIdf() 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 index 6bf8c4734..71418f391 100644 --- 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 @@ -47,8 +47,13 @@ public EimJsonUiChangeHandler(Preferences preferences) } @Override - public void onJsonFileChanged(Path file) + public void onJsonFileChanged(Path file, boolean paused) { + if (paused) + { + Logger.log("Listener is paused"); + return; + } int response = displayMessageToUser(); handleUserResponse(response); } From 555de56b61debff1824045ba3ec43aca2bba1c80 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:36:39 +0200 Subject: [PATCH 03/22] IEP-1554: Finalized eim launch and download changes --- .../idf/core/build/messages.properties | 4 +- .../{EimDownloader.java => EimLoader.java} | 140 +++++++++++- .../tools/watcher/EimJsonWatchService.java | 2 +- .../idf/ui/tools/EimButtonLaunchListener.java | 208 +++++------------- .../idf/ui/tools/EspressifToolStartup.java | 68 +++++- .../ui/tools/ManageEspIdfVersionsHandler.java | 21 -- .../com/espressif/idf/ui/tools/Messages.java | 2 + .../manager/pages/ESPIDFMainTablePage.java | 7 +- .../idf/ui/tools/messages.properties | 2 + 9 files changed, 268 insertions(+), 186 deletions(-) rename bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/{EimDownloader.java => EimLoader.java} (57%) 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 c14929c96..a872093ec 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,8 +19,8 @@ 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 Not Found -ToolsInitializationEimMissingMsgBoxMessage=ESP-IDF is not found on your system. To use the IDE, install ESP-IDF using EIM - GUI Installer. \n\nOnce installed, the IDE will automatically detect ESP-IDF. You can verify and activate it from the ESP-IDF Manager, accessible via the menu: Espressif > ESP-IDF Manager.\n\n +ToolsInitializationEimMissingMsgBoxTitle=ESP-IDF Installation Required +ToolsInitializationEimMissingMsgBoxMessage=ESP-IDF is not currently installed on your system. To proceed, you can download and launch the EIM - GUI Installer directly from this IDE.\n\nWould you like to download and start the EIM installer now?\n\nOnce installation is complete, the IDE will automatically detect ESP-IDF. You can also verify and activate it 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=Yes ToolsInitializationDifferentPathMessageBoxOptionNo=No diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java similarity index 57% rename from bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java rename to bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java index ac07804fa..7153b449f 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimDownloader.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/EimLoader.java @@ -1,6 +1,9 @@ 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; @@ -11,33 +14,164 @@ 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.Platform; +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.util.StringUtil; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -public class EimDownloader +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; - DownloadListener listener; + private DownloadListener listener; + private MessageConsoleStream standardConsoleStream; + private MessageConsoleStream errorConsoleStream; + private Display display; - public EimDownloader(DownloadListener listener) + 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)) + { + command = List.of("cmd.exe", "/c", eimPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$ + } + else if (os.equals(Platform.OS_MACOSX)) + { + command = List.of("open", "-a", eimPath.toString()); //$NON-NLS-1$//$NON-NLS-2$ + } + else if (os.equals(Platform.OS_LINUX)) + { + command = List.of("bash", "-c", "\"" + eimPath.toString() + "\""); //$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(); + + logMessage("Launched EIM application: " + eimPath + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + + return process; + } + + public Process installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException + { + logMessage("Mounting DMG...\n"); //$NON-NLS-1$ + ProcessBuilder mountBuilder = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$ + Process mountProcess = mountBuilder.start(); + + String volumePath = null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()))) + { + String line; + while ((line = reader.readLine()) != null) + { + if (line.contains("/Volumes/")) //$NON-NLS-1$ + { + String[] parts = line.split("\t"); //$NON-NLS-1$ + for (String part : parts) + { + if (part.startsWith("/Volumes/")) //$NON-NLS-1$ + { + volumePath = part.trim(); + break; + } + } + } + } + } + + 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$ + + // Copy to /Applications + ProcessBuilder copyBuilder = new ProcessBuilder("cp", "-R", appBundle.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$ + targetAppPath.toString()); + copyBuilder.inheritIO().start().waitFor(); + + logMessage("Unmounting DMG...\n"); //$NON-NLS-1$ + new ProcessBuilder("hdiutil", "detach", volumePath).start().waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ + + logMessage("Launching app from /Applications...\n"); //$NON-NLS-1$ + + Process openProcess = new ProcessBuilder("open", "-W", "-a", targetAppPath.toString()).start(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, targetAppPath.toString()); + return openProcess; + } + public void downloadEim(IProgressMonitor monitor) { 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 index 64f777119..b735b528b 100644 --- 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 @@ -89,7 +89,7 @@ public static void withPausedListeners(Runnable task) try { - task.run(); + task.run(); } catch (Exception e) { 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 index e5c8763a6..8223e75b7 100644 --- 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 @@ -1,33 +1,33 @@ package com.espressif.idf.ui.tools; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; -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.jobs.Job; 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.EimDownloader; +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.vo.EimJson; import com.espressif.idf.core.tools.watcher.EimJsonWatchService; 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; public class EimButtonLaunchListener extends SelectionAdapter @@ -39,7 +39,7 @@ public class EimButtonLaunchListener extends SelectionAdapter private IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); private MessageConsoleStream standardConsoleStream; private MessageConsoleStream errorConsoleStream; - private EimDownloader eimDownloader; + private EimLoader eimLoader; public EimButtonLaunchListener(ESPIDFMainTablePage espidfMainTablePage, Display display, MessageConsoleStream standardConsoleStream, MessageConsoleStream errorConsoleStream) @@ -50,8 +50,9 @@ public EimButtonLaunchListener(ESPIDFMainTablePage espidfMainTablePage, Display 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) { @@ -63,8 +64,7 @@ public void widgetSelected(SelectionEvent selectionEvent) @Override protected IStatus run(IProgressMonitor monitor) { - eimDownloader = new EimDownloader(new EimDownlaodListener()); - eimDownloader.downloadEim(monitor); + eimLoader.downloadEim(monitor); return Status.OK_STATUS; } }; @@ -76,30 +76,10 @@ protected IStatus run(IProgressMonitor monitor) EimJsonWatchService.withPausedListeners(() -> { try { - Process process = launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); - new Thread(() -> { - try - { - process.waitFor(); - display.asyncExec(() -> { - try - { - standardConsoleStream.write("EIM has been closed.\n"); - refreshAfterEimClose(); - } - catch (IOException e) - { - Logger.log(e); - } - }); - } - catch (InterruptedException e) - { - Logger.log(e); - } - }).start(); + Process process = eimLoader.launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); + waitForEimClosure(process); } - catch (IOException e) + catch (IOException | InterruptedException e) { Logger.log(e); } @@ -109,128 +89,77 @@ protected IStatus run(IProgressMonitor monitor) private boolean isEimInstalled() { - return false; // toolInitializer.isEimInstalled(); + return toolInitializer.isEimInstalled(); } - private void installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException + private void waitForEimClosure(Process process) throws InterruptedException { - standardConsoleStream.write("Mounting DMG...\n"); - ProcessBuilder mountBuilder = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()); - Process mountProcess = mountBuilder.start(); - - String volumePath = null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()))) - { - String line; - while ((line = reader.readLine()) != null) - { - if (line.contains("/Volumes/")) - { - String[] parts = line.split("\t"); - for (String part : parts) - { - if (part.startsWith("/Volumes/")) - { - volumePath = part.trim(); - break; - } - } - } - } - } - - if (volumePath == null) - throw new IOException("Failed to mount DMG: Volume path not found."); - - File[] apps = new File(volumePath).listFiles((dir, name) -> name.endsWith(".app")); - if (apps == null || apps.length == 0) - throw new FileNotFoundException("No .app found inside DMG."); - - File appBundle = apps[0]; - Path targetAppPath = Paths.get("/Applications", appBundle.getName()); - - standardConsoleStream.write("Copying app to /Applications...\n"); - - // Copy to /Applications - ProcessBuilder copyBuilder = new ProcessBuilder("cp", "-R", appBundle.getAbsolutePath(), - targetAppPath.toString()); - copyBuilder.inheritIO().start().waitFor(); - - standardConsoleStream.write("Unmounting DMG...\n"); - new ProcessBuilder("hdiutil", "detach", volumePath).start().waitFor(); - - standardConsoleStream.write("Launching app from /Applications...\n"); - - Process openProcess = new ProcessBuilder("open", "-W", "-a", targetAppPath.toString()).start(); - new Thread(() -> { + Thread t = new Thread(() -> { try { - openProcess.waitFor(); + process.waitFor(); display.asyncExec(() -> { try { standardConsoleStream.write("EIM has been closed.\n"); - refreshAfterEimClose(); } catch (IOException e) { Logger.log(e); } + refreshAfterEimClose(); }); } - catch (InterruptedException e) + catch (Exception ex) { - Logger.log(e); + Logger.log(ex); } - }).start(); + }); + + t.start(); + t.join(); } - + private void refreshAfterEimClose() { display.asyncExec(() -> { try { + launchEspIdfManager(); standardConsoleStream.write("Refreshing UI after EIM closed...\n"); espidfMainTablePage.refreshEditorUI(); } - catch (IOException e) + catch (IOException | PartInitException e) { Logger.log(e); } }); } - - private Process launchEim(String eimPath) throws IOException + + private void launchEspIdfManager() throws PartInitException { - if (!Files.exists(Paths.get(eimPath))) - throw new FileNotFoundException("EIM path not found: " + eimPath); - - String os = Platform.getOS(); - List command; - - if (os.equals(Platform.OS_WIN32)) - { - // Windows .exe or .msi - command = List.of("cmd.exe", "/c", eimPath.toString()); - } - else if (os.equals(Platform.OS_MACOSX)) - { - command = List.of("open", "-a", eimPath.toString()); - } - else if (os.equals(Platform.OS_LINUX)) - { - command = List.of("bash", "-c", "\"" + eimPath.toString() + "\""); - } - else - { - throw new UnsupportedOperationException("Unsupported OS: " + os); - } - - Process process = new ProcessBuilder(command).redirectErrorStream(true).start(); - - standardConsoleStream.write("Launched EIM application: " + eimPath + "\n"); + 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 | IOException e) + { + Logger.log("Failed to open ESP-IDF Manager Editor."); + Logger.log(e); + } + }); - return process; } private class EimDownlaodListener implements DownloadListener @@ -271,7 +200,8 @@ public void onCompleted(String filePath) { try { - installAndLaunchDmg(Paths.get(filePath)); + Process process = eimLoader.installAndLaunchDmg(Paths.get(filePath)); + waitForEimClosure(process); } catch ( IOException @@ -285,35 +215,17 @@ public void onCompleted(String filePath) Process process; try { - process = launchEim(filePath); - new Thread(() -> { - try - { - process.waitFor(); - display.asyncExec(() -> { - try - { - standardConsoleStream.write("EIM has been closed.\n"); - } - catch (IOException e) - { - Logger.log(e); - } - refreshAfterEimClose(); - }); - } - catch (Exception ex) - { - Logger.log(ex); - } - }).start(); + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, filePath); + process = eimLoader.launchEim(filePath); + waitForEimClosure(process); } - catch (IOException e) + catch (IOException | InterruptedException e) { Logger.log(e); } } + }); } 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 index ffb2fb6e6..23701bba5 100644 --- 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 @@ -5,18 +5,24 @@ package com.espressif.idf.ui.tools; import java.io.IOException; -import java.text.MessageFormat; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IStartup; +import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.console.MessageConsoleStream; import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.intro.IIntroManager; import org.osgi.service.prefs.Preferences; import com.espressif.idf.core.IDFEnvironmentVariables; @@ -29,11 +35,12 @@ 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.IDFConsole; import com.espressif.idf.ui.UIPlugin; -import com.espressif.idf.ui.dialogs.MessageLinkDialog; 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; import com.espressif.idf.ui.tools.watcher.EimJsonUiChangeHandler; /** @@ -65,9 +72,8 @@ public void earlyStartup() notifyMissingTools(); return; } - - if (toolInitializer.isOldEspIdfConfigPresent() - && !toolInitializer.isOldConfigExported()) + + if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) { Logger.log("Old configuration found and not converted"); handleOldConfigExport(); @@ -78,7 +84,7 @@ public void earlyStartup() { return; } - + // Set EimPath on every startup to ensure proper path in configurations IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); @@ -151,12 +157,58 @@ private void showEimJsonStateChangeNotification() private void notifyMissingTools() { Display.getDefault().asyncExec(() -> { - MessageLinkDialog.openWarning(Display.getDefault().getActiveShell(), + boolean userAgreed = MessageDialog.openQuestion(Display.getDefault().getActiveShell(), Messages.ToolsInitializationEimMissingMsgBoxTitle, - MessageFormat.format(Messages.ToolsInitializationEimMissingMsgBoxMessage, EimConstants.EIM_URL)); + Messages.ToolsInitializationEimMissingMsgBoxMessage); + if (userAgreed) + { + // Download Launch EIM + downloadAndLaunchEim(); + } + else + { + Logger.log("User selected No to download EIM"); + } }); } + private void downloadAndLaunchEim() + { + closeWelcomePage(); + Event event = new Event(); + event.widget = new Label(Display.getDefault().getActiveShell(), 0); + SelectionEvent simulatedEvent = new SelectionEvent(event); + EimButtonLaunchListener eimButtonLaunchListener = new EimButtonLaunchListener( + ESPIDFMainTablePage.getInstance(null), Display.getDefault(), getConsoleStream(false), + getConsoleStream(true)); + eimButtonLaunchListener.widgetSelected(simulatedEvent); + } + + private void closeWelcomePage() + { + Display.getDefault().asyncExec(() -> { + IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench != null) + { + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + if (window != null) + { + IIntroManager introManager = workbench.getIntroManager(); + if (introManager.getIntro() != null) + { + introManager.closeIntro(introManager.getIntro()); + } + } + } + }); + } + + 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(() -> { 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 dc1dff888..abba3d179 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,8 +1,6 @@ package com.espressif.idf.ui.tools; import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; @@ -11,14 +9,10 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.ide.IDE; -import com.espressif.idf.core.build.Messages; 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.vo.EimJson; -import com.espressif.idf.core.tools.vo.IdfInstalled; import com.espressif.idf.core.util.IDFUtil; -import com.espressif.idf.ui.dialogs.MessageLinkDialog; import com.espressif.idf.ui.handlers.EclipseHandler; import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; import com.espressif.idf.ui.tools.manager.EimEditorInput; @@ -65,22 +59,7 @@ public void run() { Logger.log(e); } - - if (eimJson.getIdfInstalled().isEmpty()) - { - notifyIDFNotFound(); - } } }); } - - private void notifyIDFNotFound() - { - Display.getDefault().asyncExec(() -> { - MessageLinkDialog.openWarning(Display.getDefault().getActiveShell(), - Messages.ToolsInitializationEimMissingMsgBoxTitle, - MessageFormat.format(Messages.ToolsInitializationEimMissingMsgBoxMessage, EimConstants.EIM_URL)); - - }); - } } 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 a6659697c..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 @@ -23,6 +23,8 @@ public class Messages extends NLS public static String EspIdfManagerNameCol; public static String EspIdfManagerReloadBtnToolTip; public static String IDFGuideLinkLabel_Text; + public static String EIMButtonDownloadText; + public static String EIMButtonLaunchText; public static String IDFToolsHandler_ToolsManagerConsole; 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 9a1c3dff9..8895e52ac 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 @@ -109,7 +109,7 @@ 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, 2, 1)); + guideLink.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1)); guideLink.addListener(SWT.Selection, e -> { try { @@ -123,7 +123,7 @@ private void createButtonAndGuideLink(Composite composite) }); eimLaunchBtn = new Button(composite, SWT.PUSH); - eimLaunchBtn.setText("Launch EIM"); + eimLaunchBtn.setText(eimJson.getIdfInstalled().isEmpty() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); eimLaunchBtn.addSelectionListener(new EimButtonLaunchListener(espidfMainTablePage, Display.getDefault(), getConsoleStream(false), getConsoleStream(true))); } @@ -190,6 +190,7 @@ public void refreshEditorUI() tableViewer.setInput(idfInstalledList); tableViewer.getControl().requestLayout(); tableViewer.refresh(); + eimLaunchBtn.setText(eimJson.getIdfSelectedId().isEmpty() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); container.redraw(); } @@ -198,7 +199,7 @@ private Composite createIdfTable(Composite parent) Group idfToolsGroup = new Group(parent, SWT.SHADOW_ETCHED_IN); idfToolsGroup.setText("IDF Tools"); 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); 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 21a1684a8..1b6344e74 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 @@ -6,6 +6,8 @@ EspIdfManagerNameCol=Name EspIdfManagerReloadBtnToolTip=Reload from disk 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 & 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. From b0c918dfa547fc8f75249ecffffdf75535d5390f Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:45:04 +0200 Subject: [PATCH 04/22] javadocs and copyright disclaimer --- .../espressif/idf/core/tools/DownloadListener.java | 10 ++++++++++ .../src/com/espressif/idf/core/tools/EimLoader.java | 10 ++++++++++ .../idf/ui/tools/EimButtonLaunchListener.java | 11 +++++++++++ 3 files changed, 31 insertions(+) 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 index 871bb3441..959713f13 100644 --- 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 @@ -1,5 +1,15 @@ +/******************************************************************************* + * 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); 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 index 7153b449f..a4d02062d 100644 --- 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 @@ -1,3 +1,7 @@ +/******************************************************************************* + * 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; @@ -31,6 +35,12 @@ 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$ 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 index 8223e75b7..ce36e1e27 100644 --- 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 @@ -1,3 +1,7 @@ +/******************************************************************************* + * 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; @@ -30,6 +34,13 @@ 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; From 22c56996b771d9be41458f61489ace2b65ddd87b Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:01:32 +0200 Subject: [PATCH 05/22] fixed issue with review NPE --- .../com/espressif/idf/ui/tools/EspressifToolStartup.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 index 23701bba5..33ffdb626 100644 --- 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 @@ -58,9 +58,9 @@ public class EspressifToolStartup implements IStartup @Override public void earlyStartup() { - Preferences preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE + preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE .getNode(UIPlugin.PLUGIN_ID); - ToolInitializer toolInitializer = new ToolInitializer(preferences); + toolInitializer = new ToolInitializer(preferences); EimJsonStateChecker stateChecker = new EimJsonStateChecker(preferences); eimJsonUiChangeHandler = new EimJsonUiChangeHandler(preferences); stateChecker.updateLastSeenTimestamp(); @@ -76,7 +76,7 @@ public void earlyStartup() if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) { Logger.log("Old configuration found and not converted"); - handleOldConfigExport(); + EimJsonWatchService.withPausedListeners(()-> handleOldConfigExport()); } EimJson eimJson = toolInitializer.loadEimJson(); From 1bfdedd5ca9d318cf24497ce3cae0dbb509a9abd Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:51:36 +0200 Subject: [PATCH 06/22] testing issues and paths validations --- .../espressif/idf/core/tools/EimLoader.java | 2 +- .../idf/core/tools/ToolInitializer.java | 25 ++- .../idf/ui/tools/EimButtonLaunchListener.java | 7 +- .../idf/ui/tools/EspressifToolStartup.java | 196 +++++++++++++++--- .../manager/pages/ESPIDFMainTablePage.java | 8 +- 5 files changed, 186 insertions(+), 52 deletions(-) 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 index a4d02062d..899e54403 100644 --- 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 @@ -178,7 +178,7 @@ public Process installAndLaunchDmg(Path dmgPath) throws IOException, Interrupted logMessage("Launching app from /Applications...\n"); //$NON-NLS-1$ Process openProcess = new ProcessBuilder("open", "-W", "-a", targetAppPath.toString()).start(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, targetAppPath.toString()); + new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, targetAppPath.toString().concat("/Contents/MacOS/eim")); //$NON-NLS-1$ return openProcess; } 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 index 42fb18a12..c84806404 100644 --- 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 @@ -6,6 +6,8 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -17,9 +19,11 @@ 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.vo.EimJson; +import com.espressif.idf.core.util.StringUtil; /** * Initializer class to be used on startup of eclipse and also @@ -31,16 +35,26 @@ 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() { - return isEimIdfJsonPresent(); + String eimExePathEnv = idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH); + return !StringUtil.isEmpty(eimExePathEnv) && Files.exists(Paths.get(eimExePathEnv)); + } + + 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() @@ -68,7 +82,7 @@ public IStatus exportOldConfig() throws IOException { // eim import pathToOldConfigJson List commands = new ArrayList<>(); - commands.add(loadEimJson().getEimPath()); + commands.add(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); commands.add("import"); //$NON-NLS-1$ commands.add(oldConfig.getAbsolutePath()); ProcessBuilderFactory processBuilderFactory = new ProcessBuilderFactory(); @@ -93,13 +107,6 @@ private File getOldConfigFile() return new File(path.toOSString(), EimConstants.TOOL_SET_CONFIG_LEGACY_CONFIG_FILE); } - private boolean isEimIdfJsonPresent() - { - String path = Platform.getOS().equals(Platform.OS_WIN32) ? EimConstants.EIM_WIN_PATH - : EimConstants.EIM_POSIX_PATH; - return new File(path).exists(); - } - public boolean isEspIdfSet() { return preferences.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false); 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 index ce36e1e27..cb1e82ddb 100644 --- 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 @@ -67,7 +67,7 @@ public EimButtonLaunchListener(ESPIDFMainTablePage espidfMainTablePage, Display @Override public void widgetSelected(SelectionEvent selectionEvent) { - if (!isEimInstalled()) + if (!toolInitializer.isEimInstalled()) { Job downloadJob = new Job("Download and Launch EIM") { @@ -98,11 +98,6 @@ protected IStatus run(IProgressMonitor monitor) } } - private boolean isEimInstalled() - { - return toolInitializer.isEimInstalled(); - } - private void waitForEimClosure(Process process) throws InterruptedException { Thread t = new Thread(() -> { 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 index 33ffdb626..5a43608f5 100644 --- 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 @@ -5,14 +5,15 @@ 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.SWT; -import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IStartup; @@ -28,7 +29,9 @@ 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.vo.EimJson; import com.espressif.idf.core.tools.watcher.EimJsonStateChecker; @@ -40,7 +43,6 @@ 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; import com.espressif.idf.ui.tools.watcher.EimJsonUiChangeHandler; /** @@ -54,19 +56,29 @@ 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); + toolInitializer = new ToolInitializer(preferences); + standardConsoleStream = getConsoleStream(false); + errorConsoleStream = getConsoleStream(true); + idfEnvironmentVariables = new IDFEnvironmentVariables(); + eimLoader = new EimLoader(new StartupClassDownloadEimDownloadListener(), + standardConsoleStream, errorConsoleStream, Display.getDefault()); EimJsonStateChecker stateChecker = new EimJsonStateChecker(preferences); eimJsonUiChangeHandler = new EimJsonUiChangeHandler(preferences); stateChecker.updateLastSeenTimestamp(); EimJsonWatchService.getInstance().addEimJsonChangeListener(eimJsonUiChangeHandler); - if (!toolInitializer.isEimInstalled()) + if (!toolInitializer.isEimInstalled() && !toolInitializer.isEimIdfJsonPresent()) { Logger.log("EIM not installed"); notifyMissingTools(); @@ -78,22 +90,15 @@ public void earlyStartup() Logger.log("Old configuration found and not converted"); EimJsonWatchService.withPausedListeners(()-> handleOldConfigExport()); } - - EimJson eimJson = toolInitializer.loadEimJson(); - if (eimJson == null) + else if (toolInitializer.isEimIdfJsonPresent() && !toolInitializer.isEspIdfSet()) { - return; + eimJson = toolInitializer.loadEimJson(); + promptUserToOpenToolManager(eimJson); } // Set EimPath on every startup to ensure proper path in configurations - IDFEnvironmentVariables idfEnvironmentVariables = new IDFEnvironmentVariables(); idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); - if (!toolInitializer.isEspIdfSet()) - { - promptUserToOpenToolManager(eimJson); - } - if (stateChecker.wasModifiedSinceLastRun()) { showEimJsonStateChangeNotification(); @@ -156,32 +161,39 @@ private void showEimJsonStateChangeNotification() private void notifyMissingTools() { - Display.getDefault().asyncExec(() -> { - boolean userAgreed = MessageDialog.openQuestion(Display.getDefault().getActiveShell(), + boolean [] userAgreed = new boolean[1]; + Display.getDefault().syncExec(() -> { + userAgreed[0] = MessageDialog.openQuestion(Display.getDefault().getActiveShell(), Messages.ToolsInitializationEimMissingMsgBoxTitle, Messages.ToolsInitializationEimMissingMsgBoxMessage); - if (userAgreed) - { - // Download Launch EIM - downloadAndLaunchEim(); - } - else - { - Logger.log("User selected No to download EIM"); - } }); + + if (userAgreed[0]) + { + // Download Launch EIM + downloadAndLaunchEim(); + } + else + { + Logger.log("User selected No to download EIM"); + } } private void downloadAndLaunchEim() { closeWelcomePage(); - Event event = new Event(); - event.widget = new Label(Display.getDefault().getActiveShell(), 0); - SelectionEvent simulatedEvent = new SelectionEvent(event); - EimButtonLaunchListener eimButtonLaunchListener = new EimButtonLaunchListener( - ESPIDFMainTablePage.getInstance(null), Display.getDefault(), getConsoleStream(false), - getConsoleStream(true)); - eimButtonLaunchListener.widgetSelected(simulatedEvent); + 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 void closeWelcomePage() @@ -248,4 +260,120 @@ private void openEspIdfManager(EimJson eimJson) 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) + { + EimJsonWatchService.withPausedListeners(() -> { + Display.getDefault().syncExec(() -> { + try + { + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); + } + catch (IOException e) + { + Logger.log(e); + } + }); + + if (filePath.endsWith(".dmg")) + { + try + { + Process process = eimLoader.installAndLaunchDmg(Paths.get(filePath)); + waitForEimClosure(process); + } + catch ( + IOException + | InterruptedException e) + { + Logger.log(e); + } + } + else + { + Process process; + try + { + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, filePath); + process = eimLoader.launchEim(filePath); + waitForEimClosure(process); + } + catch (IOException | InterruptedException e) + { + Logger.log(e); + } + } + + if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) + { + Logger.log("Old configuration found and not converted"); + EimJsonWatchService.withPausedListeners(()-> handleOldConfigExport()); + } + }); + } + + @Override + public void onError(String message, Exception e) + { + Display.getDefault().asyncExec(() -> { + try + { + errorConsoleStream.write("Download Failed: " + e.getMessage()); + } + catch (IOException e1) + { + Logger.log(e1); + } + }); + } + + private void waitForEimClosure(Process process) throws InterruptedException + { + Thread t = new Thread(() -> { + try + { + process.waitFor(); + Display.getDefault().asyncExec(() -> { + try + { + standardConsoleStream.write("EIM has been closed.\n"); + } + catch (IOException e) + { + Logger.log(e); + } + }); + } + catch (Exception ex) + { + Logger.log(ex); + } + }); + + t.start(); + t.join(); + } + } } 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 8895e52ac..0ae883786 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 @@ -40,6 +40,7 @@ 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.util.ToolsUtility; import com.espressif.idf.core.tools.vo.EimJson; import com.espressif.idf.core.tools.vo.IdfInstalled; @@ -71,6 +72,7 @@ public class ESPIDFMainTablePage 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$ @@ -80,6 +82,8 @@ public class ESPIDFMainTablePage private ESPIDFMainTablePage() { eimIdfConfiguratinParser = new EimIdfConfiguratinParser(); + toolInitializer = new ToolInitializer(org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE + .getNode(UIPlugin.PLUGIN_ID)); } public static ESPIDFMainTablePage getInstance(EimJson eimJson) @@ -123,7 +127,7 @@ private void createButtonAndGuideLink(Composite composite) }); eimLaunchBtn = new Button(composite, SWT.PUSH); - eimLaunchBtn.setText(eimJson.getIdfInstalled().isEmpty() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); + eimLaunchBtn.setText(!toolInitializer.isEimInstalled() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); eimLaunchBtn.addSelectionListener(new EimButtonLaunchListener(espidfMainTablePage, Display.getDefault(), getConsoleStream(false), getConsoleStream(true))); } @@ -190,7 +194,7 @@ public void refreshEditorUI() tableViewer.setInput(idfInstalledList); tableViewer.getControl().requestLayout(); tableViewer.refresh(); - eimLaunchBtn.setText(eimJson.getIdfSelectedId().isEmpty() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); + eimLaunchBtn.setText(!toolInitializer.isEimInstalled() ? Messages.EIMButtonDownloadText : Messages.EIMButtonLaunchText); container.redraw(); } From 6de150a888cf0781fb7e0cb281a0993b5fcbd0b7 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:57:06 +0200 Subject: [PATCH 07/22] tools refreshed and installed after the download and launch of eim --- .../src/com/espressif/idf/ui/tools/EimButtonLaunchListener.java | 1 + 1 file changed, 1 insertion(+) 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 index cb1e82ddb..5a5acdea3 100644 --- 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 @@ -134,6 +134,7 @@ private void refreshAfterEimClose() launchEspIdfManager(); standardConsoleStream.write("Refreshing UI after EIM closed...\n"); espidfMainTablePage.refreshEditorUI(); + espidfMainTablePage.setupInitialEspIdf(); } catch (IOException | PartInitException e) { From 2fb38b22ebf5f54ffdb54d152ac95c2576d4e12f Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:15:45 +0200 Subject: [PATCH 08/22] eim path updated for download and launch --- .../com/espressif/idf/core/tools/EimConstants.java | 5 +++++ .../src/com/espressif/idf/core/tools/EimLoader.java | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) 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 index 1a43560ef..781717ab5 100644 --- 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 @@ -1,5 +1,7 @@ package com.espressif.idf.core.tools; +import java.nio.file.Paths; + public interface EimConstants { String EIM_JSON = "eim_idf.json"; //$NON-NLS-1$ @@ -19,4 +21,7 @@ public interface EimConstants 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$ + } 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 index 899e54403..088aedac3 100644 --- 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 @@ -207,13 +207,20 @@ public void downloadEim(IProgressMonitor monitor) 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, DOWNLOAD_DIR.resolve("unzipped")); //$NON-NLS-1$ + Path extracted = unzip(downloadPath, eimPath); listener.onCompleted(extracted.toAbsolutePath().toString()); } - else + else if (name.endsWith(".exe")) //$NON-NLS-1$ + { + Files.copy(downloadPath, eimPath, StandardCopyOption.REPLACE_EXISTING); + listener.onCompleted(eimPath.toString()); + } + else { listener.onCompleted(downloadPath.toAbsolutePath().toString()); } From 7926dcdb0044d50db2bdff09d7eca1457caa1790 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Sat, 21 Jun 2025 00:43:28 +0200 Subject: [PATCH 09/22] fixing process on windows Windows had weird issue with waiting for ui process causing it to get stuck so needed to find a workaround to handle this --- .../idf/core/tools/EimConstants.java | 4 +- .../espressif/idf/core/tools/EimLoader.java | 175 +++++++++++++++++- .../tools/watcher/EimJsonWatchService.java | 4 +- .../idf/ui/tools/EimButtonLaunchListener.java | 112 ++++------- .../idf/ui/tools/EspressifToolStartup.java | 91 +++------ 5 files changed, 236 insertions(+), 150 deletions(-) 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 index 781717ab5..e1c1aeffd 100644 --- 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 @@ -8,7 +8,9 @@ public interface EimConstants String EIM_POSIX_DIR = System.getProperty("user.home").concat("/.espressif/tools/"); //$NON-NLS-1$//$NON-NLS-2$ - String EIM_WIN_DIR = "C:\\Espressif\\tools\\"; //$NON-NLS-1$ + String EIM_WIN_ESPRESSIF_DIR = "C:\\Espressif"; //$NON-NLS-1$ + + String EIM_WIN_DIR = EIM_WIN_ESPRESSIF_DIR + "\\tools\\"; //$NON-NLS-1$ String EIM_WIN_PATH = EIM_WIN_DIR + EIM_JSON; 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 index 088aedac3..6c1aed1e0 100644 --- 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 @@ -24,12 +24,18 @@ 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; @@ -52,6 +58,7 @@ public class EimLoader private MessageConsoleStream standardConsoleStream; private MessageConsoleStream errorConsoleStream; private Display display; + private long windowsPid; public EimLoader(DownloadListener listener, MessageConsoleStream standardConsoleStream, MessageConsoleStream errorConsoleStream, Display display) { @@ -106,7 +113,13 @@ public Process launchEim(String eimPath) throws IOException if (os.equals(Platform.OS_WIN32)) { - command = List.of("cmd.exe", "/c", eimPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$ + String powershellCmd = String.format( + "Start-Process -FilePath \"%s\" -PassThru | Select-Object -ExpandProperty Id", //$NON-NLS-1$ + eimPath.toString() + ); + command = List.of("powershell.exe", //$NON-NLS-1$ + "-Command", //$NON-NLS-1$ + powershellCmd); } else if (os.equals(Platform.OS_MACOSX)) { @@ -120,15 +133,48 @@ else if (os.equals(Platform.OS_LINUX)) { 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; } - public Process installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException + 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$ ProcessBuilder mountBuilder = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$ @@ -175,11 +221,9 @@ public Process installAndLaunchDmg(Path dmgPath) throws IOException, Interrupted logMessage("Unmounting DMG...\n"); //$NON-NLS-1$ new ProcessBuilder("hdiutil", "detach", volumePath).start().waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ - logMessage("Launching app from /Applications...\n"); //$NON-NLS-1$ - - Process openProcess = new ProcessBuilder("open", "-W", "-a", targetAppPath.toString()).start(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, targetAppPath.toString().concat("/Contents/MacOS/eim")); //$NON-NLS-1$ - return openProcess; + String eimPath = targetAppPath.toString().concat("/Contents/MacOS/eim"); //$NON-NLS-1$ + new IDFEnvironmentVariables().addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimPath); + return eimPath; } @@ -217,6 +261,7 @@ public void downloadEim(IProgressMonitor monitor) } else if (name.endsWith(".exe")) //$NON-NLS-1$ { + eimPath = Paths.get(eimPath.toString().concat("\\").concat(name)); //$NON-NLS-1$ Files.copy(downloadPath, eimPath, StandardCopyOption.REPLACE_EXISTING); listener.onCompleted(eimPath.toString()); } @@ -234,6 +279,120 @@ else if (name.endsWith(".exe")) //$NON-NLS-1$ } } + + 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 + { + while (process.isAlive()) + { + Thread.sleep(1000); + } + 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 { 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 index b735b528b..7fbe30059 100644 --- 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 @@ -101,13 +101,13 @@ public static void withPausedListeners(Runnable task) } } - private void pauseListeners() + public void pauseListeners() { Logger.log("Listeners are paused"); //$NON-NLS-1$ paused = true; } - private void unpauseListeners() + public void unpauseListeners() { Logger.log("Listeners are resumed"); //$NON-NLS-1$ paused = false; 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 index 5a5acdea3..22201670b 100644 --- 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 @@ -27,7 +27,6 @@ import com.espressif.idf.core.tools.EimLoader; import com.espressif.idf.core.tools.ToolInitializer; import com.espressif.idf.core.tools.vo.EimJson; -import com.espressif.idf.core.tools.watcher.EimJsonWatchService; import com.espressif.idf.ui.UIPlugin; import com.espressif.idf.ui.handlers.EclipseHandler; import com.espressif.idf.ui.tools.manager.ESPIDFManagerEditor; @@ -84,46 +83,16 @@ protected IStatus run(IProgressMonitor monitor) } else { - EimJsonWatchService.withPausedListeners(() -> { - try - { - Process process = eimLoader.launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); - waitForEimClosure(process); - } - catch (IOException | InterruptedException e) - { - Logger.log(e); - } - }); - } - } - - private void waitForEimClosure(Process process) throws InterruptedException - { - Thread t = new Thread(() -> { try { - process.waitFor(); - display.asyncExec(() -> { - try - { - standardConsoleStream.write("EIM has been closed.\n"); - } - catch (IOException e) - { - Logger.log(e); - } - refreshAfterEimClose(); - }); + Process process = eimLoader.launchEim(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); + eimLoader.waitForEimClosure(process, EimButtonLaunchListener.this::refreshAfterEimClose); } - catch (Exception ex) + catch (IOException e) { - Logger.log(ex); + Logger.log(e); } - }); - - t.start(); - t.join(); + } } private void refreshAfterEimClose() @@ -191,49 +160,44 @@ public void onProgress(int percent) @Override public void onCompleted(String filePath) { - EimJsonWatchService.withPausedListeners(() -> { - display.syncExec(() -> { - try - { - standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); - } - catch (IOException e) - { - Logger.log(e); - } - }); - - if (filePath.endsWith(".dmg")) + display.syncExec(() -> { + try { - try - { - Process process = eimLoader.installAndLaunchDmg(Paths.get(filePath)); - waitForEimClosure(process); - } - catch ( - IOException - | InterruptedException e) - { - Logger.log(e); - } + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); } - else + catch (IOException e) { - Process process; - try - { - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, filePath); - process = eimLoader.launchEim(filePath); - waitForEimClosure(process); - } - catch (IOException | InterruptedException e) - { - Logger.log(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 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 index 5a43608f5..f9b35bf86 100644 --- 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 @@ -285,51 +285,39 @@ public void onProgress(int percent) @Override public void onCompleted(String filePath) { - EimJsonWatchService.withPausedListeners(() -> { - Display.getDefault().syncExec(() -> { - try - { - standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); - } - catch (IOException e) - { - Logger.log(e); - } - }); - - if (filePath.endsWith(".dmg")) + Display.getDefault().syncExec(() -> { + try { - try - { - Process process = eimLoader.installAndLaunchDmg(Paths.get(filePath)); - waitForEimClosure(process); - } - catch ( - IOException - | InterruptedException e) - { - Logger.log(e); - } + standardConsoleStream.write("\nEIM Downloaded to: " + filePath + "\nLaunching...\n"); } - else + catch (IOException e) { - Process process; - try - { - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, filePath); - process = eimLoader.launchEim(filePath); - waitForEimClosure(process); - } - catch (IOException | InterruptedException e) - { - Logger.log(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"); - EimJsonWatchService.withPausedListeners(()-> handleOldConfigExport()); + handleOldConfigExport(); } }); } @@ -348,32 +336,5 @@ public void onError(String message, Exception e) } }); } - - private void waitForEimClosure(Process process) throws InterruptedException - { - Thread t = new Thread(() -> { - try - { - process.waitFor(); - Display.getDefault().asyncExec(() -> { - try - { - standardConsoleStream.write("EIM has been closed.\n"); - } - catch (IOException e) - { - Logger.log(e); - } - }); - } - catch (Exception ex) - { - Logger.log(ex); - } - }); - - t.start(); - t.join(); - } } } From 08fb317826ced220b146e8f24762ff77e1d1baf9 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Sat, 21 Jun 2025 01:16:43 +0200 Subject: [PATCH 10/22] fix for macos process wait --- .../espressif/idf/core/tools/EimLoader.java | 7 ++--- .../idf/ui/tools/EspressifToolStartup.java | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) 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 index 6c1aed1e0..bfcd65ed2 100644 --- 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 @@ -123,7 +123,7 @@ public Process launchEim(String eimPath) throws IOException } else if (os.equals(Platform.OS_MACOSX)) { - command = List.of("open", "-a", eimPath.toString()); //$NON-NLS-1$//$NON-NLS-2$ + command = List.of("open", "-W", "-a", eimPath.toString()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ } else if (os.equals(Platform.OS_LINUX)) { @@ -330,10 +330,7 @@ private IStatus waitForProcess(Process process) { try { - while (process.isAlive()) - { - Thread.sleep(1000); - } + process.waitFor(); return Status.OK_STATUS; } catch (InterruptedException e) 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 index f9b35bf86..3e849a710 100644 --- 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 @@ -247,18 +247,20 @@ private void promptUserToOpenToolManager(EimJson eimJson) private void openEspIdfManager(EimJson eimJson) { - IWorkbenchWindow window = EclipseHandler.getActiveWorkbenchWindow(); - IDFUtil.closeWelcomePage(window); - try - { - EimEditorInput input = new EimEditorInput(eimJson); - input.setFirstStartup(true); - IDE.openEditor(window.getActivePage(), input, ESPIDFManagerEditor.EDITOR_ID); - } - catch (PartInitException e) - { - Logger.log(e); - } + 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 @@ -319,6 +321,8 @@ public void onCompleted(String filePath) Logger.log("Old configuration found and not converted"); handleOldConfigExport(); } + eimJson = toolInitializer.loadEimJson(); + openEspIdfManager(eimJson); }); } From ff5e74d8ca3c5252bcac2341c2a7e5db7fc2f2bc Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:25:14 +0200 Subject: [PATCH 11/22] removed update master command --- bundles/com.espressif.idf.ui/plugin.xml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/bundles/com.espressif.idf.ui/plugin.xml b/bundles/com.espressif.idf.ui/plugin.xml index 5365f564c..f0e744069 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"> - - - - - - @@ -412,11 +401,6 @@ id="com.espressif.idf.ui.command.eclipeguide" name="%command.name.9"> - - Date: Mon, 23 Jun 2025 14:29:11 +0200 Subject: [PATCH 12/22] watchservice npe fix for no directories present --- .../idf/core/tools/watcher/EimJsonWatchService.java | 5 +++++ 1 file changed, 5 insertions(+) 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 index 7fbe30059..38cdc1029 100644 --- 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 @@ -6,6 +6,7 @@ import java.io.IOException; import java.nio.file.*; +import java.nio.file.attribute.FileAttribute; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -35,6 +36,10 @@ private EimJsonWatchService() throws IOException : 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); From c2c280ab9d47e49f15782d55b40b2642ff4e5d72 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 24 Jun 2025 11:43:48 +0200 Subject: [PATCH 13/22] manager ui refreshed --- .../espressif/idf/ui/tools/watcher/EimJsonUiChangeHandler.java | 1 + 1 file changed, 1 insertion(+) 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 index 71418f391..779486917 100644 --- 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 @@ -93,6 +93,7 @@ public void handleUserResponse(int response) { // multiple entries in json so launch manager for user to handle this launchEspIdfManager(); + ESPIDFMainTablePage.getInstance(eimJson).refreshEditorUI(); } } catch ( From adf5b29be21e8aa150dddaff93677f2675d7228b Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:02:46 +0200 Subject: [PATCH 14/22] review comments handled --- .../idf/core/build/messages.properties | 2 +- .../idf/core/tools/EimConstants.java | 7 +- .../espressif/idf/core/tools/EimLoader.java | 120 ++++++++++++------ 3 files changed, 87 insertions(+), 42 deletions(-) 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 a872093ec..00146e66e 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 @@ -20,7 +20,7 @@ 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. To proceed, you can download and launch the EIM - GUI Installer directly from this IDE.\n\nWould you like to download and start the EIM installer now?\n\nOnce installation is complete, the IDE will automatically detect ESP-IDF. You can also verify and activate it later from the ESP-IDF Manager (Espressif > ESP-IDF Manager). +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=Yes ToolsInitializationDifferentPathMessageBoxOptionNo=No 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 index e1c1aeffd..984e9ebbe 100644 --- 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 @@ -1,16 +1,17 @@ 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("/.espressif/tools/"); //$NON-NLS-1$//$NON-NLS-2$ + 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:\\Espressif"; //$NON-NLS-1$ + String EIM_WIN_ESPRESSIF_DIR = "C:" + File.separator + "Espressif"; //$NON-NLS-1$ //$NON-NLS-2$ - String EIM_WIN_DIR = EIM_WIN_ESPRESSIF_DIR + "\\tools\\"; //$NON-NLS-1$ + 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; 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 index bfcd65ed2..3248f5658 100644 --- 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 @@ -115,7 +115,7 @@ public Process launchEim(String eimPath) throws IOException { String powershellCmd = String.format( "Start-Process -FilePath \"%s\" -PassThru | Select-Object -ExpandProperty Id", //$NON-NLS-1$ - eimPath.toString() + eimPath ); command = List.of("powershell.exe", //$NON-NLS-1$ "-Command", //$NON-NLS-1$ @@ -123,11 +123,11 @@ public Process launchEim(String eimPath) throws IOException } else if (os.equals(Platform.OS_MACOSX)) { - command = List.of("open", "-W", "-a", eimPath.toString()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + 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.toString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + command = List.of("bash", "-c", "\"" + eimPath + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } else { @@ -176,33 +176,18 @@ private void storePid(Process powershellProcess) public String installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedException { - logMessage("Mounting DMG...\n"); //$NON-NLS-1$ - ProcessBuilder mountBuilder = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$ - Process mountProcess = mountBuilder.start(); + logMessage("Mounting DMG…\n"); //$NON-NLS-1$ + Process mountProcess = new ProcessBuilder("hdiutil", "attach", dmgPath.toString()) //$NON-NLS-1$ //$NON-NLS-2$ + .redirectErrorStream(true).start(); - String volumePath = null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()))) - { - String line; - while ((line = reader.readLine()) != null) - { - if (line.contains("/Volumes/")) //$NON-NLS-1$ - { - String[] parts = line.split("\t"); //$NON-NLS-1$ - for (String part : parts) - { - if (part.startsWith("/Volumes/")) //$NON-NLS-1$ - { - volumePath = part.trim(); - break; - } - } - } - } - } + 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$ + 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) @@ -211,27 +196,62 @@ public String installAndLaunchDmg(Path dmgPath) throws IOException, InterruptedE File appBundle = apps[0]; Path targetAppPath = Paths.get("/Applications", appBundle.getName()); //$NON-NLS-1$ - logMessage("Copying app to /Applications...\n"); //$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)); - // Copy to /Applications - ProcessBuilder copyBuilder = new ProcessBuilder("cp", "-R", appBundle.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$ - targetAppPath.toString()); - copyBuilder.inheritIO().start().waitFor(); + logMessage("Unmounting DMG…\n"); //$NON-NLS-1$ + Process detachProcess = new ProcessBuilder("hdiutil", "detach", volumePath) //$NON-NLS-1$ //$NON-NLS-2$ + .redirectErrorStream(true).start(); - logMessage("Unmounting DMG...\n"); //$NON-NLS-1$ - new ProcessBuilder("hdiutil", "detach", volumePath).start().waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ + 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.toString().concat("/Contents/MacOS/eim"); //$NON-NLS-1$ + 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 { - monitor.beginTask("Downloading EIM GUI...", IProgressMonitor.UNKNOWN); //$NON-NLS-1$ JsonObject root = fetchJson(); JsonArray assets = root.getAsJsonArray("assets"); //$NON-NLS-1$ Optional match = findMatchingAsset(assets); @@ -248,6 +268,7 @@ public void downloadEim(IProgressMonitor monitor) 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); @@ -261,7 +282,7 @@ public void downloadEim(IProgressMonitor monitor) } else if (name.endsWith(".exe")) //$NON-NLS-1$ { - eimPath = Paths.get(eimPath.toString().concat("\\").concat(name)); //$NON-NLS-1$ + eimPath = Paths.get(eimPath.toString(), name); Files.copy(downloadPath, eimPath, StandardCopyOption.REPLACE_EXISTING); listener.onCompleted(eimPath.toString()); } @@ -270,7 +291,7 @@ else if (name.endsWith(".exe")) //$NON-NLS-1$ listener.onCompleted(downloadPath.toAbsolutePath().toString()); } } - catch (Exception e) + catch (IOException e) { listener.onError("Download failed", e); //$NON-NLS-1$ } finally @@ -405,6 +426,29 @@ private JsonObject fetchJson() throws IOException } } + 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) From 05ec02b64c618e8c2ac5a5cb1fb12db24bd30075 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:54:26 +0200 Subject: [PATCH 15/22] updated system_path handling with EIM --- .../idf/core/IDFEnvironmentVariables.java | 2 ++ .../idf/core/tools/SetupToolsInIde.java | 33 +++++++------------ .../idf/ui/tools/messages.properties | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) 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 ab53817bc..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 @@ -54,6 +54,8 @@ public class IDFEnvironmentVariables 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 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 index 1adfc9621..e6a871389 100644 --- 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 @@ -223,29 +223,16 @@ public void run() private String replacePathVariable(String value) { - // Get system PATH - Map systemEnv = new HashMap<>(System.getenv()); - 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.concat(File.pathSeparator).concat(pathEntry); - } + // 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(); - if (Platform.getOS().equals(Platform.OS_MACOSX)) - { - value = value.concat(File.pathSeparator).concat("/opt/homebrew/bin").concat(File.pathSeparator).concat("/usr/local/bin"); //$NON-NLS-1$ //$NON-NLS-2$ - } + 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 value; + return path; } private IStatus loadTargetsAvailableFromIdfInCurrentToolSet(boolean rollback) @@ -390,7 +377,7 @@ private void setupEnvVarsInEclipse() idfEnvironmentVariables.addEnvVariable(entry.getKey(), entry.getValue()); } - String path = replacePathVariable(envVarsFromActivationScriptMap.get(IDFEnvironmentVariables.PATH)); + String path = getUpdatedPathWithSystemPath(); idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PATH, path); idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.IDF_COMPONENT_MANAGER, "1"); //$NON-NLS-1$ @@ -400,6 +387,8 @@ private void setupEnvVarsInEclipse() idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.PYTHON_EXE_PATH, idfInstalled.getPython()); + + IDFUtil.updateEspressifPrefPageOpenocdPath(); } 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 1b6344e74..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 @@ -6,7 +6,7 @@ EspIdfManagerNameCol=Name EspIdfManagerReloadBtnToolTip=Reload from disk 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 & Launch EIM +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? From ebeca6961fd4aec11be1da2bd3fcf053f32dc987 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:45:18 +0200 Subject: [PATCH 16/22] eim message if not in applicaitons on macos --- .../espressif/idf/core/build/Messages.java | 3 ++ .../idf/core/build/messages.properties | 3 ++ .../idf/ui/tools/EspressifToolStartup.java | 40 +++++++++++++++++++ 3 files changed, 46 insertions(+) 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 aa552a03d..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 @@ -50,6 +50,9 @@ public class Messages extends NLS 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 00146e66e..7e31a1293 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 @@ -31,6 +31,9 @@ IDFToolChainsMissingErrorMsg=Toolchains are missing. Please use ESP-IDF Manager NoActiveEspIdfInWorkspaceMsgTitle=ESP-IDF Setup NoActiveEspIdfInWorkspaceMsg=ESP-IDF is required to use Espressif IDE. Would you like to configure it 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 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 index 3e849a710..6528d79fe 100644 --- 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 @@ -5,10 +5,12 @@ package com.espressif.idf.ui.tools; import java.io.IOException; +import java.nio.file.Files; 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; @@ -88,6 +90,12 @@ public void earlyStartup() if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) { Logger.log("Old configuration found and not converted"); + boolean isEimInApplications = checkIfEimPathMacOsIsInApplications(); + if (!isEimInApplications) + { + promptUserToMoveEimToApplications(); + } + EimJsonWatchService.withPausedListeners(()-> handleOldConfigExport()); } else if (toolInitializer.isEimIdfJsonPresent() && !toolInitializer.isEspIdfSet()) @@ -105,6 +113,29 @@ else if (toolInitializer.isEimIdfJsonPresent() && !toolInitializer.isEspIdfSet() } } + 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() { final int[] response = new int[] { -1 }; @@ -244,6 +275,15 @@ private void promptUserToOpenToolManager(EimJson eimJson) } }); } + + private void promptUserToMoveEimToApplications() + { + Display.getDefault().asyncExec(() -> { + MessageDialog.openInformation( + Display.getDefault().getActiveShell(), + Messages.EIMNotInApplicationsTitle, Messages.EIMNotInApplicationsMessage); + }); + } private void openEspIdfManager(EimJson eimJson) { From 54ba2f79a0c024a5840d4fe67eee2cab1c77ce9e Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:05:47 +0200 Subject: [PATCH 17/22] rebase fix --- .../src/com/espressif/idf/core/tools/SetupToolsInIde.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index e6a871389..a4b603a7d 100644 --- 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 @@ -221,7 +221,7 @@ public void run() } } - private String replacePathVariable(String value) + 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(); From 219ea0b258a03d1a9ae2092691ed0160c17e518e Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:14:08 +0200 Subject: [PATCH 18/22] eim powershell space error fixed --- .../src/com/espressif/idf/core/tools/EimLoader.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) 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 index 3248f5658..4db1005c2 100644 --- 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 @@ -113,13 +113,14 @@ public Process launchEim(String eimPath) throws IOException if (os.equals(Platform.OS_WIN32)) { - String powershellCmd = String.format( - "Start-Process -FilePath \"%s\" -PassThru | Select-Object -ExpandProperty Id", //$NON-NLS-1$ - eimPath - ); + 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", //$NON-NLS-1$ - powershellCmd); + "-Command", powershellCmd); //$NON-NLS-1$ } else if (os.equals(Platform.OS_MACOSX)) { From b6a73a179c1126763a955f9cbcc2110abb97b83d Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:15:24 +0200 Subject: [PATCH 19/22] Display thread invalid access fixed --- .../ui/tools/watcher/EimJsonUiChangeHandler.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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 index 779486917..4517e2a0f 100644 --- 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 @@ -92,13 +92,21 @@ public void handleUserResponse(int response) else { // multiple entries in json so launch manager for user to handle this - launchEspIdfManager(); - ESPIDFMainTablePage.getInstance(eimJson).refreshEditorUI(); + Display.getDefault().asyncExec(() -> { + try + { + launchEspIdfManager(); + } + catch (PartInitException e) + { + Logger.log(e); + } + ESPIDFMainTablePage.getInstance(eimJson).refreshEditorUI(); + }); } } catch ( - IOException - | PartInitException e) + IOException e) { Logger.log(e); } From 1826069735cd0482e153092ca13cfb77ca80ce80 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:17:28 +0200 Subject: [PATCH 20/22] code flow handling and logigng added --- .../src/com/espressif/idf/core/tools/ToolInitializer.java | 1 + .../com/espressif/idf/ui/tools/EspressifToolStartup.java | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) 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 index c84806404..daa001d5a 100644 --- 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 @@ -85,6 +85,7 @@ public IStatus exportOldConfig() throws IOException commands.add(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); 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()); 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 index 6528d79fe..94d284c0b 100644 --- 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 @@ -86,6 +86,8 @@ public void earlyStartup() notifyMissingTools(); return; } + + eimJson = toolInitializer.loadEimJson(); if (toolInitializer.isOldEspIdfConfigPresent() && !toolInitializer.isOldConfigExported()) { @@ -100,12 +102,14 @@ public void earlyStartup() } else if (toolInitializer.isEimIdfJsonPresent() && !toolInitializer.isEspIdfSet()) { - eimJson = toolInitializer.loadEimJson(); promptUserToOpenToolManager(eimJson); } // Set EimPath on every startup to ensure proper path in configurations - idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); + if (eimJson != null) + { + idfEnvironmentVariables.addEnvVariable(IDFEnvironmentVariables.EIM_PATH, eimJson.getEimPath()); + } if (stateChecker.wasModifiedSinceLastRun()) { From 5f4fa52b4d594854355da8c1ece9aae90b7eb5ea Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:19:06 +0200 Subject: [PATCH 21/22] eimPath for export configurations added --- .../src/com/espressif/idf/core/tools/ToolInitializer.java | 5 +++-- .../src/com/espressif/idf/ui/tools/EspressifToolStartup.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) 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 index daa001d5a..7b7e514f8 100644 --- 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 @@ -75,14 +75,15 @@ public boolean isOldEspIdfConfigPresent() return getOldConfigFile().exists(); } - public IStatus exportOldConfig() throws IOException + public IStatus exportOldConfig(String eimPath) throws IOException { File oldConfig = getOldConfigFile(); if (oldConfig.exists()) { // eim import pathToOldConfigJson List commands = new ArrayList<>(); - commands.add(idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH)); + commands.add(StringUtil.isEmpty(eimPath) ? + idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.EIM_PATH) : eimPath); commands.add("import"); //$NON-NLS-1$ commands.add(oldConfig.getAbsolutePath()); Logger.log("Running: " + commands.toString()); //$NON-NLS-1$ 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 index 94d284c0b..84d1fd6a0 100644 --- 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 @@ -156,7 +156,7 @@ private void handleOldConfigExport() { try { - IStatus status = toolInitializer.exportOldConfig(); + IStatus status = toolInitializer.exportOldConfig(eimJson != null ? eimJson.getEimPath() : StringUtil.EMPTY); Logger.log("Tools Conversion Process Message: "); Logger.log(status.getMessage()); if (status.getSeverity() != IStatus.ERROR) From af74e4f50c985fdb93dbe75667c8642ef85d3d6f Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:56:00 +0200 Subject: [PATCH 22/22] fix for master version for size analysis --- .../src/com/espressif/idf/ui/size/IDFSizeAnalysisEditor.java | 5 +++++ .../src/com/espressif/idf/ui/size/IDFSizeDataManager.java | 5 +++++ 2 files changed, 10 insertions(+) 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 a12e6d089..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 @@ -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;