Skip to content

Commit 31b7055

Browse files
authored
IEP-1018 Automation of hints viewer (#809)
* gathering hints after build * added test coverage * optimizing pattern compilation
1 parent 9d6c775 commit 31b7055

File tree

18 files changed

+509
-78
lines changed

18 files changed

+509
-78
lines changed

bundles/com.espressif.idf.core/src/com/espressif/idf/core/IDFCorePreferenceConstants.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ public class IDFCorePreferenceConstants
2222
{
2323
// CMake CCache preferences
2424
public static final String CMAKE_CCACHE_STATUS = "cmakeCCacheStatus"; //$NON-NLS-1$
25+
public static final String AUTOMATE_BUILD_HINTS_STATUS = "automateHintsStatus"; //$NON-NLS-1$
2526
public static final boolean CMAKE_CCACHE_DEFAULT_STATUS = true;
26-
27+
public static final boolean AUTOMATE_BUILD_HINTS_DEFAULT_STATUS = true;
2728
/**
2829
* Returns the node in the preference in the given context.
2930
*
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*******************************************************************************
2+
* Copyright 2022-2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
3+
* Use is subject to license terms.
4+
*******************************************************************************/
5+
package com.espressif.idf.core.build;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
import org.eclipse.cdt.core.IConsoleParser;
11+
12+
import com.espressif.idf.core.resources.OpenDialogListenerSupport;
13+
import com.espressif.idf.core.resources.PopupDialog;
14+
import com.espressif.idf.core.util.StringUtil;
15+
16+
/**
17+
* The EspIdfErrorParser class implements the IConsoleParser interface to parse console output for ESP-IDF errors and
18+
* extract relevant hints. It processes each line of the console output and checks against a list of regular expression
19+
* patterns to identify errors and their corresponding hints.
20+
*
21+
* This class maintains a list of regular expression hint pairs (ReHintPair) that are used to match and identify errors,
22+
* and associate them with appropriate hints. It accumulates matched pairs in the 'allMatchesList' for further
23+
* processing.
24+
*
25+
* The processLine method is responsible for processing each input line by iterating through the list of regular
26+
* expression hint pairs. It uses regular expressions to determine if the line matches any error pattern. If a match is
27+
* found, the corresponding hint is associated with the error message and added to the 'allMatchesList'.
28+
*
29+
* The shutdown method is used to trigger the completion of parsing. It notifies listeners registred in the UI plugin
30+
* that the list of available hints has changed and providing the accumulated error hint pairs. The 'allMatchesList' is
31+
* then cleared to prepare for the next parsing session.
32+
*
33+
*
34+
* @author Denys Almazov (denys.almazov@espressif.com)
35+
*
36+
*/
37+
public class EspIdfErrorParser implements IConsoleParser
38+
{
39+
40+
private List<ReHintPair> reHintsList;
41+
private List<ReHintPair> allMatchesList;
42+
43+
public EspIdfErrorParser(List<ReHintPair> reHintPairs)
44+
{
45+
this.reHintsList = reHintPairs;
46+
this.allMatchesList = new ArrayList<>();
47+
}
48+
public boolean processLine(String paramString)
49+
{
50+
int initialListSize = allMatchesList.size();
51+
reHintsList.stream().filter(
52+
reHintEntry -> reHintEntry.getRe().map(pattern -> pattern.matcher(paramString).find()).orElse(false))
53+
.forEach(matchedReHintEntry -> allMatchesList
54+
.add(new ReHintPair(paramString, matchedReHintEntry.getHint())));
55+
56+
return allMatchesList.size() != initialListSize;
57+
}
58+
59+
public void shutdown()
60+
{
61+
OpenDialogListenerSupport.getSupport().firePropertyChange(PopupDialog.AVAILABLE_HINTS.name(),
62+
StringUtil.EMPTY, new ArrayList<>(allMatchesList));
63+
allMatchesList.clear();
64+
}
65+
}

bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
import com.espressif.idf.core.internal.CMakeErrorParser;
105105
import com.espressif.idf.core.logging.Logger;
106106
import com.espressif.idf.core.util.DfuCommandsUtil;
107+
import com.espressif.idf.core.util.HintsUtil;
107108
import com.espressif.idf.core.util.IDFUtil;
108109
import com.espressif.idf.core.util.ParitionSizeHandler;
109110
import com.espressif.idf.core.util.StringUtil;
@@ -418,8 +419,14 @@ private void runCmakeBuildCommand(IConsole console, IProgressMonitor monitor, IP
418419
console.getErrorStream().write(String.format(Messages.CMakeBuildConfiguration_Failure, "")); //$NON-NLS-1$
419420
throw new CmakeBuildException();
420421
}
421-
422-
watchProcess(p, new IConsoleParser[] { epm, new StatusParser() });
422+
boolean buildHintsStatus = Platform.getPreferencesService().getBoolean(IDFCorePlugin.PLUGIN_ID,
423+
IDFCorePreferenceConstants.AUTOMATE_BUILD_HINTS_STATUS,
424+
IDFCorePreferenceConstants.AUTOMATE_BUILD_HINTS_DEFAULT_STATUS, null);
425+
IConsoleParser[] consoleParsers = buildHintsStatus
426+
? new IConsoleParser[] { epm, new StatusParser(),
427+
new EspIdfErrorParser(HintsUtil.getReHintsList(new File(HintsUtil.getHintsYmlPath()))) }
428+
: new IConsoleParser[] { epm, new StatusParser() };
429+
watchProcess(p, consoleParsers);
423430

424431
final String isSkip = System.getProperty("skip.idf.components"); //$NON-NLS-1$
425432
if (!Boolean.parseBoolean(isSkip))
@@ -501,6 +508,7 @@ protected int watchProcess(Process process, IConsoleParser[] consoleParsers) thr
501508
{
502509
Thread.sleep(100);
503510
}
511+
Stream.of(consoleParsers).forEach(IConsoleParser::shutdown);
504512
return rc;
505513
}
506514
catch (InterruptedException e)

bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/ReHintPair.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,38 @@
44
*******************************************************************************/
55
package com.espressif.idf.core.build;
66

7+
import java.util.Optional;
8+
import java.util.regex.Pattern;
9+
import java.util.regex.PatternSyntaxException;
10+
11+
import com.espressif.idf.core.logging.Logger;
12+
713
/**
814
* Represents a parsed re and hint entries of a hints.yml file.
915
*
1016
* @author Denys Almazov
1117
*/
1218
public class ReHintPair
1319
{
14-
private String re;
20+
private Pattern re;
1521
private String hint;
1622

1723
public ReHintPair(String re, String hint)
1824
{
19-
this.re = re;
25+
try
26+
{
27+
this.re = Pattern.compile(re);
28+
}
29+
catch (PatternSyntaxException e)
30+
{
31+
Logger.log(e);
32+
}
2033
this.hint = hint;
2134
}
2235

23-
public String getRe()
36+
public Optional<Pattern> getRe()
2437
{
25-
return re;
38+
return Optional.ofNullable(re);
2639
}
2740

2841
public String getHint()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.espressif.idf.core.resources;
2+
3+
public enum PopupDialog
4+
{
5+
LOW_PARTITION_SIZE, AVAILABLE_HINTS
6+
}

bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/ParitionSizeHandler.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.eclipse.core.runtime.Path;
1818

1919
import com.espressif.idf.core.resources.OpenDialogListenerSupport;
20+
import com.espressif.idf.core.resources.PopupDialog;
2021

2122
public class ParitionSizeHandler
2223
{
@@ -56,17 +57,15 @@ private String getPartitionTable() throws IOException, CoreException
5657
+ "partition-table.bin"); //$NON-NLS-1$
5758

5859
Process process = startProcess(commands);
59-
String partitionTableContent = new String(process.getInputStream().readAllBytes());
60-
return partitionTableContent;
60+
return new String(process.getInputStream().readAllBytes());
6161
}
6262

6363
private Process startProcess(List<String> commands) throws IOException
6464
{
65-
infoStream.write(String.join(" ", commands) + '\n'); //$NON-NLS-1$ //$NON-NLS-2$
65+
infoStream.write(String.join(" ", commands) + '\n'); //$NON-NLS-1$
6666
Path workingDir = (Path) project.getLocation();
6767
ProcessBuilder processBuilder = new ProcessBuilder(commands).directory(workingDir.toFile());
68-
Process process = processBuilder.start();
69-
return process;
68+
return processBuilder.start();
7069
}
7170

7271
private void startIdfSizeProcess() throws IOException, CoreException
@@ -100,7 +99,8 @@ private void checkRemainingSize(IPath path) throws IOException, CoreException
10099
double remainSize = (maxSize - imageSize) / (maxSize);
101100
if (remainSize < 0.3)
102101
{
103-
OpenDialogListenerSupport.getSupport().firePropertyChange(null, maxSize, remainSize * maxSize);
102+
OpenDialogListenerSupport.getSupport().firePropertyChange(PopupDialog.LOW_PARTITION_SIZE.name(),
103+
maxSize, remainSize * maxSize);
104104
break;
105105
}
106106
}

