diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultSystemWrapper.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultSystemWrapper.java index 9a4967b41..1238bec58 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultSystemWrapper.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/DefaultSystemWrapper.java @@ -6,9 +6,6 @@ public class DefaultSystemWrapper implements SystemWrapper { - private static final String PATH = "PATH"; //$NON-NLS-1$ - private static final String PATHEXT = "PATHEXT"; //$NON-NLS-1$ - @Override public String getPathEnv() { diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemWrapper.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemWrapper.java index 97007f06d..d545a24e4 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemWrapper.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemWrapper.java @@ -6,6 +6,9 @@ public interface SystemWrapper { + String PATH = "PATH"; //$NON-NLS-1$ + String PATHEXT = "PATHEXT"; //$NON-NLS-1$ + public String getPathEnv(); public String getEnvExecutables(); } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java new file mode 100644 index 000000000..5ac2d9356 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/ToolsSystemWrapper.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools; + +import com.espressif.idf.core.SystemWrapper; + +/** + * Tools System wrapper to make sure to avoid the + * system path when verifying for validation after tools installation + * @author Ali Azam Rana + * + */ +public class ToolsSystemWrapper implements SystemWrapper +{ + private String path; + + public ToolsSystemWrapper(String path) + { + this.path = path; + } + + @Override + public String getPathEnv() + { + return path; + } + + @Override + public String getEnvExecutables() + { + return System.getenv(PATHEXT); + } + +} diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java index f8876b2ba..6c4479a43 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java @@ -27,13 +27,17 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.utils.IOUtils; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.tukaani.xz.XZInputStream; import com.espressif.idf.core.IDFEnvironmentVariables; +import com.espressif.idf.core.SystemExecutableFinder; import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.tools.ToolsSystemWrapper; import com.espressif.idf.core.tools.vo.ToolsVO; import com.espressif.idf.core.util.FileUtil; +import com.espressif.idf.core.util.StringUtil; /** * Utility class for Tools Management operations @@ -303,4 +307,25 @@ public static String getFileChecksum(MessageDigest digest, File file) throws IOE } return sb.toString(); } + + /** + * Gets the absolute path for the tool from the given path + * @param toolName tool to find absolute path + * @param path the path to variable to look into, if null System.getenv() will be used + * @return absolute path to the tool + */ + public static IPath findAbsoluteToolPath(String toolName, String path) + { + if (StringUtil.isEmpty(path)) + { + Map env = System.getenv(); + if (env.containsKey(IDFEnvironmentVariables.PATH)) + path = env.get(IDFEnvironmentVariables.PATH); + else + path = env.get("Path"); //$NON-NLS-1$ + } + + SystemExecutableFinder systemExecutableFinder = new SystemExecutableFinder(new ToolsSystemWrapper(path)); + return systemExecutableFinder.find(toolName); + } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java index 563231f40..92ab5bf9e 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/ToolsVO.java @@ -7,6 +7,7 @@ import java.text.DecimalFormat; import java.util.List; import java.util.Map; +import java.util.Objects; import org.eclipse.core.runtime.Platform; @@ -226,4 +227,33 @@ public void setVersionRegex(String versionRegex) { this.versionRegex = versionRegex; } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + ToolsVO other = (ToolsVO) obj; + return Objects.equals(description, other.description) + && Objects.equals(exportPaths, other.exportPaths) + && Objects.equals(exportVars, other.exportVars) + && Objects.equals(infoUrl, other.infoUrl) + && Objects.equals(installType, other.installType) + && Objects.equals(licesnse, other.licesnse) + && Objects.equals(name, other.name) + && Objects.equals(supportedTargets, other.supportedTargets) + && Objects.equals(versionCmd, other.versionCmd) + && Objects.equals(versionRegex, other.versionRegex) + && Objects.equals(versionVOs, other.versionVOs) + && Objects.equals(version, other.version) + && installed == other.installed; + } + + @Override + public int hashCode() + { + return Objects.hash(description, exportPaths, exportVars, infoUrl, installType, licesnse, name, supportedTargets, versionCmd, versionRegex, versionVOs, version, installed); + } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java index 340c71d6b..a9a2122b0 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionDetailsVO.java @@ -5,6 +5,7 @@ package com.espressif.idf.core.tools.vo; import java.text.DecimalFormat; +import java.util.Objects; /** * Version details vo for the versions class @@ -70,4 +71,24 @@ public void setSelected(boolean selected) { this.selected = selected; } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + VersionDetailsVO other = (VersionDetailsVO) obj; + return Double.compare(size, other.size) == 0 + && selected == other.selected + && Objects.equals(sha256, other.sha256) + && Objects.equals(url, other.url); + } + + @Override + public int hashCode() + { + return Objects.hash(sha256, size, url, selected); + } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java index 2441f8a7f..ac871a78a 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/vo/VersionsVO.java @@ -5,6 +5,7 @@ package com.espressif.idf.core.tools.vo; import java.util.Map; +import java.util.Objects; /** * Versions class for versions information in tools json @@ -73,4 +74,25 @@ public void setAvailablePath(String availablePath) { this.availablePath = availablePath; } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + VersionsVO other = (VersionsVO) obj; + return isAvailable == other.isAvailable + && Objects.equals(name, other.name) + && Objects.equals(status, other.status) + && Objects.equals(versionOsMap, other.versionOsMap) + && Objects.equals(availablePath, other.availablePath); + } + + @Override + public int hashCode() + { + return Objects.hash(name, status, versionOsMap, isAvailable, availablePath); + } } diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/URLDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/URLDialog.java new file mode 100644 index 000000000..fd9e2aa3b --- /dev/null +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/URLDialog.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright 2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.ui.dialogs; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.program.Program; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; + +import com.espressif.idf.core.logging.Logger; + +/** + * URL Dialog class that can show multiple external web URLs in the text and + * make them click able and launches the default program to open them + * @author Ali Azam Rana + * + */ +public class URLDialog extends Dialog +{ + private static final String URL_REGEX = "\\b((http|https)://)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"; //$NON-NLS-1$ + + private String text; + private String title; + + public URLDialog(Shell parentShell, String title, String text) + { + super(parentShell); + this.text = text; + this.title = title; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite container = new Composite((Composite) super.createDialogArea(parent), SWT.NONE); + container.setLayout(new GridLayout()); + Link link = new Link(container, SWT.NONE); + link.setText(getTextForLinkControl()); + link.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true)); + link.addListener(SWT.Selection, e -> Program.launch(e.text)); + return container; + } + + @Override + protected void configureShell(Shell newShell) + { + super.configureShell(newShell); + newShell.setText(title); + } + + private String getTextForLinkControl() + { + StringBuilder stringBuilder = new StringBuilder(); + Pattern pattern = Pattern.compile(URL_REGEX); + Matcher matcher = pattern.matcher(text); + int startIndex = 0, endIndex = text.length(); + while (matcher.find()) + { + String url = matcher.group(); + Logger.log("URL Found: " + url); + endIndex = text.indexOf(url); + stringBuilder.append(text.substring(startIndex, endIndex)); + stringBuilder.append(""); //$NON-NLS-1$ + stringBuilder.append(url); + stringBuilder.append(""); //$NON-NLS-1$ + startIndex = endIndex + url.length(); + endIndex = text.length(); + } + if (stringBuilder.toString().isEmpty()) + { + stringBuilder.append(text); + } + return stringBuilder.toString(); + } +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/Messages.java index 2d40dd779..a2bf5e032 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 @@ -105,6 +105,9 @@ public class Messages extends NLS public static String FilterTargetBoxToolTip; public static String ShowAvailableVersionsOnlyToolTip; public static String DeleteToolsTextToolTip; + public static String MissingToolsValidationMessage_A; + public static String MissingToolsValidationMessage_B; + public static String MissingToolsValidationLink; static { diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationHandler.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationHandler.java index 7b2f5b12f..d8141729a 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationHandler.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/ToolsInstallationHandler.java @@ -26,9 +26,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.InstanceScope; @@ -50,6 +49,7 @@ import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.StringUtil; import com.espressif.idf.ui.UIPlugin; +import com.espressif.idf.ui.dialogs.URLDialog; import com.espressif.idf.ui.tools.wizard.pages.ManageToolsInstallationWizardPage; import com.espressif.idf.ui.update.InstallToolsHandler; @@ -585,9 +585,10 @@ public Boolean call() throws Exception private void validateToolsInstall() { + List missingToolsVOs = new ArrayList<>(); for (ToolsVO toolsVO : requireToolsVOs) { - final List arguments = new ArrayList(); + final List arguments = new ArrayList(); arguments.addAll(toolsVO.getVersionCmd()); final String cmd = Messages.AbstractToolsHandler_ExecutingMsg + " " + getCommandString(arguments); logQueue.add(cmd); @@ -602,13 +603,22 @@ else if (environment.containsKey("Path")) { environment.put("Path", idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH)); } + + IPath absolutePathToTool = ToolsUtility.findAbsoluteToolPath(toolsVO.getName(), + idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.PATH)); + if (absolutePathToTool == null) + { + Logger.log("Required tool: " + toolsVO.getName() + " not found on the PATH"); + missingToolsVOs.add(toolsVO); + continue; + } + arguments.add(0, absolutePathToTool.toOSString()); + arguments.remove(1); + final ProcessBuilderFactory processRunner = new ProcessBuilderFactory(); try { - final IStatus status = processRunner.runInBackground(arguments, - org.eclipse.core.runtime.Path.fromOSString( - idfEnvironmentVariables.getEnvValue(IDFEnvironmentVariables.IDF_PATH)), - environment); + final IStatus status = processRunner.runInBackground(arguments, null, environment); if (status == null) { Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Status can't be null", null)); //$NON-NLS-1$ @@ -618,30 +628,31 @@ else if (environment.containsKey("Path")) final String cmdOutput = status.getMessage(); Logger.log(cmdOutput); logQueue.add(cmdOutput); - - Pattern pattern = Pattern.compile(toolsVO.getVersionRegex()); - Matcher matcher = pattern.matcher(cmdOutput); - if (matcher.find()) - { - String match = matcher.group(); - if (!match.equals(toolsVO.getVersion())) - { - Logger.log("Version Mismatch for " + toolsVO.getName() + " IDF required: " - + toolsVO.getVersion() + " Found: " + match); - logQueue.add("Version Mismatch for " + toolsVO.getName() + " IDF required: " - + toolsVO.getVersion() + " Found: " + match); - } - else - { - // TODO: Handle the case when the tool was not installed and is required - } - } } catch (IOException e1) { Logger.log(IDFCorePlugin.getPlugin(), e1); + missingToolsVOs.add(toolsVO); } } + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(Messages.MissingToolsValidationMessage_A); + stringBuilder.append(System.lineSeparator()); + for (ToolsVO toolsVO : missingToolsVOs) + { + stringBuilder.append(toolsVO.getName()); + stringBuilder.append(System.lineSeparator()); + } + + stringBuilder.append(Messages.MissingToolsValidationMessage_B); + stringBuilder.append(Messages.MissingToolsValidationLink); + + manageToolsInstallationWizardPage.getShell().getDisplay().asyncExec(() -> { + URLDialog urlDialog = new URLDialog(manageToolsInstallationWizardPage.getShell(), "Missing Tools", + stringBuilder.toString()); + urlDialog.open(); + }); } private void configEnv() @@ -773,16 +784,45 @@ private void replacePathVariable(StringBuilder paths) return; } - Map environment = System.getenv(); String systemPath = StringUtil.EMPTY; - if (environment.containsKey(IDFEnvironmentVariables.PATH)) + if (Platform.getOS().equals(Platform.OS_WIN32)) { - systemPath = environment.get(IDFEnvironmentVariables.PATH); + Map environment = System.getenv(); + + if (environment.containsKey(IDFEnvironmentVariables.PATH)) + { + systemPath = environment.get(IDFEnvironmentVariables.PATH); + } + else if (environment.containsKey("Path")) + { + systemPath = environment.get("Path"); + } } - else if (environment.containsKey("Path")) + else { - systemPath = environment.get("Path"); + try + { + ProcessBuilderFactory processBuilderFactory = new ProcessBuilderFactory(); + List arguments = new ArrayList<>(); + arguments.add("bash"); + arguments.add("-l"); + arguments.add("-c"); + arguments.add("echo $PATH"); + + IStatus status = processBuilderFactory.runInBackground(arguments, null, null); + if (status == null) + { + Logger.log(IDFCorePlugin.getPlugin(), IDFCorePlugin.errorStatus("Stat us can't be null", null)); //$NON-NLS-1$ + return; + } + + systemPath = status.getMessage(); + } + catch (IOException e) + { + e.printStackTrace(); + } } List pathsToAppend = new ArrayList(); 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 13273e708..bd697cd84 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 @@ -107,3 +107,6 @@ IDFDownloadWizard_DecompressingCompleted=Archive extracted! IDFDownloadWizard_UpdatingIDFPathMessage=Updating IDF_PATH to: {0} FilterTargetBoxToolTip=Filter the tools based on the target selection of ESP chips ShowAvailableVersionsOnlyToolTip=Shows the versions that are available already and downloaded. The versions should be in the espressif home directory to be visible with this. +MissingToolsValidationMessage_A=Following required tools are missing: +MissingToolsValidationMessage_B=Please visit the Link below to see configuration for these tools +MissingToolsValidationLink= diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/wizard/pages/ManageToolsInstallationWizardPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/wizard/pages/ManageToolsInstallationWizardPage.java index e2e0b9c18..194a90a30 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/wizard/pages/ManageToolsInstallationWizardPage.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/wizard/pages/ManageToolsInstallationWizardPage.java @@ -847,7 +847,6 @@ private void checkItems(TreeItem item, boolean checked) item.setChecked(checked); if (item.getParentItem() != null) { - String key = item.getText(0); VersionsVO versionsVO = (VersionsVO) item.getData(); for(String os : versionsVO.getVersionOsMap().keySet()) @@ -887,7 +886,7 @@ public void widgetSelected(SelectionEvent e) ManageToolsInstallationWizardPage.this, idfEnvironmentVariables); try { - toolsInstallationHandler.operationToPerform(selectedItems, forceDownloadBtn.getSelection(), + toolsInstallationHandler.operationToPerform(toolsJsonParser.getRequiredToolsList(), selectedItems, forceDownloadBtn.getSelection(), ToolsInstallationHandler.DELETING_TOOLS); } catch (Exception e1)