Rework updater to fix some bugs [release]

This commit is contained in:
crschnick 2023-04-01 12:04:01 +00:00
parent 5444bc785f
commit b1f2272fc2
9 changed files with 104 additions and 113 deletions

View file

@ -38,6 +38,7 @@ public class FileBrowserComp extends SimpleComp {
@Override @Override
protected Region createSimple() { protected Region createSimple() {
var bookmarksList = new BookmarkList(model).createRegion(); var bookmarksList = new BookmarkList(model).createRegion();
VBox.setVgrow(bookmarksList, Priority.ALWAYS);
var localDownloadStage = new LocalFileTransferComp(model.getLocalTransfersStage()).hide(Bindings.createBooleanBinding(() -> { var localDownloadStage = new LocalFileTransferComp(model.getLocalTransfersStage()).hide(Bindings.createBooleanBinding(() -> {
if (model.getOpenFileSystems().size() == 0) { if (model.getOpenFileSystems().size() == 0) {
return true; return true;

View file

@ -40,20 +40,16 @@ public class UpdateCheckComp extends SimpleComp {
} }
private void restart() { private void restart() {
// Check if we're still on latest AppUpdater.get().refreshUpdateCheckSilent();
if (!AppUpdater.get().isDownloadedUpdateStillLatest()) {
return;
}
AppUpdater.get().executeUpdateAndClose(); AppUpdater.get().executeUpdateAndClose();
} }
private void update() { private void download() {
AppUpdater.get().downloadUpdateAsync(); AppUpdater.get().downloadUpdateAsync();
} }
private void refresh() { private void refresh() {
AppUpdater.get().checkForUpdateAsync(true); AppUpdater.get().checkForUpdateAsync();
} }
private ObservableValue<String> descriptionText() { private ObservableValue<String> descriptionText() {
@ -131,8 +127,6 @@ public class UpdateCheckComp extends SimpleComp {
updateReady)); updateReady));
button.getStyleClass().add("button-comp"); button.getStyleClass().add("button-comp");
button.setOnAction(e -> { button.setOnAction(e -> {
AppUpdater.get().refreshUpdateState();
if (updateReady.getValue()) { if (updateReady.getValue()) {
restart(); restart();
return; return;
@ -142,7 +136,7 @@ public class UpdateCheckComp extends SimpleComp {
Hyperlinks.open( Hyperlinks.open(
AppUpdater.get().getLastUpdateCheckResult().getValue().getReleaseUrl()); AppUpdater.get().getLastUpdateCheckResult().getValue().getReleaseUrl());
} else if (updateAvailable.getValue()) { } else if (updateAvailable.getValue()) {
update(); download();
} else { } else {
refresh(); refresh();
} }

View file

@ -88,7 +88,7 @@ public class TerminalErrorHandler implements ErrorHandler {
private static void handleProbableUpdate() { private static void handleProbableUpdate() {
try { try {
AppUpdater.init(); AppUpdater.init();
var rel = AppUpdater.get().checkForUpdate(true); var rel = AppUpdater.get().refreshUpdateCheck();
if (rel != null && rel.isUpdate()) { if (rel != null && rel.isUpdate()) {
var update = AppWindowHelper.showBlockingAlert(alert -> { var update = AppWindowHelper.showBlockingAlert(alert -> {
alert.setAlertType(Alert.AlertType.INFORMATION); alert.setAlertType(Alert.AlertType.INFORMATION);

View file

@ -1,5 +1,6 @@
package io.xpipe.app.update; package io.xpipe.app.update;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
@ -96,26 +97,41 @@ public class AppDownloads {
} }
} }
public static String getLatestVersion(boolean omitErrors) { public static String getLatestVersion() throws IOException {
return getLatestSuitableRelease(omitErrors) return getLatestSuitableRelease()
.map(ghRelease -> ghRelease.getTagName()) .map(ghRelease -> ghRelease.getTagName())
.orElse("?"); .orElse("?");
} }
public static Optional<GHRelease> getLatestSuitableRelease(boolean omitErrors) {
try {
var repo = getRepository();
// Always choose most up-to-date release as we assume that there are only full releases and prereleases public static Optional<GHRelease> getLatestIncludingPreRelease() throws IOException {
if (AppPrefs.get() != null && AppPrefs.get().updateToPrereleases().get()) { var repo = getRepository();
return Optional.ofNullable(repo.listReleases().iterator().next()); return Optional.ofNullable(repo.listReleases().iterator().next());
} }
return Optional.ofNullable(repo.getLatestRelease()); public static Optional<GHRelease> getLatestRelease() throws IOException {
} catch (IOException e) { var repo = getRepository();
ErrorEvent.fromThrowable("Unable to fetch latest release information", e).omitted(omitErrors).handle(); return Optional.ofNullable(repo.getLatestRelease());
return Optional.empty(); }
public static Optional<GHRelease> getLatestSuitableRelease() throws IOException {
var preIncluding = getLatestIncludingPreRelease();
if (AppPrefs.get() != null && AppPrefs.get().updateToPrereleases().get()) {
return preIncluding;
} }
// If we are currently running a prerelease, always return this as the suitable release!
if (preIncluding.isPresent() && AppProperties.get().getVersion().equals(preIncluding.get().getTagName())) {
return preIncluding;
}
// If this release is not a prerelease, just return it to prevent querying another release
if (preIncluding.isPresent() && !preIncluding.get().isPrerelease()) {
return preIncluding;
}
return getLatestRelease();
} }
public static Optional<GHRelease> getRelease(String version, boolean omitErrors) { public static Optional<GHRelease> getRelease(String version, boolean omitErrors) {

View file

@ -20,6 +20,7 @@ import lombok.With;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
import org.kohsuke.github.GHRelease; import org.kohsuke.github.GHRelease;
import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration; import java.time.Duration;
@ -50,6 +51,8 @@ public class AppUpdater {
} }
downloadedUpdate.setValue(AppCache.get("downloadedUpdate", DownloadedUpdate.class, () -> null)); downloadedUpdate.setValue(AppCache.get("downloadedUpdate", DownloadedUpdate.class, () -> null));
// Check if the original version this was downloaded from is still the same
if (downloadedUpdate.getValue() != null if (downloadedUpdate.getValue() != null
&& !downloadedUpdate && !downloadedUpdate
.getValue() .getValue()
@ -57,6 +60,16 @@ public class AppUpdater {
.equals(AppProperties.get().getVersion())) { .equals(AppProperties.get().getVersion())) {
downloadedUpdate.setValue(null); downloadedUpdate.setValue(null);
} }
// Check if somehow the downloaded version is equal to the current one
if (downloadedUpdate.getValue() != null
&& downloadedUpdate
.getValue()
.getVersion()
.equals(AppProperties.get().getVersion())) {
downloadedUpdate.setValue(null);
}
if (!XPipeDistributionType.get().supportsUpdate()) { if (!XPipeDistributionType.get().supportsUpdate()) {
downloadedUpdate.setValue(null); downloadedUpdate.setValue(null);
} }
@ -64,20 +77,10 @@ public class AppUpdater {
downloadedUpdate.addListener((c, o, n) -> { downloadedUpdate.addListener((c, o, n) -> {
AppCache.update("downloadedUpdate", n); AppCache.update("downloadedUpdate", n);
}); });
lastUpdateCheckResult.setValue(AppCache.get("lastUpdateCheckResult", AvailableRelease.class, () -> null));
if (lastUpdateCheckResult.getValue() != null
&& lastUpdateCheckResult.getValue().getSourceVersion() != null
&& !lastUpdateCheckResult
.getValue()
.getSourceVersion()
.equals(AppProperties.get().getVersion())) {
lastUpdateCheckResult.setValue(null);
}
event("Last update check result was " + lastUpdateCheckResult.getValue());
lastUpdateCheckResult.addListener((c, o, n) -> { lastUpdateCheckResult.addListener((c, o, n) -> {
AppCache.update("lastUpdateCheckResult", n); downloadedUpdate.setValue(null);
}); });
refreshUpdateCheckSilent();
} }
private static void event(String msg) { private static void event(String msg) {
@ -94,14 +97,17 @@ public class AppUpdater {
} }
INSTANCE = new AppUpdater(); INSTANCE = new AppUpdater();
startBackgroundUpdater();
}
private static void startBackgroundUpdater() {
if (XPipeDistributionType.get().supportsUpdate() if (XPipeDistributionType.get().supportsUpdate()
&& XPipeDistributionType.get() != XPipeDistributionType.DEVELOPMENT) { && XPipeDistributionType.get() != XPipeDistributionType.DEVELOPMENT) {
ThreadHelper.create("updater", true, () -> { ThreadHelper.create("updater", true, () -> {
ThreadHelper.sleep(Duration.ofMinutes(10).toMillis()); ThreadHelper.sleep(Duration.ofMinutes(10).toMillis());
event("Starting background updater thread"); event("Starting background updater thread");
while (true) { while (true) {
var rel = INSTANCE.checkForUpdate(false); var rel = INSTANCE.refreshUpdateCheckSilent();
if (rel != null if (rel != null
&& AppPrefs.get().automaticallyUpdate().get() && rel.isUpdate()) { && AppPrefs.get().automaticallyUpdate().get() && rel.isUpdate()) {
event("Performing background update"); event("Performing background update");
@ -115,7 +121,7 @@ public class AppUpdater {
} }
} }
private static boolean isUpdate(String currentVersion) { private static boolean isUpdate(String releaseVersion) {
if (AppPrefs.get() != null if (AppPrefs.get() != null
&& AppPrefs.get().developerMode().getValue() && AppPrefs.get().developerMode().getValue()
&& AppPrefs.get().developerDisableUpdateVersionCheck().get()) { && AppPrefs.get().developerDisableUpdateVersionCheck().get()) {
@ -123,10 +129,7 @@ public class AppUpdater {
return true; return true;
} }
if ( if (!AppProperties.get().getVersion().equals(releaseVersion)) {
// true
// ||
!AppProperties.get().getVersion().equals(currentVersion)) {
event("Release has a different version"); event("Release has a different version");
return true; return true;
} }
@ -134,13 +137,6 @@ public class AppUpdater {
return false; return false;
} }
public void refreshUpdateState() {
if (lastUpdateCheckResult.getValue() != null
&& !isUpdate(lastUpdateCheckResult.getValue().getVersion())) {
lastUpdateCheckResult.setValue(lastUpdateCheckResult.getValue().withUpdate(false));
}
}
public void downloadUpdateAsync() { public void downloadUpdateAsync() {
ThreadHelper.runAsync(() -> downloadUpdate()); ThreadHelper.runAsync(() -> downloadUpdate());
} }
@ -158,6 +154,10 @@ public class AppUpdater {
return; return;
} }
if (!lastUpdateCheckResult.getValue().isUpdate()) {
return;
}
try (var ignored = new BusyProperty(busy)) { try (var ignored = new BusyProperty(busy)) {
event("Performing update download ..."); event("Performing update download ...");
try { try {
@ -184,20 +184,12 @@ public class AppUpdater {
} }
} }
private boolean shouldPerformUpdate() { public void executeUpdateAndClose() {
if (busy.getValue()) { if (busy.getValue()) {
return false; return;
} }
if (downloadedUpdate.getValue() == null) { if (downloadedUpdate.getValue() == null) {
return false;
}
return true;
}
public void executeUpdateAndClose() {
if (!shouldPerformUpdate()) {
return; return;
} }
@ -222,69 +214,57 @@ public class AppUpdater {
}); });
} }
public void checkForUpdateAsync(boolean forceCheck) { public void checkForUpdateAsync() {
ThreadHelper.runAsync(() -> checkForUpdate(forceCheck)); ThreadHelper.runAsync(() -> refreshUpdateCheckSilent());
} }
public synchronized boolean isDownloadedUpdateStillLatest() { public synchronized AvailableRelease refreshUpdateCheckSilent() {
if (downloadedUpdate.getValue() == null) { try {
return false; return refreshUpdateCheck();
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).omit().handle();
return null;
} }
var available = checkForUpdate(true);
if (available == null) {
return true;
}
return downloadedUpdate.getValue() != null
&& available.getVersion().equals(downloadedUpdate.getValue().getVersion());
} }
public synchronized AvailableRelease checkForUpdate(boolean forceCheck) { public synchronized AvailableRelease refreshUpdateCheck() throws IOException {
if (busy.getValue()) { if (busy.getValue()) {
return lastUpdateCheckResult.getValue(); return lastUpdateCheckResult.getValue();
} }
if (!forceCheck
&& lastUpdateCheckResult.getValue() != null
&& Duration.between(lastUpdateCheckResult.getValue().getCheckTime(), Instant.now())
.compareTo(Duration.ofHours(1))
<= 0) {
return lastUpdateCheckResult.getValue();
}
try (var ignored = new BusyProperty(busy)) { try (var ignored = new BusyProperty(busy)) {
var rel = AppDownloads.getLatestSuitableRelease(!forceCheck); var rel = AppDownloads.getLatestSuitableRelease();
event("Determined latest suitable release " event("Determined latest suitable release "
+ rel.map(GHRelease::getName).orElse(null)); + rel.map(GHRelease::getName).orElse(null));
lastUpdateCheckResult.setValue(null);
if (rel.isEmpty()) { if (rel.isEmpty()) {
lastUpdateCheckResult.setValue(null);
return null; return null;
} }
var isUpdate = isUpdate(rel.get().getTagName()); // Don't update value if result is the same
try { if (lastUpdateCheckResult.getValue() != null && lastUpdateCheckResult.getValue().getVersion().equals(rel.get().getTagName())) {
var assetType = AppInstaller.getSuitablePlatformAsset(); return lastUpdateCheckResult.getValue();
var ghAsset = rel.orElseThrow().listAssets().toList().stream()
.filter(g -> assetType.isCorrectAsset(g.getName()))
.findAny();
if (ghAsset.isEmpty()) {
return null;
}
event("Selected asset " + ghAsset.get().getName());
lastUpdateCheckResult.setValue(new AvailableRelease(
AppProperties.get().getVersion(),
rel.get().getTagName(),
rel.get().getHtmlUrl().toString(),
ghAsset.get().getBrowserDownloadUrl(),
assetType,
Instant.now(),
isUpdate));
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).omit().handle();
} }
var isUpdate = isUpdate(rel.get().getTagName());
var assetType = AppInstaller.getSuitablePlatformAsset();
var ghAsset = rel.orElseThrow().listAssets().toList().stream()
.filter(g -> assetType.isCorrectAsset(g.getName()))
.findAny();
if (ghAsset.isEmpty()) {
return null;
}
event("Selected asset " + ghAsset.get().getName());
lastUpdateCheckResult.setValue(new AvailableRelease(
AppProperties.get().getVersion(),
rel.get().getTagName(),
rel.get().getHtmlUrl().toString(),
ghAsset.get().getBrowserDownloadUrl(),
assetType,
Instant.now(),
isUpdate));
} }
return lastUpdateCheckResult.getValue(); return lastUpdateCheckResult.getValue();

View file

@ -18,11 +18,6 @@ public class UpdateAvailableAlert {
return; return;
} }
if (AppUpdater.get().getDownloadedUpdate().getValue() != null && !AppUpdater.get().isDownloadedUpdateStillLatest()) {
AppUpdater.get().getDownloadedUpdate().setValue(null);
return;
}
var update = AppWindowHelper.showBlockingAlert(alert -> { var update = AppWindowHelper.showBlockingAlert(alert -> {
alert.setTitle(AppI18n.get("updateReadyAlertTitle")); alert.setTitle(AppI18n.get("updateReadyAlertTitle"));
alert.setHeaderText(AppI18n.get("updateReadyAlertHeader", AppUpdater.get().getDownloadedUpdate().getValue().getVersion())); alert.setHeaderText(AppI18n.get("updateReadyAlertHeader", AppUpdater.get().getDownloadedUpdate().getValue().getVersion()));

View file

@ -32,7 +32,7 @@ public class ProxyManagerProviderImpl extends ProxyManagerProvider {
@Override @Override
public Optional<String> checkCompatibility(ShellControl s) throws Exception { public Optional<String> checkCompatibility(ShellControl s) throws Exception {
var version = ModuleHelper.isImage() ? AppProperties.get().getVersion() : AppDownloads.getLatestVersion(true); var version = ModuleHelper.isImage() ? AppProperties.get().getVersion() : AppDownloads.getLatestVersion();
if (AppPrefs.get().developerDisableConnectorInstallationVersionCheck().get()) { if (AppPrefs.get().developerDisableConnectorInstallationVersionCheck().get()) {
return Optional.of(AppI18n.get("versionCheckOverride")); return Optional.of(AppI18n.get("versionCheckOverride"));
@ -59,7 +59,7 @@ public class ProxyManagerProviderImpl extends ProxyManagerProvider {
if (message.isPresent()) { if (message.isPresent()) {
if (showAlert()) { if (showAlert()) {
var version = var version =
ModuleHelper.isImage() ? AppProperties.get().getVersion() : AppDownloads.getLatestVersion(true); ModuleHelper.isImage() ? AppProperties.get().getVersion() : AppDownloads.getLatestVersion();
AppInstaller.installOnRemoteMachine(s, version); AppInstaller.installOnRemoteMachine(s, version);
return true; return true;
} }

5
dist/changelogs/0.5.29.md vendored Normal file
View file

@ -0,0 +1,5 @@
- Introduce new download functionality in the file browser
- Allow for the creation of desktop shortcuts on portable distributions as well
- Fix file sizes sometimes being incorrectly displayed
- Fix background updater downloading the same version
- Fix various small bugs

View file

@ -1 +1 @@
0.5.28 0.5.29