duplicate `BundleUtil` class to avoid reflection error on console update #7198

This commit is contained in:
kifir23917 2025-01-17 14:26:16 +03:00 committed by rusefillc
parent 107c3dec42
commit 2d2b368a78
3 changed files with 132 additions and 4 deletions

View File

@ -1,7 +1,6 @@
package com.rusefi; package com.rusefi;
import com.devexperts.logging.Logging; import com.devexperts.logging.Logging;
import com.rusefi.core.io.BundleUtil;
import com.rusefi.core.net.ConnectionAndMeta; import com.rusefi.core.net.ConnectionAndMeta;
import com.rusefi.core.preferences.storage.PersistentConfiguration; import com.rusefi.core.preferences.storage.PersistentConfiguration;
import com.rusefi.core.ui.FrameHelper; import com.rusefi.core.ui.FrameHelper;
@ -10,6 +9,7 @@ import com.rusefi.io.serial.BaudRateHolder;
import com.rusefi.maintenance.*; import com.rusefi.maintenance.*;
import com.rusefi.ui.BasicLogoHelper; import com.rusefi.ui.BasicLogoHelper;
import com.rusefi.ui.LogoHelper; import com.rusefi.ui.LogoHelper;
import com.rusefi.ui.duplicates.ConsoleBundleUtil;
import com.rusefi.ui.util.HorizontalLine; import com.rusefi.ui.util.HorizontalLine;
import com.rusefi.ui.util.URLLabel; import com.rusefi.ui.util.URLLabel;
import com.rusefi.ui.util.UiUtils; import com.rusefi.ui.util.UiUtils;
@ -209,7 +209,7 @@ public class StartupFrame {
JPanel rightPanel = new JPanel(new VerticalFlowLayout()); JPanel rightPanel = new JPanel(new VerticalFlowLayout());
if (BundleUtil.readBundleFullNameNotNull().getTarget().contains("proteus_f7")) { if (ConsoleBundleUtil.readBundleFullNameNotNull().getTarget().contains("proteus_f7")) {
String text = "WARNING: Proteus F7"; String text = "WARNING: Proteus F7";
URLLabel urlLabel = new URLLabel(text, "https://github.com/rusefi/rusefi/wiki/F7-requires-full-erase"); URLLabel urlLabel = new URLLabel(text, "https://github.com/rusefi/rusefi/wiki/F7-requires-full-erase");
new Timer(500, new ActionListener() { new Timer(500, new ActionListener() {
@ -252,7 +252,7 @@ public class StartupFrame {
final String textAlign, final String textAlign,
final Supplier<Integer> minWidthSupplier final Supplier<Integer> minWidthSupplier
) { ) {
final String nextBranchName = BundleUtil.readBundleFullNameNotNull().getNextBranchName(); final String nextBranchName = ConsoleBundleUtil.readBundleFullNameNotNull().getNextBranchName();
if (nextBranchName != null && !nextBranchName.isBlank()) { if (nextBranchName != null && !nextBranchName.isBlank()) {
final JLabel newReleaseAmmomceMessage = new JLabel( final JLabel newReleaseAmmomceMessage = new JLabel(
String.format( String.format(
@ -287,7 +287,7 @@ public class StartupFrame {
jLabel.setForeground(Color.red); jLabel.setForeground(Color.red);
} else { } else {
final Date binaryModificationDate = new Date(binaryModificationTimestamp); final Date binaryModificationDate = new Date(binaryModificationTimestamp);
final String branchNameToDisplay = BundleUtil.readBundleFullNameNotNull().getBranchName(); final String branchNameToDisplay = ConsoleBundleUtil.readBundleFullNameNotNull().getBranchName();
jLabel = new JLabel(String.format( jLabel = new JLabel(String.format(
"<html><center>%s files<br/>%s</center></html>", "<html><center>%s files<br/>%s</center></html>",
branchNameToDisplay, branchNameToDisplay,

View File

@ -0,0 +1,117 @@
package com.rusefi.ui.duplicates;
import com.devexperts.logging.Logging;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import static com.devexperts.logging.Logging.getLogging;
// `com.rusefi.ui.duplicates.ConsoleBundleUtil` class duplicates `com.rusefi.core.io.BundleUtil` class to avoid crash
// on console update (caused by missed `BundleInfo.getNextBranchName` method) - see `readme.md` for details.
// TODO: in June 2025 we need to get rid of this class and to replace its usage with `com.rusefi.core.io.BundleUtil`.
public class ConsoleBundleUtil {
private static final Logging log = getLogging(ConsoleBundleUtil.class);
private static final String DEVELOPMENT = "development";
private static final String BRANCH_REF_FILE = "release.txt";
/**
* @return null in case of error
*/
public static List<@NotNull String> readBundleFullName() {
File f = new File(BRANCH_REF_FILE);
if (!f.exists()) {
log.error(BRANCH_REF_FILE + " not found");
return null;
}
try {
return Files.readAllLines(f.toPath());
} catch (InvalidPathException | IOException e) {
log.error("Error reading bundle name", e);
return null;
}
}
@NotNull
public static BundleInfo readBundleFullNameNotNull() {
List<@NotNull String> info = readBundleFullName();
if (info == null)
return BundleInfo.UNKNOWN;
return parse(info);
}
public static String getBundleTarget() {
return readBundleFullNameNotNull().getTarget();
}
public static BundleInfo parse(List<@NotNull String> info) {
Map<String, String> keyValues = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (String line : info) {
String[] pair = line.split("=", 2);
keyValues.put(pair[0], pair[1]);
}
String target = keyValues.get("platform");
String branchName = keyValues.get("release");
String nextBranchName = keyValues.get("nextRelease");
if (target == null || branchName == null) {
log.info(BRANCH_REF_FILE + " says " + keyValues);
return BundleInfo.UNKNOWN;
}
return new ConsoleBundleUtil.BundleInfo(branchName, nextBranchName, target);
}
public static class BundleInfo {
static final BundleInfo UNKNOWN = new BundleInfo("unknown", null, "unknown");
private final String branchName;
private final String nextBranchName;
private final String target;
public BundleInfo(String branchName, String nextBranchName, String target) {
this.branchName = Objects.requireNonNull(branchName, "branchName");
this.nextBranchName = nextBranchName;
this.target = Objects.requireNonNull(target, "target");
}
public static boolean isUndefined(BundleInfo bundleInfo) {
return bundleInfo == UNKNOWN;
}
public String getBranchName() {
return branchName;
}
public String getNextBranchName() {
return nextBranchName;
}
public boolean isMaster() {
return DEVELOPMENT.equals(branchName);
}
public String getTarget() {
return target;
}
@Override
public String toString() {
return "BundleInfo{" +
"branchName='" + branchName + '\'' +
"nextBranchName='" + nextBranchName + '\'' +
", target='" + target + '\'' +
'}';
}
public String getUiLabel() {
return target + "." + branchName;
}
}
}

View File

@ -0,0 +1,11 @@
We have a problem with classes that are used by both `rusefi_autoupdate.jar` and `rusefi_console.jar`: if we add a new method to such class and use it in `rusefi_console.jar` than we get reflection exception after update.
The reason is that `rusefi_autoupdate.jar` contains an obsolete version of the class without new method, but a new version `rusefi_console.jar` tries to call the missed method and crashes.
This is not a total catastrophe, because after crash `rusefi_console.jar` can be restarted successfully, but we want to reduce number of users experiencing this problem.
The suggested solution is to temporarily duplicate problematic classes in `com.rusefi.ui.duplicates` package and at first to use this duplicated classes in `rusefi_console.jar` instead of original classes that is used in `rusefi_autoupdate.jar`.
After the majority of users have already updated their console, we could get rid of duplicated classes and replace them with the original class used by `rusefi_autoupdate.jar`.
We will still have a few users that haven't updated their console and they will experience a crash on console update, but I do not think that it is serious problem.