bundles/com.espressif.idf.ui/OSGI-INF/l10n/bundle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,5 @@ command.label.PartitionTableEditor = ESP-IDF: Partition Table Editor
6767
command.name.PartitionTableEditor = ESP-IDF: Partition Table Editor
6868
command.label.nsvTableEditor = ESP-IDF: NVS Table Editor
6969
command.name.nvsTableEditor = ESP-IDF: NVS Table Editor
70-
command.tooltip.nvsTableEditor = NVS Editor can help you to easily edit NVS CSV, generate encrypted and non-encrypted partitions through GUI, without interacting directly with the csv files.
70+
command.tooltip.nvsTableEditor = NVS Editor can help you to easily edit NVS CSV, generate encrypted and non-encrypted partitions through GUI, without interacting directly with the csv files.
71+
build_hints.name = Build Hints

bundles/com.espressif.idf.ui/plugin.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,15 @@
638638
id="com.espressif.idf.ui.category"
639639
name="%views_category.name">
640640
</category>
641+
<view
642+
allowMultiple="false"
643+
category="com.espressif.idf.ui.category"
644+
class="com.espressif.idf.ui.dialogs.BuildView"
645+
icon="icons/Hints_View.png"
646+
id="com.espressif.idf.ui.views.buildhints"
647+
name="%build_hints.name"
648+
restorable="true">
649+
</view>
641650
</extension>
642651
<extension
643652
point="org.eclipse.ui.intro">

bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/InitializeToolsStartup.java

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
package com.espressif.idf.ui;
66

77
import java.beans.PropertyChangeEvent;
8-
import java.beans.PropertyChangeListener;
98
import java.io.File;
109
import java.io.FileReader;
1110
import java.io.FileWriter;
1211
import java.io.IOException;
1312
import java.net.URL;
1413
import java.text.MessageFormat;
14+
import java.util.List;
1515

1616
import org.eclipse.cdt.cmake.core.internal.Activator;
1717
import org.eclipse.core.resources.ResourcesPlugin;
@@ -25,6 +25,8 @@
2525
import org.eclipse.swt.widgets.MessageBox;
2626
import org.eclipse.swt.widgets.Shell;
2727
import org.eclipse.ui.IStartup;
28+
import org.eclipse.ui.PartInitException;
29+
import org.eclipse.ui.PlatformUI;
2830
import org.json.simple.JSONObject;
2931
import org.json.simple.parser.JSONParser;
3032
import org.json.simple.parser.ParseException;
@@ -33,11 +35,14 @@
3335

3436
import com.espressif.idf.core.IDFEnvironmentVariables;
3537
import com.espressif.idf.core.build.Messages;
38+
import com.espressif.idf.core.build.ReHintPair;
3639
import com.espressif.idf.core.logging.Logger;
3740
import com.espressif.idf.core.resources.OpenDialogListenerSupport;
41+
import com.espressif.idf.core.resources.PopupDialog;
3842
import com.espressif.idf.core.resources.ResourceChangeListener;
3943
import com.espressif.idf.core.toolchain.ESPToolChainManager;
4044
import com.espressif.idf.core.util.StringUtil;
45+
import com.espressif.idf.ui.dialogs.BuildView;
4146
import com.espressif.idf.ui.dialogs.MessageLinkDialog;
4247
import com.espressif.idf.ui.update.ExportIDFTools;
4348
import com.espressif.idf.ui.update.InstallToolsHandler;
@@ -46,6 +51,8 @@
4651
public class InitializeToolsStartup implements IStartup
4752
{
4853

54+
private static final String BUILDHINTS_ID = "com.espressif.idf.ui.views.buildhints"; //$NON-NLS-1$
55+
4956
/**
5057
* esp-idf.json is file created by the installer
5158
*/
@@ -65,24 +72,18 @@ public class InitializeToolsStartup implements IStartup
6572
@Override
6673
public void earlyStartup()
6774
{
68-
OpenDialogListenerSupport.getSupport().addPropertyChangeListener(new PropertyChangeListener()
69-
{
70-
71-
@Override
72-
public void propertyChange(PropertyChangeEvent evt)
75+
OpenDialogListenerSupport.getSupport().addPropertyChangeListener(evt -> {
76+
PopupDialog popupDialog = PopupDialog.valueOf(evt.getPropertyName());
77+
switch (popupDialog)
7378
{
74-
Display.getDefault().asyncExec(new Runnable()
75-
{
76-
@Override
77-
public void run()
78-
{
79-
MessageLinkDialog.openWarning(Display.getDefault().getActiveShell(),
80-
Messages.IncreasePartitionSizeTitle,
81-
MessageFormat.format(Messages.IncreasePartitionSizeMessage, evt.getNewValue(),
82-
evt.getOldValue(), DOC_URL));
83-
}
84-
});
85-
79+
case LOW_PARTITION_SIZE:
80+
openLowPartitionSizeDialog(evt);
81+
break;
82+
case AVAILABLE_HINTS:
83+
openAvailableHintsDialog(evt);
84+
break;
85+
default:
86+
break;
8687
}
8788
});
8889
ILaunchBarListener launchBarListener = new LaunchBarListener();
@@ -197,6 +198,52 @@ else if (isInstallerConfigSet())
197198
Logger.log(e);
198199
}
199200
}
201+
202+
@SuppressWarnings("unchecked")
203+
private void openAvailableHintsDialog(PropertyChangeEvent evt)
204+
{
205+
Display.getDefault().asyncExec(() ->
206+
{
207+
List<ReHintPair> erroHintPairs = (List<ReHintPair>) evt.getNewValue();
208+
// if list is empty we don't want to change focus from the console output
209+
if (erroHintPairs.isEmpty())
210+
{
211+
updateValuesInBuildView(erroHintPairs);
212+
return;
213+
}
214+
try
215+
{
216+
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
217+
.showView(BUILDHINTS_ID);
218+
}
219+
catch (PartInitException e)
220+
{
221+
Logger.log(e);
222+
}
223+
updateValuesInBuildView(erroHintPairs);
224+
}
225+
);
226+
227+
}
228+
229+
private void updateValuesInBuildView(List<ReHintPair> erroHintPairs)
230+
{
231+
BuildView view = ((BuildView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
232+
.findView(BUILDHINTS_ID));
233+
if (view != null)
234+
{
235+
view.updateReHintsPairs(erroHintPairs);
236+
}
237+
}
238+
239+
private void openLowPartitionSizeDialog(PropertyChangeEvent evt)
240+
{
241+
Display.getDefault().asyncExec(() ->
242+
MessageLinkDialog.openWarning(Display.getDefault().getActiveShell(),
243+
Messages.IncreasePartitionSizeTitle, MessageFormat.format(Messages.IncreasePartitionSizeMessage,
244+
evt.getNewValue(), evt.getOldValue(), DOC_URL))
245+
);
246+
}
200247

201248
@SuppressWarnings("unchecked")
202249
private void updateEspIdfJsonFile(File idf_json_file, String newIdfPathToUpdate)

0 commit comments

Comments
 (0)