fix(gui): update check fixed to match current artifact naming
This commit is contained in:
@@ -27,6 +27,7 @@ dependencies {
|
||||
|
||||
implementation("org.jcommander:jcommander:2.0")
|
||||
implementation("ch.qos.logback:logback-classic:1.5.11")
|
||||
implementation("io.github.oshai:kotlin-logging-jvm:7.0.0")
|
||||
|
||||
implementation("com.fifesoft:rsyntaxtextarea:3.4.1")
|
||||
implementation(files("libs/jfontchooser-1.0.5.jar"))
|
||||
|
||||
@@ -666,10 +666,10 @@ public class JadxSettingsWindow extends JDialog {
|
||||
group.addRow(NLS.str("preferences.lineNumbersMode"), lineNumbersMode);
|
||||
group.addRow(NLS.str("preferences.jumpOnDoubleClick"), jumpOnDoubleClick);
|
||||
group.addRow(NLS.str("preferences.useAlternativeFileDialog"), useAltFileDialog);
|
||||
group.addRow(NLS.str("preferences.check_for_updates"), update);
|
||||
group.addRow(NLS.str("preferences.cfg"), cfg);
|
||||
group.addRow(NLS.str("preferences.raw_cfg"), rawCfg);
|
||||
group.addRow(NLS.str("preferences.xposed_codegen_language"), xposedCodegenLanguage);
|
||||
group.addRow(NLS.str("preferences.check_for_updates"), update);
|
||||
group.addRow(NLS.str("preferences.update_channel"), updateChannel);
|
||||
return group;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
package jadx.gui.update
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import jadx.api.JadxDecompiler
|
||||
import jadx.core.Jadx
|
||||
import jadx.gui.settings.JadxUpdateChannel
|
||||
import jadx.gui.update.data.Artifact
|
||||
import jadx.gui.update.data.Release
|
||||
import org.jetbrains.kotlin.konan.file.use
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Date
|
||||
import java.net.URI
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
data class Release(val name: String)
|
||||
|
||||
data class ArtifactList(val artifacts: List<Artifact>)
|
||||
|
||||
data class Artifact(
|
||||
val name: String,
|
||||
@SerializedName("workflow_run") val workflowRun: WorkflowRun,
|
||||
)
|
||||
|
||||
data class WorkflowRun(
|
||||
@SerializedName("head_branch") val branch: String,
|
||||
)
|
||||
|
||||
interface IUpdateCallback {
|
||||
fun onUpdate(r: Release)
|
||||
}
|
||||
|
||||
object JadxUpdate {
|
||||
private val LOG: Logger = LoggerFactory.getLogger(JadxUpdate::class.java)
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
const val JADX_ARTIFACTS_URL = "https://nightly.link/skylot/jadx/workflows/build-artifacts/master"
|
||||
const val JADX_RELEASES_URL = "https://github.com/skylot/jadx/releases"
|
||||
|
||||
private const val GITHUB_API_URL = "https://api.github.com/repos/skylot/jadx"
|
||||
private const val GITHUB_ARTIFACTS_URL = "$GITHUB_API_URL/actions/artifacts"
|
||||
private const val GITHUB_LATEST_ARTIFACTS_URL = "$GITHUB_API_URL/actions/artifacts?per_page=5&page=1"
|
||||
private const val GITHUB_LATEST_RELEASE_URL = "$GITHUB_API_URL/releases/latest"
|
||||
|
||||
@JvmStatic
|
||||
@@ -37,7 +48,7 @@ object JadxUpdate {
|
||||
callback.onUpdate(release)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
LOG.debug("Jadx update error", e)
|
||||
log.warn(e) { "Jadx update error" }
|
||||
}
|
||||
}.apply {
|
||||
name = "Jadx update thread"
|
||||
@@ -48,12 +59,12 @@ object JadxUpdate {
|
||||
|
||||
private fun checkForNewRelease(updateChannel: JadxUpdateChannel): Release? {
|
||||
if (Jadx.isDevVersion()) {
|
||||
LOG.debug("Ignore check for update: development version")
|
||||
log.debug { "Ignore check for update: development version" }
|
||||
return null
|
||||
}
|
||||
|
||||
LOG.info("Checking for updates... Update channel: {}, current version: {}", updateChannel, JadxDecompiler.getVersion())
|
||||
|
||||
log.info {
|
||||
"Checking for updates... Update channel: $updateChannel, current version: ${JadxDecompiler.getVersion()}"
|
||||
}
|
||||
return when (updateChannel) {
|
||||
JadxUpdateChannel.STABLE -> checkForNewStableRelease()
|
||||
JadxUpdateChannel.UNSTABLE -> checkForNewUnstableRelease()
|
||||
@@ -61,76 +72,40 @@ object JadxUpdate {
|
||||
}
|
||||
|
||||
private fun checkForNewStableRelease(): Release? {
|
||||
val latestRelease = get(GITHUB_LATEST_RELEASE_URL)?.let { inputStream ->
|
||||
InputStreamReader(inputStream).use {
|
||||
Gson().fromJson(it, Release::class.java)
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
val currentVersion = JadxDecompiler.getVersion()
|
||||
|
||||
if (currentVersion.equals(latestRelease.name, ignoreCase = true)) return null
|
||||
if (currentVersion.startsWith("r")) {
|
||||
// current version is 'unstable', but update channel set to 'stable'
|
||||
log.info { "Skip update check: can't compare unstable and stable versions" }
|
||||
return null
|
||||
}
|
||||
val latestRelease = getAndParse(GITHUB_LATEST_RELEASE_URL, Release::class) ?: return null
|
||||
if (VersionComparator.checkAndCompare(currentVersion, latestRelease.name) >= 0) return null
|
||||
|
||||
LOG.info("Found new jadx version: {}", latestRelease)
|
||||
|
||||
log.info { "Found new jadx version: ${latestRelease.name}" }
|
||||
return latestRelease
|
||||
}
|
||||
|
||||
private fun checkForNewUnstableRelease(): Release? {
|
||||
val artifacts = getArtifacts() ?: return null
|
||||
val artifacts = getAndParse(GITHUB_LATEST_ARTIFACTS_URL, ArtifactList::class)
|
||||
?.artifacts
|
||||
?.filter { it.workflowRun.branch == "master" }
|
||||
?: return null
|
||||
if (artifacts.isEmpty()) return null
|
||||
|
||||
val currentVersion = JadxDecompiler.getVersion()
|
||||
val currentArtifactName = "jadx-$currentVersion"
|
||||
|
||||
var newestArtifact: Artifact? = null
|
||||
var currentArtifact: Artifact? = null
|
||||
|
||||
for (artifact in artifacts) {
|
||||
if (newestArtifact == null && artifact.name.startsWith("jadx-") && !artifact.name.startsWith("jadx-gui-")) {
|
||||
newestArtifact = artifact
|
||||
}
|
||||
if (currentArtifact == null && artifact.name == currentArtifactName) {
|
||||
currentArtifact = artifact
|
||||
}
|
||||
if (newestArtifact != null && currentArtifact != null) break
|
||||
}
|
||||
|
||||
LOG.debug("Current artifact: {}, newest artifact: {}", currentArtifact, newestArtifact)
|
||||
|
||||
return if (currentArtifact != null && newestArtifact != null && newestArtifact.createdAt > currentArtifact.createdAt) {
|
||||
newestArtifact.let { Release().apply { name = it.name } }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val latestVersion = artifacts[0].name.removePrefix("jadx-gui-").removePrefix("jadx-").substringBefore('-')
|
||||
if (VersionComparator.checkAndCompare(JadxDecompiler.getVersion(), latestVersion) >= 0) return null
|
||||
log.info { "Found new unstable version: $latestVersion" }
|
||||
return Release(latestVersion)
|
||||
}
|
||||
|
||||
private fun getArtifacts(): List<Artifact>? {
|
||||
return get(GITHUB_ARTIFACTS_URL)?.let { inputStream ->
|
||||
InputStreamReader(inputStream).use { reader ->
|
||||
val response = JsonParser.parseReader(reader).asJsonObject
|
||||
|
||||
val count = response.get("total_count").asInt
|
||||
LOG.debug("Fetched $count artifacts...")
|
||||
|
||||
response.getAsJsonArray("artifacts").map {
|
||||
val obj = it.asJsonObject
|
||||
val name = obj.get("name").asString
|
||||
val sizeInBytes = obj.get("size_in_bytes").asLong
|
||||
val createdAt = obj.get("created_at").asString
|
||||
val parsedCreatedAt = ZonedDateTime.parse(createdAt, DateTimeFormatter.ISO_ZONED_DATE_TIME)
|
||||
Artifact(name, sizeInBytes, Date.from(parsedCreatedAt.toInstant()))
|
||||
}
|
||||
private fun <T : Any> getAndParse(url: String, klass: KClass<T>): T? {
|
||||
val con = URI(url).toURL().openConnection() as? HttpURLConnection
|
||||
if (con == null || con.responseCode != 200) {
|
||||
return null
|
||||
}
|
||||
return con.inputStream.use { stream ->
|
||||
InputStreamReader(stream).use { reader ->
|
||||
Gson().fromJson(reader, klass.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun get(url: String): InputStream? {
|
||||
val con = URL(url).openConnection() as HttpURLConnection
|
||||
return if (con.responseCode == 200) con.inputStream else null
|
||||
}
|
||||
|
||||
interface IUpdateCallback {
|
||||
fun onUpdate(r: Release)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,23 @@ public class VersionComparator {
|
||||
return "";
|
||||
}
|
||||
String result = str.trim().toLowerCase();
|
||||
if (result.startsWith("jadx-gui-")) {
|
||||
result = result.substring(9);
|
||||
}
|
||||
if (result.startsWith("jadx-")) {
|
||||
result = result.substring(5);
|
||||
}
|
||||
if (result.charAt(0) == 'v') {
|
||||
result = result.substring(1);
|
||||
}
|
||||
// treat package version as part of version
|
||||
if (result.charAt(0) == 'r') {
|
||||
result = result.substring(1);
|
||||
int dot = result.indexOf('.');
|
||||
if (dot != -1) {
|
||||
result = result.substring(0, dot);
|
||||
}
|
||||
}
|
||||
// treat a package version as part of version
|
||||
result = result.replace('-', '.');
|
||||
return result;
|
||||
}
|
||||
@@ -50,8 +63,7 @@ public class VersionComparator {
|
||||
|
||||
private static boolean isZeroTail(String[] arr, int pos) {
|
||||
for (int i = pos; i < arr.length; i++) {
|
||||
String s = arr[i];
|
||||
if (Integer.valueOf(s) != 0) {
|
||||
if (Integer.parseInt(arr[i]) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package jadx.gui.update.data
|
||||
|
||||
import java.util.Date
|
||||
|
||||
data class Artifact(
|
||||
val name: String,
|
||||
val sizeInBytes: Long,
|
||||
val createdAt: Date,
|
||||
)
|
||||
@@ -1,75 +0,0 @@
|
||||
package jadx.gui.update.data;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Asset {
|
||||
private int id;
|
||||
private String name;
|
||||
private long size;
|
||||
|
||||
@SerializedName("download_count")
|
||||
private int downloadCount;
|
||||
|
||||
@SerializedName("browser_download_url")
|
||||
private String downloadUrl;
|
||||
|
||||
@SerializedName("created_at")
|
||||
private String createdAt;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getDownloadCount() {
|
||||
return downloadCount;
|
||||
}
|
||||
|
||||
public void setDownloadCount(int downloadCount) {
|
||||
this.downloadCount = downloadCount;
|
||||
}
|
||||
|
||||
public String getDownloadUrl() {
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
public void setDownloadUrl(String downloadUrl) {
|
||||
this.downloadUrl = downloadUrl;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(String createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name
|
||||
+ ", size: " + String.format("%.2fMB", size / 1024. / 1024.)
|
||||
+ ", downloads count: " + downloadCount
|
||||
+ ", url: " + downloadUrl
|
||||
+ ", date: " + createdAt;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package jadx.gui.update.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Release {
|
||||
private int id;
|
||||
private String name;
|
||||
private List<Asset> assets;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Asset> getAssets() {
|
||||
return assets;
|
||||
}
|
||||
|
||||
public void setAssets(List<Asset> assets) {
|
||||
this.assets = assets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
for (Asset asset : getAssets()) {
|
||||
sb.append("\n ");
|
||||
sb.append(asset);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,11 @@ class VersionComparatorTest {
|
||||
checkCompare("1.3.3.1-1", "1.3.3", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareUnstable() {
|
||||
checkCompare("r2190.ce527ed", "jadx-r2299.742d30d", -1);
|
||||
}
|
||||
|
||||
private static void checkCompare(String a, String b, int result) {
|
||||
assertThat(VersionComparator.checkAndCompare(a, b))
|
||||
.as("Compare %s and %s expect %d", a, b, result)
|
||||
|
||||
Reference in New Issue
Block a user