Hi, is it possible to implement auto-update featur...
# random
a
Hi, is it possible to implement auto-update feature in a JAR that updates itself in runtime and run the application once again after the update without a launcher or separate updater, application, or another JAR file/script? The solution is pretty simple however it doesn't work on Windows due to file locking (can't rename the current running JAR or remove it) One of the requirements is to have only one JAR with the same name without changing it or creating a new jar with the new version and running it, because this JAR file will be used by different applications and each one has its own configurations to store the JAR file name. Having a launcher to update the JAR does complicate things for the end user due to how will this JAR file used.
e
I'm not sure what file locking the JVM does on Windows, but usually you should be able to rename a file to replace it even if it's in use
p
I've faced with the same issue. On Windows it remains locked even if close ClassLoader that had load it. I can't find good solution as you want, so I've made logic such as storing new jar file as a separate file. Then load it through new ClassLoader. Close old ClassLoader and then periodically trying to delete old jar.
a
I'm not sure what file locking the JVM does on Windows, but usually you should be able to rename a file to replace it even if it's in use
This file locking is something specific to Windows and not a restriction by the JVM, otherwise renaming the current running JAR file on Linux and macOS works pretty well
> so I've made logic such as storing new jar file as a separate file. Then load it through new ClassLoader. Close old ClassLoader and then periodically trying to delete old jar. Sounds like a good solution, however for the project use case, this JAR will not be executed directly by the user, instead the user will download it, add it somewhere the script doesn't know about to some launchers for a game, then they will configure the instance to run a command before launching the instance, which has the JAR file name, so it's important the JAR file name remain the same and does not include the version in it as it will complicate things for the end user by having to manually update the command, I want it so they copy the command and paste it without changing anything extra Full Details: The problem is I want the new JAR to have the same name as the current running one, by renaming or overwriting the file, then directly exiting the process and running the new JAR with the same previous file name, I can't manually update the file name in the configurations for more than 10-50 launchers with each one has their own configurations, file format, some of them store the data in system preferences, I would prefer to have this as a last solution. Probably the best solution is to use an auto-updater, this has other problems, the project uses Kotlin/JVM which add Kotlin standard library (which is about 1.7 MB alone), and one of the requirements of the project is to make the size as less as possible, we already use ProGuard however to avoid duplicating the logic we would have to share it in
buildSrc
, another issue that we have
autoUpdate
preference in configurations file and data classes that are specific to the script, we already have common module however we prefer to not complicate things more as it require more setup to get it working from the user side. and what if there is a update to the auto updater launcher that fix bugs or add new features, we would prefer to not complicate things too much. I already tried common solutions like
deleteOnExit
or
addShutdownHook
One solution that could work is to create a bat script in the same JAR and run it then stop the code execution to have the requirements.
I was able to solve this problem by creating a bat script and launch it and then close the application:
Copy code
if (!OperatingSystem.current.isWindows()) {
            Runtime.getRuntime().addShutdownHook(
                Thread {
                    currentRunningJarFile.delete()
                    newJarFile.renameTo(currentRunningJarFile)
                },
            )
        } else {
            // On Windows, we can't rename, delete or modify the current running JAR file due to file locking
            val updateBatScript =
                SyncScriptInstanceFiles.SyncScriptData.Temp.file
                    .resolve("update.bat")
            withContext(Dispatchers.IO) {
                updateBatScript.parentFile.mkdirs()
                updateBatScript.createNewFile()
            }
            updateBatScript.writeText(
                """
                @echo off
                timeout /t 2 > nul
                del "${currentRunningJarFile.absolutePath}"
                move "${newJarFile.absolutePath}" "${currentRunningJarFile.absolutePath}"
                exit
                """.trimIndent(),
            )
            ProcessBuilder("cmd", "/c", "start", updateBatScript.absolutePath).start()
        }
        exitProcess(0)
It cause other issues as I have to close the process with 0, which indicate success, 1 indicate failure, which cause a bug with the launcher that use this JAR, however this issue is not directly related to this Thread. The code can still be improved, for now a workaround for the issue above is to exit with 1 and ask the user to launch once again.