@@ -13,6 +13,7 @@ import org.digma.intellij.plugin.common.Retries
1313import org.digma.intellij.plugin.common.buildVersionRequest
1414import org.digma.intellij.plugin.common.findActiveProject
1515import org.digma.intellij.plugin.common.newerThan
16+ import org.digma.intellij.plugin.common.olderThan
1617import org.digma.intellij.plugin.errorreporting.ErrorReporter
1718import org.digma.intellij.plugin.log.Log
1819import org.digma.intellij.plugin.paths.DigmaPathManager
@@ -21,6 +22,7 @@ import org.digma.intellij.plugin.posthog.ActivityMonitor
2122import org.digma.intellij.plugin.reload.ReloadService
2223import org.digma.intellij.plugin.reload.ReloadSource
2324import org.digma.intellij.plugin.scheduling.disposingPeriodicTask
25+ import org.digma.intellij.plugin.semanticversion.SemanticVersionUtil
2426import org.digma.intellij.plugin.settings.InternalFileSettings
2527import java.io.File
2628import java.net.HttpURLConnection
@@ -114,6 +116,9 @@ class UIVersioningService(val cs: CoroutineScope) : DisposableAdaptor {
114116 }
115117
116118 private fun setCurrentUiVersion (uiVersion : String ) {
119+ // on every change to current version keep also the plugin version it will help to identify a plugin downgrade
120+ val currentPluginVersion = SemanticVersionUtil .getPluginVersionWithoutBuildNumberAndPreRelease(" unknown" )
121+ PersistenceService .getInstance().setLastUiUpdatePluginVersion(currentPluginVersion)
117122 return PersistenceService .getInstance().setCurrentUiVersion(uiVersion)
118123 }
119124
@@ -141,11 +146,69 @@ class UIVersioningService(val cs: CoroutineScope) : DisposableAdaptor {
141146
142147 try {
143148
144- // update this property so it has a value on the first installation of the ui versioning feature
149+ // update this property so it has a value on the first installation of the ui versioning feature.
150+ // if it doesn't have a value its means that this is the first update to a version that includes the feature,
151+ // or it's a new installation. in both cases it's ok to set the current version to the bundled version. from now on
152+ // current version will always be updated to the used ui version.
145153 if (PersistenceService .getInstance().getCurrentUiVersion() == null ) {
146154 setCurrentUiVersion(bundledUiVersion)
147155 }
148156
157+ /*
158+ The following code is support for plugin downgrade.
159+ but we don't detect plugin downgrade we keep track of the plugin version that installed the current ui.
160+ this service keeps track of the plugin version every time setCurrentUiVersion() is called.
161+ on startup , this code will check if the current plugin version is older than the plugin version that installed
162+ the current ui version, this definitely means that there was a plugin downgrade and we need to revert to the bundled ui.
163+ the ui will not be reverted if it was installed by the current plugin version. it may be a downgrade of the plugin ,we don't know.
164+ but if this plugin version installed the current ui it will not be downgraded.
165+ for example
166+ plugin version 5 bundled with ui version 1
167+ then upgraded to ui 2
168+ then upgraded to ui 3
169+ upgrade plugin to version 6 that bundles ui 3
170+ no change - ui is already 3 installed y plugin version 5
171+ downgrade plugin to version 5
172+ ui will not be reverted because it was installed by plugin version 5
173+
174+ example 2
175+ plugin version 5 bundled with ui version 1
176+ then upgraded to ui 2
177+ upgrade plugin to version 6 that bundles ui 3
178+ ui version 3 will be used
179+ downgrade plugin to version 5
180+ ui will revert to version 1 because the current ui was installed by a newer plugin, and we don't know if
181+ ui 3 is compatible with plugin 5
182+
183+ */
184+ val needToUnpackAfterPluginDowngrade = PersistenceService .getInstance().getLastUiUpdatePluginVersion()?.let { lastUiUpdatePluginVersion ->
185+ val currentPluginVersion = SemanticVersionUtil .getPluginVersionWithoutBuildNumberAndPreRelease(" unknown" )
186+ ComparableVersion (currentPluginVersion).olderThan(ComparableVersion (lastUiUpdatePluginVersion))
187+ } ? : false
188+ if (needToUnpackAfterPluginDowngrade) {
189+ Log .log(
190+ logger::info,
191+ " there was a plugin downgrade, using bundled ui. current version: {}, bundled version: {}" ,
192+ getCurrentUiVersion(),
193+ bundledUiVersion
194+ )
195+ if (unpackUiBundle()) {
196+ deleteUiBundle(getCurrentUiVersion())
197+ getLatestDownloadedVersion()?.let {
198+ deleteUiBundle(it)
199+ setLatestDownloadedVersion(null )
200+ }
201+ setCurrentUiVersion(bundledUiVersion)
202+ findActiveProject()?.let {
203+ ActivityMonitor .getInstance(it).setUIVersion(getCurrentUiVersion())
204+ }
205+ } else {
206+ Log .log(logger::warn, " could not unpack bundled ui version {}" , bundledUiVersion)
207+ }
208+ return
209+ }
210+
211+
149212 // Note:always use the methods getCurrentUiVersion() and getLatestDownloadedVersion() and don't assign to local variables
150213 // because values may change concurrently
151214
@@ -160,7 +223,9 @@ class UIVersioningService(val cs: CoroutineScope) : DisposableAdaptor {
160223
161224 // if we have the latest downloaded file, switch to use it and delete the old version
162225 val latestDownloadedUiVersion = getLatestDownloadedVersion()
163- if (latestDownloadedUiVersion != null ) {
226+ if (latestDownloadedUiVersion != null &&
227+ ComparableVersion (latestDownloadedUiVersion).newerThan(ComparableVersion (getCurrentUiVersion()))
228+ ) {
164229 Log .log(
165230 logger::info,
166231 " got latest downloaded ui version on startup {}, trying to update.." , latestDownloadedUiVersion
@@ -207,13 +272,19 @@ class UIVersioningService(val cs: CoroutineScope) : DisposableAdaptor {
207272 " latestDownloadedUiVersion property exists but file does not exist, not updating"
208273 )
209274
275+ setLatestDownloadedVersion(null )
276+ }
277+ } else {
278+ // in any case if we didn't use latest downloaded reset it if it exists
279+ getLatestDownloadedVersion()?.let {
280+ deleteUiBundle(it)
210281 setLatestDownloadedVersion(null )
211282 }
212283 }
213284
214285
215- // maybe user updated the plugin, and the bundled ui is newer then the current ui version .
216- // this is a valid check even if we had a latestDownloadedVersion and we switched to it above
286+ // this is support for plugin update that have a newer ui bundled with it .
287+ // this is a valid check even if we had a latestDownloadedVersion and we switched to it above.
217288 if (ComparableVersion (bundledUiVersion).newerThan(ComparableVersion (getCurrentUiVersion()))) {
218289 Log .log(
219290 logger::info,
0 commit comments