diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e06ad4553bfe30e718279191e2ed5a2d3a834741..02489077ce9c2395da04addd694bae8ae8fd95d8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,7 +14,7 @@ updates: labels: - "dependencies" - "github-actions" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" @@ -30,7 +30,7 @@ updates: labels: - "dependencies" - "gradle" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" @@ -43,7 +43,7 @@ updates: labels: - "dependencies" - "gradle" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" @@ -56,7 +56,7 @@ updates: labels: - "dependencies" - "gradle" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" @@ -72,7 +72,7 @@ updates: labels: - "dependencies" - "npm" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" @@ -88,6 +88,6 @@ updates: labels: - "dependencies" - "docker" - target-branch: "dependabot" + target-branch: "develop" pull-request-branch-name: separator: "-" diff --git a/.runConfigurations/Run App.run.xml b/.runConfigurations/Run App.run.xml index 7487e4db9b1867341616de18212ea4579c82df31..cca44e66dcfa447b6d8ad54e356d3a5bbf08473e 100644 --- a/.runConfigurations/Run App.run.xml +++ b/.runConfigurations/Run App.run.xml @@ -2,7 +2,7 @@ <configuration default="false" name="Run App" type="JetRunConfigurationType"> <option name="MAIN_CLASS_NAME" value="de.griefed.serverpackcreator.app.ServerPackCreatorKt" /> <module name="serverpackcreator.serverpackcreator-app.main" /> - <option name="PROGRAM_PARAMETERS" value="--home "$ProjectFileDir$/serverpackcreator-app/tests"" /> + <option name="PROGRAM_PARAMETERS" value="--home "$ProjectFileDir$/serverpackcreator-app/tests" -cli" /> <shortenClasspath name="NONE" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/serverpackcreator-app/tests" /> <method v="2"> diff --git a/HELP.md b/HELP.md index c67dbe18d07d95fa800db02fdd483da35e031d01..1698f4c021a6c3a3d511139b7dd5c2136b213de4 100644 --- a/HELP.md +++ b/HELP.md @@ -111,6 +111,8 @@ The following placeholders will be replaced by ServerPackCreator during the crea | SPC_JABBA_INSTALL_URL_PS_SPC | The URL to the PowerShell install-script for Jabba. | | SPC_JABBA_INSTALL_URL_SH_SPC | The URL to the Shell install-script for Jabba. | | SPC_JABBA_INSTALL_VERSION_SPC | The version of Jabba to install. | +| SPC_SERVERSTARTERJAR_FORCE_FETCH_SPC | Whether the ServerStarterJar, when using Forge or NeoForge, should be refreshed at every start. Also affects updates to newer versions. | +| SPC_SERVERSTARTERJAR_VERSION_SPC | The version of the ServerStarterJar to use. Set to 'latest' to always use the latest available version. | Jabba is a piece of software which makes the installation and usage of a JDK according to the system you are on very easy. It is used by the `install_java.xxx`-scripts to supply the correct Java version for your modded server should the criteria @@ -138,6 +140,9 @@ The contents of the variables are as follows. See `### Default values` above for | JDK_VENDOR | SPC_JDK_VENDOR_SPC | | JABBA_INSTALL_URL | SPC_JABBA_INSTALL_URL_PS_SPC or SPC_JABBA_INSTALL_URL_SH_SPC | | JABBA_INSTALL_VERSION | SPC_JABBA_INSTALL_VERSION_SPC | +| JABBA_INSTALL_VERSION | SPC_JABBA_INSTALL_VERSION_SPC | +| SERVERSTARTERJAR_FORCE_FETCH | SPC_SERVERSTARTERJAR_FORCE_FETCH_SPC | +| SERVERSTARTERJAR_VERSION | SPC_SERVERSTARTERJAR_VERSION_SPC | Plus any additional custom key-value pair you added to your server pack config. @@ -481,54 +486,56 @@ There are a couple more ways to use/run ServerPackCreator which may or may not b depending on how you plan on using it: ``` - -lang: Allows you to use one of the available languages for ServerPackCreator. I can not - guarantee that each of the following available languages is 100% translated. - You best choice is en_us, or not specifying any as that is the default, because - I write ServerPackCreator with english in mind. Available usages: - -lang en_us - -lang uk_ua - -lang de_de - - -cgen: Only available for the commandline interface. This will start the generation of - a new configuration file. You will be asked to enter information about your modpack - step-by-step. Each setting you enter will be checked for errors before it is saved. - If everything you enter is valid and without errors, it will be written to a new - serverpackcreator.conf and ServerPackCreator will immediately start a run with said - configuration file, generating a server pack for you. - --update: Check whether a new version of ServerPackCreator is available for download. - If an update is available, the version and link to the release of said update are - written to the console so you can from work with it from there. - Note: Automatic updates are currently not planned nor supported, and neither are - downloads of any available updates to your system. You need to update manually. - - -cli: Run ServerPackCreator in Command-line interface mode. Checks the serverpackcreator.conf - for errors and if none are found, starts the generation of a server pack with the configuration - provided by your serverpackcreator.conf. - - -web: Run ServerPackCreator as a webservice available at http://localhost:8080. The webservice - provides the same functionality as running ServerPackCreator in GUI mode (so no Commandline - arguments and a non-headless environment) as well as a REST API which can be used in different ways. - For more information about the REST API, please see the Java documentation: - - GitHub Pages: https://griefed.github.io/ServerPackCreator/ - - GitLab Pages: https://griefed.pages.griefed.de/ServerPackCreator/ - - -gui: Run ServerPackCreator using the graphical user interface. If your environment supports - graphics, i.e. is not headless, then this is the default mode in which ServerPackCreator - started as when no arguments are used. - ---setup: Set up and prepare the environment for subsequent runs of ServerPackCreator. - This will create/copy all files needed for ServerPackCreator to function - properly from inside its JAR-file and setup everything else, too. You can pass a properties-file, too - if you so desire. - Examples: - --setup "/path/to/custom.properties" - --setup "C:\path\to\custom.properties" - ---home: Override the home-directory setting for your user. - Examples: - --home "/path/to/directory" - --home "C:\users\<YOUR_USER>\SPC" + -lang: Allows you to use one of the available languages for ServerPackCreator. I can not + guarantee that each of the following available languages is 100% translated. + You best choice is en_us, or not specifying any as that is the default, because + I write ServerPackCreator with english in mind. Available usages: + -lang en_us + -lang uk_ua + -lang de_de + + -cgen: Only available for the commandline interface. This will start the generation of + a new configuration file. You will be asked to enter information about your modpack + step-by-step. Each setting you enter will be checked for errors before it is saved. + If everything you enter is valid and without errors, it will be written to a new + serverpackcreator.conf and ServerPackCreator will immediately start a run with said + configuration file, generating a server pack for you. + + -update: Check whether a new version of ServerPackCreator is available for download. + If an update is available, the version and link to the release of said update are + written to the console so you can from work with it from there. + Note: Automatic updates are currently not planned nor supported, and neither are + downloads of any available updates to your system. You need to update manually. + + -cli: Run ServerPackCreator in an interactive commandline-mode. + + -config: Generate a server pack from a specific server pack configuration from the commandline. + --destination: Only effective in combination with -config. Sets the destination in which the server pack + will be generated in. + + -web: Run ServerPackCreator as a webservice available at http://localhost:8080. The webservice + provides the same functionality as running ServerPackCreator in GUI mode (so no Commandline + arguments and a non-headless environment) as well as a REST API which can be used in different ways. + For more information about the REST API, please see the Java documentation: + - GitHub Pages: https://griefed.github.io/ServerPackCreator/ + - GitLab Pages: https://griefed.pages.griefed.de/ServerPackCreator/ + + -gui: Run ServerPackCreator using the graphical user interface. If your environment supports + graphics, i.e. is not headless, then this is the default mode in which ServerPackCreator + started as when no arguments are used. + + --setup: Set up and prepare the environment for subsequent runs of ServerPackCreator. + This will create/copy all files needed for ServerPackCreator to function + properly from inside its JAR-file and setup everything else, too. You can pass a properties-file, too + if you so desire. + Examples: + --setup "/path/to/custom.properties" + --setup "C:\path\to\custom.properties" + + --home: Override the home-directory setting for your user. + Examples: + --home "/path/to/directory" + --home "C:\users\<YOUR_USER>\SPC" ``` Each of these modes has its advantages and disadvantages. @@ -539,7 +546,7 @@ Each of these modes has its advantages and disadvantages. |:--------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------| | No need for a graphical environment. Can be used on a server to generate a server pack for immediate use. | Gathering of information for a configuration file is tedious. | | Step-by-Step generation of a configuration-file with the use of the `-cgen` argument. Generated config will be used immediately afterwards. | No convenience features file folder-browsing or jumping to the generated server pack after generation. | -| | Debugging in case of a broken/erroring configuration file can be time consuming. Careful reading of logs is required. | +| Automate using `-config`, and optionally `--destination`, in order to create a server pack from a specific config, in a specific location. | Debugging in case of a broken/erroring configuration file can be time consuming. Careful reading of logs is required. | | | Manual editing of the configuration-file in case you want to change it. | ### GUI: @@ -824,21 +831,21 @@ For a plugin to be accepted, you must at least provide: The serverpackcreator.conf file allows you to customize a couple of different things: -| Variable | Description | -|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| modpackDir | The path to the directory/ZIP-archive where your modpack resides in. | -| [[inclusions]] | Each inclusion-specification ensures that the file or directory from `source` gets included in your server pack one way or another.<br>A basic configuration usually contains the `mods` and `config` directories. No need to prefix them with the path to your modpack.<br>ServerPackCreator will take care of that automatically by itself.<br>If you want to include files or folders *outside* of your modpack, then you will need to specify the whole path.<br>Below are some examples for including files from your modpack (`mods` and `config`) as well as files and folders from outside the modpack.<br>[[inclusions]]<br> destination = ""<br> exclusionFilter = ""<br> source = "config"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = ""<br> exclusionFilter = ""<br> source = "mods"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "SomeFiles"<br> exclusionFilter = ""<br> source = "C:\\Some\\Path\\With\Files<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "somefiles"<br> exclusionFilter = ""<br> source = "/home/myuser/some/files"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "MyInstructions.md"<br> exclusionFilter = ""<br> source = "C:\\MyAwesomeModpack\\Stuff\\HowTo.md"br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "MyInstructions.md"<br> exclusionFilter = ""<br> source ="/home/myuser/my_awesome_modpack/HOWTO.md"<br> inclusionFilter = "" | -| [scripts]<br> SPC_JAVA_SPC = "java" | Path to the Java Installation. On Linux systems use `which java` to find the location of your Java install. On Windows use `where java` and exclude the `.exe`-part. Note, that changing this value only affects the *unzipped* server pack's `variables.txt`. The one in the *zipped* server pack is unaffected by this setting and will always point to `java` to increase compatibility with users who download the *zipped* server pack. | -| minecraftVersion | The version of Minecraft for which to install the modloader server. The same version of Minecraft your modpack uses. | -| modLoader | Which modloader to install. Must be either "Forge", "NeoForge", "Fabric", "Quilt" or "LegacyFabric". The same modloader your modpack uses. | -| modLoaderVersion | Specific Modloader version to install the server in the serverpack. The same version your modpack uses. | -| includeServerIcon | Whether to include server-icon.png in your serverpack. Must be `true` or `false`. | -| includeServerProperties | Whether to include server.properties in your serverpack. Must be `true` or `false`. | -| includeZipCreation | Whether to create a zip-file of your serverpack, saved in the directory you specified with `modpackDir`. Must be `true` or `false`. | -| javaArgs | JVM flags / Java Args to add to the generated start-scripts. Set to "empty" to not use any in your start-scripts. | -| serverPackSuffix | A suffix to append to the name of the server pack directory and server pack ZIP-archive. Illegal characters are / < > : " \ | ? * # % & { } $ ! ' @ + ´ \` = and must not end with a SPACE<code>  </code> or a DOT<code> .  </code> | -| serverIconPath | Path to a custom server-icon.png-file to include in the server pack. | -| serverPropertiesPath | Path to a custom server.properties-file to include in the server pack. | +| Variable | Description | +|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| modpackDir | The path to the directory/ZIP-archive where your modpack resides in. | +| [[inclusions]] | Each inclusion-specification ensures that the file or directory from `source` gets included in your server pack one way or another.<br>A basic configuration usually contains the `mods` and `config` directories. No need to prefix them with the path to your modpack.<br>ServerPackCreator will take care of that automatically by itself.<br>If you want to include files or folders *outside* of your modpack, then you will need to specify the whole path.<br>Below are some examples for including files from your modpack (`mods` and `config`) as well as files and folders from outside the modpack.<br>[[inclusions]]<br> destination = ""<br> exclusionFilter = "config/bluemap/.*"<br> source = "config"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = ""<br> exclusionFilter = ""<br> source = "mods"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "SomeFiles"<br> exclusionFilter = ""<br> source = "C:\\Some\\Path\\With\\Files"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "somefiles"<br> exclusionFilter = ""<br> source = "/home/myuser/some/files"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "MyInstructions.md"<br> exclusionFilter = ""<br> source = "C:\\MyAwesomeModpack\\Stuff\\HowTo.md"<br> inclusionFilter = ""<br>[[inclusions]]<br> destination = "MyInstructions.md"<br> exclusionFilter = ""<br> source ="/home/myuser/my_awesome_modpack/HOWTO.md"<br> inclusionFilter = "" | +| [scripts]<br> SPC_JAVA_SPC = "java" | Path to the Java Installation. On Linux systems use `which java` to find the location of your Java install. On Windows use `where java` and exclude the `.exe`-part. Note, that changing this value only affects the *unzipped* server pack's `variables.txt`. The one in the *zipped* server pack is unaffected by this setting and will always point to `java` to increase compatibility with users who download the *zipped* server pack. | +| minecraftVersion | The version of Minecraft for which to install the modloader server. The same version of Minecraft your modpack uses. | +| modLoader | Which modloader to install. Must be either "Forge", "NeoForge", "Fabric", "Quilt" or "LegacyFabric". The same modloader your modpack uses. | +| modLoaderVersion | Specific Modloader version to install the server in the serverpack. The same version your modpack uses. | +| includeServerIcon | Whether to include server-icon.png in your serverpack. Must be `true` or `false`. | +| includeServerProperties | Whether to include server.properties in your serverpack. Must be `true` or `false`. | +| includeZipCreation | Whether to create a zip-file of your serverpack, saved in the directory you specified with `modpackDir`. Must be `true` or `false`. | +| javaArgs | JVM flags / Java Args to add to the generated start-scripts. Set to "empty" to not use any in your start-scripts. | +| serverPackSuffix | A suffix to append to the name of the server pack directory and server pack ZIP-archive. Illegal characters are / < > : " \ | ? * # % & { } $ ! ' @ + ´ \` = and must not end with a SPACE<code>  </code> or a DOT<code> .  </code> | +| serverIconPath | Path to a custom server-icon.png-file to include in the server pack. | +| serverPropertiesPath | Path to a custom server.properties-file to include in the server pack. | ### serverpackcreator.properties diff --git a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/config/PackConfig.kt b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/config/PackConfig.kt index 3628e274d15361595380b520022074de2f4e51d1..0a3a907377527e5ed8c37395e54c404347d3d0a5 100644 --- a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/config/PackConfig.kt +++ b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/config/PackConfig.kt @@ -33,6 +33,9 @@ import org.apache.logging.log4j.kotlin.cachedLoggerOf import java.io.File import java.io.FileNotFoundException import java.nio.charset.StandardCharsets +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashMap private const val modpackComment = "\n Path to your modpack. Can be either relative or absolute." + @@ -230,6 +233,8 @@ open class PackConfig() { var modpackJson: JsonNode? = null var configVersion: String? = null + var customDestination: Optional<File> = Optional.empty() + open var projectID: String? = null open var versionID: String? = null open var source: ModpackSource = ModpackSource.DIRECTORY diff --git a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/serverpack/ServerPackHandler.kt b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/serverpack/ServerPackHandler.kt index ed030c249c18254a7404352e8c256135ac1ccf98..fe4ceec29e9e75e6558d00d051518aefa0b27960 100644 --- a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/serverpack/ServerPackHandler.kt +++ b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/serverpack/ServerPackHandler.kt @@ -287,7 +287,11 @@ class ServerPackHandler( val relativeFiles : ArrayList<String> = ArrayList(10000) val serverPackManifest: ServerPackManifest var serverPackZip: Optional<File> = Optional.empty() - val serverPack = File(getServerPackDestination(packConfig)) + val serverPack = if (packConfig.customDestination.isPresent) { + packConfig.customDestination.get() + } else { + File(getServerPackDestination(packConfig)) + } val existingManifest: File val oldManifest: ServerPackManifest var oldFile: File @@ -297,11 +301,6 @@ class ServerPackHandler( * Check whether the server pack for the specified modpack already exists and whether overwrite is disabled. * If the server pack exists and overwrite is disabled, no new server pack will be generated. */ - try { - serverPack.create(createFileOrDir = true, asDirectory = true) - } catch (ignored: IOException) { - } - if (apiProperties.isServerPacksOverwriteEnabled) { // Make sure no files from previously generated server packs interrupt us. cleanupEnvironment(true, serverPack.absolutePath) @@ -310,6 +309,11 @@ class ServerPackHandler( deleteExistingServerPackZip(serverPack.absolutePath) } + try { + serverPack.create(createFileOrDir = true, asDirectory = true) + } catch (ignored: IOException) { + } + if (apiProperties.isUpdatingServerPacksEnabled) { existingManifest = File(serverPack.absolutePath, "manifest.json") if (existingManifest.isFile) { @@ -333,21 +337,27 @@ class ServerPackHandler( // Recursively copy all specified directories and files, excluding clientside-only mods, to server pack. files.addAll( copyFiles( - packConfig, + packConfig.modpackDir, + packConfig.inclusions, + packConfig.clientMods, + packConfig.modsWhitelist, + packConfig.minecraftVersion, + serverPack.absolutePath, + packConfig.modloader, !(!apiProperties.isServerPacksOverwriteEnabled && !apiProperties.isUpdatingServerPacksEnabled) ) ) // If true, copy the server-icon.png from server_files to the server pack. if (packConfig.isServerIconInclusionDesired) { - copyIcon(packConfig) + copyIcon(serverPack.absolutePath, packConfig.serverIconPath) } else { log.info("Not including servericon.") } // If true, copy the server.properties from server_files to the server pack. if (packConfig.isServerPropertiesInclusionDesired) { - copyProperties(packConfig) + copyProperties(serverPack.absolutePath, packConfig.serverPropertiesPath) } else { log.info("Not including server.properties.") } @@ -375,8 +385,13 @@ class ServerPackHandler( * is present. This is because a ZIP-archive, if one is created, is supposed to be uploaded * to platforms like CurseForge. We must not have scripts with custom Java paths there. */ - createServerRunFiles(packConfig, false) - serverPackZip = zipBuilder(packConfig) + createServerRunFiles(packConfig.scriptSettings, serverPack.absolutePath, false) + serverPackZip = zipBuilder( + packConfig.minecraftVersion, + serverPack.absolutePath, + packConfig.modloader, + packConfig.modloaderVersion + ) } else { log.info("Not creating zip archive of serverpack.") } @@ -386,7 +401,7 @@ class ServerPackHandler( * The difference to the previous call is that these scripts respect the SPC_JAVA_SPC * placeholder setting, if the user has set one */ - createServerRunFiles(packConfig, true) + createServerRunFiles(packConfig.scriptSettings, serverPack.absolutePath, true) // Inform user about location of newly generated server pack. log.info("Server pack available at: ${serverPack.absolutePath}") @@ -413,19 +428,6 @@ class ServerPackHandler( ) } - /** - * Deletes all files, directories and ZIP-archives of previously generated server packs to ensure - * newly generated server pack is as clean as possible. This will completely empty the server pack - * directory, so use with caution! - * - * @param deleteZip Whether to delete the server pack ZIP-archive. - * @param packConfig ConfigurationModel containing the modpack directory from which the - * destination of the server pack is acquired. - * @author Griefed - */ - fun cleanupEnvironment(deleteZip: Boolean, packConfig: PackConfig) = - cleanupEnvironment(deleteZip, getServerPackDestination(packConfig)) - /** * Deletes all files, directories and ZIP-archives of previously generated server packs to ensure * newly generated server pack is as clean as possible. This will completely empty the server pack @@ -452,32 +454,6 @@ class ServerPackHandler( File(destination + "_server_pack.zip").deleteQuietly() } - /** - * Copies all specified directories and mods, excluding clientside-only mods, from the modpack - * directory into the server pack directory. If a `source/file;destination/file` - * -combination is provided, the specified source-file is copied to the specified - * destination-file. One of the reasons as to why it is recommended to run a given - * ConfigurationModel through the ConfigurationHandler first, is because the ConfigurationHandler - * will resolve links to their files first before then correcting the given - * ConfigurationModel. - * - * @param packConfig ConfigurationModel containing the modpack directory, list of - * directories and files to copy, list of clientside-only mods to - * exclude, the Minecraft version used by the modpack and server pack, - * and the modloader used by the modpack and server pack. - * @author Griefed - */ - fun copyFiles(packConfig: PackConfig, overwrite: Boolean = true) = copyFiles( - packConfig.modpackDir, - packConfig.inclusions, - packConfig.clientMods, - packConfig.modsWhitelist, - packConfig.minecraftVersion, - getServerPackDestination(packConfig), - packConfig.modloader, - overwrite - ) - /** * Copies all specified directories and mods, excluding clientside-only mods, from the modpack * directory into the server pack directory. If a `source/file;destination/file` @@ -562,72 +538,6 @@ class ServerPackHandler( return copiedFiles } - /** - * Download and provide the improved Fabric Server Launcher, if it is available for the given - * Minecraft and Fabric version. - * - * @param packConfig ConfigurationModel containing the Minecraft and Fabric version for - * which to acquire the improved Fabric Server Launcher. - * @author Griefed - */ - fun provideImprovedFabricServerLauncher(packConfig: PackConfig) = getImprovedFabricLauncher( - packConfig.minecraftVersion, packConfig.modloaderVersion, getServerPackDestination(packConfig) - ) - - /** - * Copies the server-icon.png into server pack. The sever-icon is automatically scaled to a - * resolution of 64x64 pixels. - * - * @param packConfig Containing the modpack directory to acquire the destination of the - * server pack and the path to the server icon to copy. - * @author Griefed - */ - fun copyIcon(packConfig: PackConfig) = copyIcon(getServerPackDestination(packConfig), packConfig.serverIconPath) - - /** - * Copies the server.properties into server pack. - * - * @param packConfig Containing the modpack directory to acquire the destination of the - * server pack and the path to the server properties to copy. - * @author Griefed - */ - fun copyProperties(packConfig: PackConfig) = - copyProperties(getServerPackDestination(packConfig), packConfig.serverPropertiesPath) - - /** - * Create start-scripts for the generated server pack using the templates the user has defined for - * their instance of ServerPackCreator. - * - * @param packConfig Configuration model containing modpack specific values. keys to be - * replaced with their respective values in the start scripts, as well - * as the modpack directory from which the destination of the server - * pack is acquired. - * @param isLocal Whether the start scripts should be created for a locally usable - * server pack. Use `false` if the start scripts should be created - * for a server pack about to be zipped. - * @author Griefed - */ - fun createServerRunFiles(packConfig: PackConfig, isLocal: Boolean) = - createServerRunFiles(packConfig.scriptSettings, getServerPackDestination(packConfig), isLocal) - - /** - * Creates a ZIP-archive of the server pack previously generated. Depending on the property - * `de.griefed.serverpackcreator.serverpack.zip.exclude.enabled`, files will be excluded. To customize - * the files which will be excluded, see the property `de.griefed.serverpackcreator.serverpack.zip.exclude` - * - * @param packConfig Contains the Minecraft version used by the modpack and server pack, - * whether the modloader server was installed, the modpack directory to - * acquire the destination of the server pack, the modloader used by the - * modpack and server pack and the modloader version. - * @author Griefed - */ - fun zipBuilder(packConfig: PackConfig) = zipBuilder( - packConfig.minecraftVersion, - getServerPackDestination(packConfig), - packConfig.modloader, - packConfig.modloaderVersion - ) - fun getServerFiles( inclusion: InclusionSpecification, modpackDir: String, @@ -1393,17 +1303,6 @@ class ServerPackHandler( } } - /** - * Cleans up the server_pack directory by deleting left-over files from modloader installations - * and version checking. - * - * @param packConfig Containing the Minecraft version used by the modpack and server pack, - * the modloader version used by the modpack and server pack and the - * modpack directory to acquire the destination of the server pack. - * @author Griefed - */ - fun cleanUpServerPack(packConfig: PackConfig) = postInstallCleanup(getServerPackDestination(packConfig)) - /** * Go through the mods in the modpack and exclude any of the user-specified clientside-only mods * according to the filter method set in the serverpackcreator.properties. For available filters, diff --git a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/utilities/common/SystemUtilities.kt b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/utilities/common/SystemUtilities.kt index 5d95bd042d2eb7aa4a2347fe7470a6f716594495..75569f4ac387f5516f5d993aaf3d80bda6e4df9d 100644 --- a/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/utilities/common/SystemUtilities.kt +++ b/serverpackcreator-api/src/main/kotlin/de/griefed/serverpackcreator/api/utilities/common/SystemUtilities.kt @@ -21,6 +21,7 @@ package de.griefed.serverpackcreator.api.utilities.common import org.apache.logging.log4j.kotlin.cachedLoggerOf import java.io.File +import java.util.* /** * Utility-class revolving around the system we are running on. @@ -36,6 +37,12 @@ class SystemUtilities { private val javaPathSuffix = "%s${File.separator}bin${File.separator}java" private val javaHome = System.getProperty("java.home") + private val OS: String = System.getProperty("os.name").lowercase(Locale.getDefault()) + val IS_WINDOWS: Boolean = (OS.indexOf("win") >= 0) + val IS_MAC: Boolean = (OS.indexOf("mac") >= 0) + val IS_UNIX: Boolean = (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0) + val IS_SOLARIS: Boolean = (OS.indexOf("sunos") >= 0) + /** * Automatically acquire the path to the systems default Java installation. * diff --git a/serverpackcreator-api/src/main/resources/de/griefed/resources/cli_help.txt b/serverpackcreator-api/src/main/resources/de/griefed/resources/cli_help.txt index ce7afabf92334fb2e42e0ed2186f9739f8cff85c..3255b9942c52baa305d85a275f17e3419f84b8e8 100644 --- a/serverpackcreator-api/src/main/resources/de/griefed/resources/cli_help.txt +++ b/serverpackcreator-api/src/main/resources/de/griefed/resources/cli_help.txt @@ -7,54 +7,56 @@ How to use ServerPackCreator: mode will automatically be used. Extra arguments to use ServerPackCreator with: # - -lang: Allows you to use one of the available languages for ServerPackCreator. I can not - guarantee that each of the following available languages is 100% translated. - You best choice is en_us, or not specifying any as that is the default, because - I write ServerPackCreator with english in mind. Available usages: - -lang en_us - -lang uk_ua - -lang de_de - - -cgen: Only available for the commandline interface. This will start the generation of - a new configuration file. You will be asked to enter information about your modpack - step-by-step. Each setting you enter will be checked for errors before it is saved. - If everything you enter is valid and without errors, it will be written to a new - serverpackcreator.conf and ServerPackCreator will immediately start a run with said - configuration file, generating a server pack for you. - - -update: Check whether a new version of ServerPackCreator is available for download. - If an update is available, the version and link to the release of said update are - written to the console so you can from work with it from there. - Note: Automatic updates are currently not planned nor supported, and neither are - downloads of any available updates to your system. You need to update manually. - - -cli: Run ServerPackCreator in Command-line interface mode. Checks the serverpackcreator.conf - for errors and if none are found, starts the generation of a server pack with the configuration - provided by your serverpackcreator.conf. - - -web: Run ServerPackCreator as a webservice available at http://localhost:8080. The webservice - provides the same functionality as running ServerPackCreator in GUI mode (so no Commandline - arguments and a non-headless environment) as well as a REST API which can be used in different ways. - For more information about the REST API, please see the Java documentation: - - GitHub Pages: https://griefed.github.io/ServerPackCreator/ - - GitLab Pages: https://griefed.pages.griefed.de/ServerPackCreator/ - - -gui: Run ServerPackCreator using the graphical user interface. If your environment supports - graphics, i.e. is not headless, then this is the default mode in which ServerPackCreator - started as when no arguments are used. - - --setup: Set up and prepare the environment for subsequent runs of ServerPackCreator. - This will create/copy all files needed for ServerPackCreator to function - properly from inside its JAR-file and setup everything else, too. You can pass a properties-file, too - if you so desire. - Examples: - --setup "/path/to/custom.properties" - --setup "C:\path\to\custom.properties" - - --home: Override the home-directory setting for your user. - Examples: - --home "/path/to/directory" - --home "C:\users\<YOUR_USER>\SPC" + -lang: Allows you to use one of the available languages for ServerPackCreator. I can not + guarantee that each of the following available languages is 100% translated. + You best choice is en_us, or not specifying any as that is the default, because + I write ServerPackCreator with english in mind. Available usages: + -lang en_us + -lang uk_ua + -lang de_de + + -cgen: Only available for the commandline interface. This will start the generation of + a new configuration file. You will be asked to enter information about your modpack + step-by-step. Each setting you enter will be checked for errors before it is saved. + If everything you enter is valid and without errors, it will be written to a new + serverpackcreator.conf and ServerPackCreator will immediately start a run with said + configuration file, generating a server pack for you. + + -update: Check whether a new version of ServerPackCreator is available for download. + If an update is available, the version and link to the release of said update are + written to the console so you can from work with it from there. + Note: Automatic updates are currently not planned nor supported, and neither are + downloads of any available updates to your system. You need to update manually. + + -cli: Run ServerPackCreator in an interactive commandline-mode. + + -config: Generate a server pack from a specific server pack configuration from the commandline. + --destination: Only effective in combination with -config. Sets the destination in which the server pack + will be generated in. + + -web: Run ServerPackCreator as a webservice available at http://localhost:8080. The webservice + provides the same functionality as running ServerPackCreator in GUI mode (so no Commandline + arguments and a non-headless environment) as well as a REST API which can be used in different ways. + For more information about the REST API, please see the Java documentation: + - GitHub Pages: https://griefed.github.io/ServerPackCreator/ + - GitLab Pages: https://griefed.pages.griefed.de/ServerPackCreator/ + + -gui: Run ServerPackCreator using the graphical user interface. If your environment supports + graphics, i.e. is not headless, then this is the default mode in which ServerPackCreator + started as when no arguments are used. + + --setup: Set up and prepare the environment for subsequent runs of ServerPackCreator. + This will create/copy all files needed for ServerPackCreator to function + properly from inside its JAR-file and setup everything else, too. You can pass a properties-file, too + if you so desire. + Examples: + --setup "/path/to/custom.properties" + --setup "C:\path\to\custom.properties" + + --home: Override the home-directory setting for your user. + Examples: + --home "/path/to/directory" + --home "C:\users\<YOUR_USER>\SPC" Support: diff --git a/serverpackcreator-api/src/test/resources/serverpackcreator.properties b/serverpackcreator-api/src/test/resources/serverpackcreator.properties index 7080d8135fad5cffed96a3bba005fb05e4d7d2e8..74c75d83153fb3d3a3b734f04760085dd99c151a 100644 --- a/serverpackcreator-api/src/test/resources/serverpackcreator.properties +++ b/serverpackcreator-api/src/test/resources/serverpackcreator.properties @@ -1,15 +1,16 @@ #For details about each property, see https://help.serverpackcreator.de/settings-and-configs.html -#Wed Aug 28 11:18:42 CEST 2024 +#Sat Sep 21 15:40:30 CEST 2024 de.griefed.serverpackcreator.configuration.aikar=-Xms4G -Xmx4G -XX\:+UseG1GC -XX\:+ParallelRefProcEnabled -XX\:MaxGCPauseMillis\=200 -XX\:+UnlockExperimentalVMOptions -XX\:+DisableExplicitGC -XX\:+AlwaysPreTouch -XX\:G1NewSizePercent\=30 -XX\:G1MaxNewSizePercent\=40 -XX\:G1HeapRegionSize\=8M -XX\:G1ReservePercent\=20 -XX\:G1HeapWastePercent\=5 -XX\:G1MixedGCCountTarget\=4 -XX\:InitiatingHeapOccupancyPercent\=15 -XX\:G1MixedGCLiveThresholdPercent\=90 -XX\:G1RSetUpdatingPauseTimePercent\=5 -XX\:SurvivorRatio\=32 -XX\:+PerfDisableSharedMem -XX\:MaxTenuringThreshold\=1 -Dusing.aikars.flags\=https\://mcflags.emc.gs -Daikars.new.flags\=true de.griefed.serverpackcreator.configuration.directories.mustinclude=mods,config,kubejs,defaultconfigs,scripts de.griefed.serverpackcreator.configuration.directories.shouldexclude=overrides,packmenu,resourcepacks,server_pack,fancymenu,libraries,downloads,logs,profileImage,resourcepacks,screenshots,shaderpacks,tv-cache,asm de.griefed.serverpackcreator.configuration.fallback.updateurl=https\://raw.githubusercontent.com/Griefed/ServerPackCreator/main/serverpackcreator-api/src/main/resources/serverpackcreator.properties -de.griefed.serverpackcreator.configuration.fallbackmodslist=Ping-Wheel- +de.griefed.serverpackcreator.configuration.fallbackmodslist=3dskinlayers-,Absolutely-Not-A-Zoom-Mod-,AdvancedChat-,AdvancedChatCore-,AdvancedChatHUD-,AdvancedCompas-,Ambience,AmbientEnvironment-,AmbientSounds_,AnimaticaReforged-,AreYouBlind-,Armor Status HUD-,ArmorSoundTweak-,BH-Menu-,Batty's Coordinates PLUS Mod,BetterAdvancements-,BetterAnimationsCollection-,BetterDarkMode-,BetterF3-,BetterFog-,BetterFoliage-,BetterModsButton-,BetterPingDisplay-,BetterPlacement-,BetterTaskbar-,BetterThirdPerson,BetterTitleScreen-,Blur-,BorderlessWindow-,CTM-,Chat Ping ,ChunkAnimator-,Clear-Water-,ClientTweaks_,CompletionistsIndex-,Controller Support-,Controlling-,CraftPresence-,CullLessLeaves-,CustomCursorMod-,CustomMainMenu-,DefaultOptions_,DefaultSettings-,DeleteWorldsToTrash-,DetailArmorBar-,Ding-,DistantHorizons-,DripSounds-,Durability101-,DurabilityNotifier-,DynamicSurroundings-,DynamicSurroundingsHuds-,EasyLAN-,EffectsLeft-,EiraMoticons_,EnchantmentDescriptions-,EnhancedVisuals_,EquipmentCompare-,EuphoriaPatcher-,FPS-Monitor-,FabricCustomCursorMod-,FadingNightVision-,Fallingleaves-,FancySpawnEggs,FancyVideo-API-,FirstPersonMod,FogTweaker-,ForgeCustomCursorMod-,FpsReducer-,FpsReducer2-,FullscreenWindowed-,GameMenuModOption-,HealthOverlay-,HeldItemTooltips-,HorseStatsMod-,ImmediatelyFast-,ImmediatelyFastReforged-,InventoryEssentials_,InventoryHud_,InventorySpam-,InventoryTweaks-,ItemBorders-,ItemLocks-,ItemPhysicLite_,ItemStitchingFix-,JBRA-Client-,JustEnoughCalculation-,JustEnoughEffects-,JustEnoughProfessions-,LLOverlayReloaded-,LOTRDRP-,LeaveMyBarsAlone-,LegendaryTooltips,LegendaryTooltips-,LightOverlay-,MineMenu-,MinecraftCapes,MinecraftCapes ,MoBends,ModernUI-,MouseTweaks-,MyServerIsCompatible-,Neat,Neat ,Neat-,NekosEnchantedBooks-,NoAutoJump-,NoFog-,Notes-,NotifMod-,OldJavaWarning-,OptiFine,OptiFine_,OptiForge,OptiForge-,OverflowingBars-,PackMenu-,PackModeMenu-,PickUpNotifier-,Ping-,PingHUD-,PresenceFootsteps-,RPG-HUD-,ReAuth-,Reforgium-,ResourceLoader-,ResourcePackOrganizer,RyoamicLights-,Ryoamiclights-,ShoulderSurfing-,ShulkerTooltip-,SimpleDiscordRichPresence-,SimpleWorldTimer-,SoundFilters-,SpawnerFix-,StylishEffects-,TRansliterationLib-,TextruesRubidiumOptions-,TipTheScales-,Tips-,Toast Control-,Toast-Control-,ToastControl-,TravelersTitles-,VR-Combat_,VoidFog-,WindowedFullscreen-,WorldNameRandomizer-,YeetusExperimentus-,YungsMenuTweaks-,[1.12.2]DamageIndicatorsMod-,[1.12.2]bspkrscore-,antighost-,anviltooltipmod-,armorchroma-,armorpointspp-,auditory-,authme-,auto-reconnect-,autojoin-,autoreconnect-,axolotl-item-fix-,backtools-,bannerunlimited-,beenfo-,better-clouds-,better-recipe-book-,betterbiomeblend-,bhmenu-,blur-,borderless-mining-,cat_jam-,catalogue-,cfwinfo-,charmonium-,chat_heads-,cherishedworlds-,cirback-1.0-,classicbar-,clickadv-,clienttweaks-,combat_music-,connectedness-,controllable-,cullleaves-,cullparticles-,custom-crosshair-mod-,customdiscordrpc-,darkness-,dashloader-,defaultoptions-,desiredservers-,discordrpc-,drippyloadingscreen-,drippyloadingscreen_,durabilitytooltip-,dynamic-fps-,dynamic-music-,dynamiclights-,dynamiclightsreforged-,dynmus-,e4mc-,effective-,eggtab-,eguilib-,eiramoticons-,embeddium-,enchantment-lore-,entity-texture-features-,entityculling-,essential_,exhaustedstamina-,extremesoundmuffler-,fabricemotes-,fabricmod_VoxelMap-,fancymenu_,fancymenu_video_extension,farsight-,fast-ip-ping-,firstperson-,flickerfix-,fm_audio_extension_,forgemod_VoxelMap-,freecam-,freelook-,galacticraft-rpc-,gamestagesviewer-,gpumemleakfix-,grid-,helium-,hiddenrecipebook-,hiddenrecipebook_,infinitemusic-,inventoryhud.,inventoryprofiles,invtweaks-,itemzoom,itlt-,jeed-,jehc-,jeiintegration_,jumpoverfences-,just-enough-harvestcraft-,justenoughbeacons-,justenoughdrags-,justzoom_,keymap-,keywizard-,lazurite-,lazydfu-,lib39-,light-overlay-,lightfallclient-,lightspeed-,loadmyresources_,lock_minecart_view-,lootbeams-,lwl-,macos-input-fixes-,magnesium_extras-,maptooltip-,massunbind,mcbindtype-,mcwifipnp-,medievalmusic-,memoryusagescreen-,mightyarchitect-,mindful-eating-,minetogether-,mobplusplus-,modcredits-,modernworldcreation_,modnametooltip-,modnametooltip_,moreoverlays-,mousewheelie-,movement-vision-,multihotbar-,music-duration-reducer-,musicdr-,neiRecipeHandlers-,ngrok-lan-expose-mod-,no_nv_flash-,nopotionshift_,notenoughanimations-,oculus-,ornaments-,overloadedarmorbar-,panorama-,paperdoll-,phosphor-,physics-mod-,preciseblockplacing-,radon-,realm-of-lost-souls-,rebind-narrator-,rebind_narrator-,rebindnarrator-,rebrand-,reforgium-,replanter-,rrls-,rubidium-,rubidium_extras-,screenshot-to-clipboard-,servercountryflags-,shutupexperimentalsettings-,shutupmodelloader-,signtools-,simple-rpc-,simpleautorun-,skinlayers3d-forge,smartcursor-,smarthud-,smoothboot-,smoothfocus-,sodium-fabric-,sodiumdynamiclights-,sounddeviceoptions-,soundreloader-,spoticraft-,tconplanner-,textrues_embeddium_options-,timestamps-,tooltipscroller-,torchoptimizer-,torohealth-,totaldarkness,toughnessbar-,watermedia-,whats-that-slot-forge-,wisla-,xenon-,xlifeheartcolors-,yisthereautojump- de.griefed.serverpackcreator.configuration.hastebinserver=https\://haste.zneix.eu/documents de.griefed.serverpackcreator.configuration.modswhitelist=Ping-Wheel- de.griefed.serverpackcreator.firstrun=false de.griefed.serverpackcreator.java=C\:\\Program Files\\Eclipse Adoptium\\jdk-21.0.3.9-hotspot\\bin\\java.exe de.griefed.serverpackcreator.language=en_GB +de.griefed.serverpackcreator.loglevel=DEBUG de.griefed.serverpackcreator.minecraft.snapshots=true de.griefed.serverpackcreator.script.java.autoupdate=true de.griefed.serverpackcreator.serverpack.autodiscovery.enabled=false @@ -23,5 +24,5 @@ de.griefed.serverpackcreator.spring.schedules.database.cleanup=0 0 0 * * * de.griefed.serverpackcreator.spring.schedules.files.cleanup=0 30 0 * * * de.griefed.serverpackcreator.spring.schedules.versions.refresh=0 0 0 * * * de.griefed.serverpackcreator.versioncheck.prerelease=false -server.tomcat.basedir=F\:\\GitLab\\ServerPackCreator\\serverpackcreator-api\\tests +server.tomcat.basedir=F\:\\GitLab\\ServerPackCreator\\serverpackcreator-app\\tests spring.datasource.url=jdbc\:postgresql\://localhost\:5432/serverpackcreator diff --git a/serverpackcreator-app/build.gradle.kts b/serverpackcreator-app/build.gradle.kts index f176c25b7b63b5309e5b7ff7c51f49b040b8fbfd..70b6deb27365e8f470ea3d68706b508b653119b0 100644 --- a/serverpackcreator-app/build.gradle.kts +++ b/serverpackcreator-app/build.gradle.kts @@ -32,6 +32,9 @@ configurations { dependencies { api(project(":serverpackcreator-api")) + //CLI + api("info.picocli:picocli-shell-jline3:4.7.6") + //GUI api("commons-io:commons-io:2.16.1") api("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.8.0") diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/CommandlineParser.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/CommandlineParser.kt index 6ec5f2ccfe1068e233e33016ce691a897de506b4..08891be19aef5468035f2dde12a10347006c673f 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/CommandlineParser.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/CommandlineParser.kt @@ -53,6 +53,8 @@ open class CommandlineParser(args: Array<String>, appInfo: JarInformation) { } else { File(appInfo.jarFolder, "serverpackcreator.properties") } + var serverPackConfig : Optional<File> = Optional.empty() + var serverPackDestination : Optional<File> = Optional.empty() var homeDir: Optional<File> = Optional.empty() @@ -113,6 +115,28 @@ open class CommandlineParser(args: Array<String>, appInfo: JarInformation) { return@run } + /* + * Check whether the user wants to generate a specific server pack config from the commandline. + */ + if (argsList.any { entry -> entry.contains(Mode.CONFIG.argument()) }) { + val confPos = argsList.indexOf(Mode.CONFIG.argument()) + 1 + val confArg = argsList[confPos] + val confFile = File(confArg) + if (argsList.size > 1 && confFile.isFile) { + serverPackConfig = Optional.of(confFile) + } + + if (argsList.any { entry -> entry.contains(Mode.DESTINATION.argument()) }) { + val destPos = argsList.indexOf(Mode.DESTINATION.argument()) + 1 + val destArg = argsList[destPos] + val destFile = File(destArg) + serverPackDestination = Optional.of(destFile) + } + + mode = Mode.CONFIG + return@run + } + /* * Check whether the user wants to run in commandline-mode or whether a GUI would not be supported. */ diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/Mode.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/Mode.kt index 88fb71f7849d3986ab4a632eccc5e7ea9e443179..a1818009e874259827182d53897687849b626e3a 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/Mode.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/Mode.kt @@ -54,6 +54,23 @@ enum class Mode(private val argument: String) { * **Priority 3** * * + * Run ServerPackCreator from the commandline and generate a server pack from a specific server pack config. + */ + CONFIG("-config"), + + /** + * **Priority 3.1** + * + * + * Generate the server pack from the config specified in [CONFIG] in a specific location. + * This argument requires [CONFIG] being present, too. + */ + DESTINATION("--destination"), + + /** + * **Priority 4** + * + * * Run ServerPackCreator in commandline-mode. If no graphical environment is supported, this is * the default ServerPackCreator will enter, even when starting ServerPackCreator with no extra * arguments at all. @@ -61,7 +78,7 @@ enum class Mode(private val argument: String) { CLI("-cli"), /** - * **Priority 4** + * **Priority 5** * * * Run ServerPackCreator as a webservice. @@ -69,7 +86,7 @@ enum class Mode(private val argument: String) { WEB("-web"), /** - * **Priority 5** + * **Priority 6** * * * Run ServerPackCreator with our GUI. If a graphical environment is supported, this is the @@ -79,7 +96,7 @@ enum class Mode(private val argument: String) { GUI("-gui"), /** - * **Priority 6** + * **Priority 7** * * * Set up and prepare the environment for subsequent runs of ServerPackCreator. This will @@ -102,7 +119,7 @@ enum class Mode(private val argument: String) { HOME("--home"), /** - * **Priority 7** + * **Priority 8** * * * Exit ServerPackCreator. diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/ServerPackCreator.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/ServerPackCreator.kt index 9139fbf2ffd4e8d6e088d2c53d4e9e9de2670c39..6bf977fd4816742f99654621ea1bc3be1d11d179 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/ServerPackCreator.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/ServerPackCreator.kt @@ -25,11 +25,9 @@ import com.formdev.flatlaf.fonts.jetbrains_mono.FlatJetBrainsMonoFont import com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDarkerIJTheme import de.comahe.i18n4k.Locale import de.griefed.serverpackcreator.api.ApiWrapper -import de.griefed.serverpackcreator.api.config.PackConfig import de.griefed.serverpackcreator.api.utilities.common.JarInformation import de.griefed.serverpackcreator.api.utilities.common.JarUtilities -import de.griefed.serverpackcreator.api.utilities.common.readText -import de.griefed.serverpackcreator.app.cli.ConfigurationEditor +import de.griefed.serverpackcreator.app.cli.InteractiveCommandLine import de.griefed.serverpackcreator.app.gui.MainWindow import de.griefed.serverpackcreator.app.gui.splash.SplashScreen import de.griefed.serverpackcreator.app.updater.MigrationManager @@ -49,8 +47,6 @@ import java.util.prefs.Preferences import javax.swing.JFileChooser import javax.swing.JOptionPane import javax.xml.parsers.ParserConfigurationException -import kotlin.system.exitProcess - /** * Entry point for the app. Creates a new instance of [ServerPackCreator] and executes [ServerPackCreator.run] with the @@ -126,43 +122,33 @@ class ServerPackCreator(private val args: Array<String>) { } @get:Synchronized - val configurationEditor: ConfigurationEditor by lazy { - ConfigurationEditor( - apiWrapper.configurationHandler, - apiWrapper.apiProperties, - apiWrapper.utilities, - apiWrapper.versionMeta - ) + val interactiveCommandLine: InteractiveCommandLine by lazy { + InteractiveCommandLine(apiWrapper, updateChecker) } fun run(mode: Mode = Mode.GUI) { log.info("Running with args: ${args.joinToString(" ")}") - log.info("Running in mode: $mode") + log.info("Running in mode: $mode") log.info("App information:") - log.info("App Folder: ${appInfo.jarFolder}") - log.info("App File: ${appInfo.jarFile}") - log.info("App Path: ${appInfo.jarPath}") - log.info("App Name: ${appInfo.jarFileName}") - log.info("Java version: ${apiWrapper.apiProperties.getJavaVersion()}") - log.info("OS architecture: ${apiWrapper.apiProperties.getOSArch()}") - log.info("OS name: ${apiWrapper.apiProperties.getOSName()}") - log.info("OS version: ${apiWrapper.apiProperties.getOSVersion()}") + log.info("App Folder: ${appInfo.jarFolder}") + log.info("Appy File: ${appInfo.jarFile}") + log.info("App Path: ${appInfo.jarPath}") + log.info("App Name: ${appInfo.jarFileName}") + log.info("Java version: ${apiWrapper.apiProperties.getJavaVersion()}") + log.info("OS architecture: ${apiWrapper.apiProperties.getOSArch()}") + log.info("OS name: ${apiWrapper.apiProperties.getOSName()}") + log.info("OS version: ${apiWrapper.apiProperties.getOSVersion()}") when (mode) { Mode.HELP -> { - System.setProperty("java.awt.headless", "true") - printHelp() - continuedRunOptions() + interactiveCommandLine.helpCommand.run() } Mode.UPDATE -> { - System.setProperty("java.awt.headless", "true") - updateChecker.updateCheck(true) - continuedRunOptions() + interactiveCommandLine.updateCommand.run() } Mode.WEB -> { - System.setProperty("java.awt.headless", "true") apiWrapper.stageOne() migrationManager.migrate() apiWrapper.stageTwo() @@ -172,22 +158,29 @@ class ServerPackCreator(private val args: Array<String>) { } Mode.CGEN -> { - System.setProperty("java.awt.headless", "true") apiWrapper.stageOne() migrationManager.migrate() apiWrapper.stageTwo() - createDefaultConfig() - runConfigurationEditor() - continuedRunOptions() + interactiveCommandLine.configGenCommand.run() + } + + Mode.CONFIG -> { + apiWrapper.stageOne() + migrationManager.migrate() + apiWrapper.stageTwo() + apiWrapper.stageThree() + interactiveCommandLine.runHeadlessCommand.runHeadless( + commandlineParser.serverPackConfig.get(), + commandlineParser.serverPackDestination + ) } Mode.CLI -> { - System.setProperty("java.awt.headless", "true") apiWrapper.stageOne() migrationManager.migrate() apiWrapper.stageTwo() apiWrapper.stageThree() - runHeadless() + interactiveCommandLine.run(args) } Mode.GUI -> { @@ -210,8 +203,7 @@ class ServerPackCreator(private val args: Array<String>) { } Mode.SETUP -> { - System.setProperty("java.awt.headless", "true") - apiWrapper.setup(force = true) + interactiveCommandLine.setupCommand.run() log.info("Setup completed.") log.debug("Exiting...") } @@ -221,202 +213,6 @@ class ServerPackCreator(private val args: Array<String>) { } } - /** - * Check whether a `serverpackcreator.conf`-file exists. If it doesn't exist, and we are not - * running in [Mode.CLI] or [Mode.CGEN], create an unconfigured default one which can - * then be loaded into the GUI. - * - * @return `true` if a `serverpackcreator.conf`-file was created. - * @author Griefed - */ - private fun createDefaultConfig(): Boolean { - return if (!apiWrapper.apiProperties.defaultConfig.exists()) { - JarUtilities.copyFileFromJar( - "de/griefed/resources/${apiWrapper.apiProperties.defaultConfig.name}", - apiWrapper.apiProperties.defaultConfig, this.javaClass - ) - } else { - false - } - } - - /** - * Prints the help-text to the console. The help text contains information about: - * - * * running ServerPackCreator in different modes: - * - * * [Mode.CGEN] - * * [Mode.UPDATE] - * * [Mode.CLI] - * * [Mode.WEB] - * * [Mode.GUI] - * * [Mode.SETUP] - * - * * available languages - * * where to report issues - * * where to get support - * * where to find the wiki - * * how to support me - * - * - * @author Griefed - */ - private fun printHelp() { - try { - println( - this.javaClass.getResourceAsStream("/de/griefed/resources/cli_help.txt")!!.readText() - ) - } catch (e: IOException) { - throw RuntimeException(e) - } - } - - /** - * Print the text-menu so the user may decide what they would like to do next. - * - * @author Griefed - */ - private fun printMenu() { - println() - println("What would you like to do next?") - println("(1) : Print help") - println("(2) : Check for updates") - println("(3) : Change locale") - println("(4) : Generate a new configuration") - println("(5) : Run ServerPackCreator in CLI-mode") - println("(6) : Run ServerPackCreator as a webservice") - println("(7) : Run ServerPackCreator with a GUI") - println("(0) : Exit") - println("-------------------------------------------") - print("Enter the number of your selection: ") - } - - /** - * Offer the user to continue using ServerPackCreator when running in [Mode.HELP], [Mode.UPDATE] or [Mode.CGEN]. - * - * @throws IOException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to - * be instantiated, but an error occurred during the parsing of a manifest. - * @throws ParserConfigurationException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to - * be instantiated, but an error occurred during the parsing of a manifest. - * @throws SAXException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to - * be instantiated, but an error occurred during the parsing of a manifest. - * @author Griefed - */ - @Throws(IOException::class, ParserConfigurationException::class, SAXException::class) - private fun continuedRunOptions() { - printMenu() - val scanner = Scanner(System.`in`) - var selection: Int - do { - try { - selection = scanner.nextInt() - if (selection == 7 && GraphicsEnvironment.isHeadless()) { - println("You environment does not support a GUI.") - selection = 100 - } - when (selection) { - 1 -> { - printHelp() - printMenu() - selection = 100 - } - - 2 -> { - updateChecker.updateCheck(true) - printMenu() - selection = 100 - } - - 3 -> { - changeLocale() - printMenu() - selection = 100 - } - - 4 -> { - runConfigurationEditor() - printMenu() - selection = 100 - } - - else -> if (selection > 7) { - println("Not a valid number. Please pick a number from 0 to 7.") - printMenu() - } - } - } catch (ex: InputMismatchException) { - println("Not a valid number. Please pick a number from 0 to 7.") - selection = 100 - } catch (ex: ParserConfigurationException) { - println("Not a valid number. Please pick a number from 0 to 7.") - selection = 100 - } catch (ex: SAXException) { - println("Not a valid number. Please pick a number from 0 to 7.") - selection = 100 - } - } while (selection > 7) - scanner.close() - when (selection) { - 5 -> run(Mode.CLI) - 6 -> run(Mode.WEB) - 7 -> run(Mode.GUI) - 0 -> println("Exiting...") - else -> println("Exiting...") - } - } - - /** - * Run in [Mode.CGEN] and allow the user to load, edit and create a - * `serverpackcreator.conf`-file using the CLI. - * - * @throws IOException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @throws ParserConfigurationException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @throws SAXException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @author Griefed - */ - @Throws(IOException::class, ParserConfigurationException::class, SAXException::class) - private fun runConfigurationEditor() { - configurationEditor.continuedRunOptions() - } - - /** - * Run ServerPackCreator in [Mode.CLI]. Requires a `serverpackcreator.conf`-file to be - * present. - * - * @throws IOException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @throws ParserConfigurationException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @throws SAXException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but - * an error occurred during the parsing of a manifest. - * @author Griefed - */ - @Throws(IOException::class, ParserConfigurationException::class, SAXException::class) - private fun runHeadless() { - if (!apiWrapper.apiProperties.defaultConfig.exists()) { - log.warn("No serverpackcreator.conf found...") - log.info("If you want to run ServerPackCreator in CLI-mode, a serverpackcreator.conf is required.") - log.info( - "Either copy an existing config, or run ServerPackCreator with the '-cgen'-argument to generate one via commandline." - ) - exitProcess(1) - } else { - val packConfig = PackConfig() - if (!apiWrapper.configurationHandler.checkConfiguration( - apiWrapper.apiProperties.defaultConfig, packConfig - ).allChecksPassed - ) { - exitProcess(1) - } - if (!apiWrapper.serverPackHandler.run(packConfig).success) { - exitProcess(1) - } - } - } - @get:Synchronized var splashScreen: SplashScreen? = null get() { @@ -537,40 +333,4 @@ class ServerPackCreator(private val args: Array<String>) { log.debug("File-watcher started...") } } - - /** - * Allow the user to change the locale used in localization. - * - * @author Griefed - */ - private fun changeLocale() { - println("What locale would you like to use?") - println("(Locale format is en_gb, de_de, uk_ua etc.)") - println("Note: Changing the locale only affects the GUI. CLI always uses en_US.") - val scanner = Scanner(System.`in`) - val regex = "^[a-zA-Z]+_[a-zA-Z]+$".toRegex() - var userLocale: String - - // For a list of locales, see https://stackoverflow.com/a/3191729/12537638 or - // https://stackoverflow.com/a/28357857/12537638 - do { - userLocale = scanner.next() - if (!userLocale.matches(regex)) { - println( - "Incorrect format. ServerPackCreator currently only supports locales in the format of en_us (Language, Country)." - ) - } else { - try { - apiWrapper.apiProperties.i18n4kConfig.locale = Locale(userLocale) - } catch (e: RuntimeException) { - println( - "Incorrect format. ServerPackCreator currently only supports locales in the format of en_GB (Language, Country)." - ) - userLocale = "en_GB" - } - } - } while (!userLocale.matches(regex)) - scanner.close() - println("Using language: ${Translations.localeName}") - } } \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/ConfigurationEditor.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/ConfigurationEditor.kt index e9b033889c83ac8f9677c2dff1dff7dceb0c3162..0031c8e302ccd7e6c33070be8fe4243344e66277 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/ConfigurationEditor.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/ConfigurationEditor.kt @@ -29,7 +29,6 @@ import de.griefed.serverpackcreator.api.config.PackConfig import de.griefed.serverpackcreator.api.utilities.common.BooleanUtilities import de.griefed.serverpackcreator.api.utilities.common.ListUtilities import de.griefed.serverpackcreator.api.utilities.common.StringUtilities -import de.griefed.serverpackcreator.api.utilities.common.Utilities import de.griefed.serverpackcreator.api.versionmeta.VersionMeta import org.apache.logging.log4j.kotlin.cachedLoggerOf import java.io.File @@ -49,7 +48,6 @@ import kotlin.io.path.moveTo class ConfigurationEditor( private val configurationHandler: ConfigurationHandler, private val apiProperties: ApiProperties, - private val utilities: Utilities, private val versionMeta: VersionMeta ) { private val log by lazy { cachedLoggerOf(this.javaClass) } diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/InteractiveCommandLine.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/InteractiveCommandLine.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b1eac0bc58a4b2a44741ddcfbf91571d79c5c6c --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/InteractiveCommandLine.kt @@ -0,0 +1,156 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli + +import de.griefed.serverpackcreator.api.ApiWrapper +import de.griefed.serverpackcreator.app.cli.commands.* +import de.griefed.serverpackcreator.app.updater.UpdateChecker +import org.apache.logging.log4j.kotlin.cachedLoggerOf +import org.jline.builtins.ConfigurationPath +import org.jline.console.CmdLine +import org.jline.console.SystemRegistry +import org.jline.console.impl.Builtins +import org.jline.console.impl.SystemRegistryImpl +import org.jline.keymap.KeyMap +import org.jline.reader.* +import org.jline.reader.impl.DefaultParser +import org.jline.reader.impl.LineReaderImpl +import org.jline.terminal.TerminalBuilder +import org.jline.widget.TailTipWidgets +import org.jline.widget.TailTipWidgets.TipType +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands +import picocli.shell.jline3.PicocliCommands.ClearScreen +import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory +import java.io.PrintWriter +import java.nio.file.Path +import java.util.function.Supplier + +class InteractiveCommandLine(private val apiWrapper: ApiWrapper, updateChecker: UpdateChecker) { + + private val log by lazy { cachedLoggerOf(this.javaClass) } + + @get:Synchronized + val configurationEditor: ConfigurationEditor by lazy { + ConfigurationEditor( + apiWrapper.configurationHandler, + apiWrapper.apiProperties, + apiWrapper.versionMeta + ) + } + + val configGenCommand = ConfigGenCommand(apiWrapper, configurationEditor) + val helpCommand = HelpCommand() + val homeDirCommand = HomeDirCommand() + val languageCommand = LanguageCommand(apiWrapper) + val runHeadlessCommand = RunHeadlessCommand(apiWrapper) + val setupCommand = SetupCommand(apiWrapper) + val updateCommand = UpdateCommand(updateChecker) + + + @CommandLine.Command( + name = "", + description = ["Interactive shell with completion and autosuggestions."], + subcommands = [ + ConfigGenCommand::class, + HelpCommand::class, + HomeDirCommand::class, + LanguageCommand::class, + RunHeadlessCommand::class, + SetupCommand::class, + UpdateCommand::class, + ClearScreen::class, + CommandLine.HelpCommand::class + ] + ) + class CliCommands : Runnable { + private var reader: LineReaderImpl? = null + var out: PrintWriter? = null + + fun setReader(reader: LineReader) { + this.reader = reader as LineReaderImpl + out = reader.terminal.writer() + } + + override fun run() { + out!!.println(CommandLine(this).usageMessage) + } + } + + fun run(args: Array<String> = arrayOf("")) { + try { + val workDir: Supplier<Path> = Supplier<Path> { apiWrapper.apiProperties.homeDirectory.absoluteFile.toPath() } + val builtins = Builtins(workDir, ConfigurationPath(workDir.get(), workDir.get()), null) + builtins.rename(Builtins.Command.TTOP, "top") + builtins.alias("zle", "widget") + builtins.alias("bindkey", "keymap") + + val commands = CliCommands() + val factory = PicocliCommandsFactory() + val cmd = CommandLine(commands, factory) + val picocliCommands = PicocliCommands(cmd) + val parser: Parser = DefaultParser() + + TerminalBuilder.builder().build().use { terminal -> + val systemRegistry: SystemRegistry = SystemRegistryImpl(parser, terminal, workDir, null) + systemRegistry.setCommandRegistries(builtins, picocliCommands) + systemRegistry.register("help", picocliCommands) + + val reader = LineReaderBuilder.builder() + .terminal(terminal) + .completer(systemRegistry.completer()) + .parser(parser) + .variable(LineReader.LIST_MAX, 50) // max tab completion candidates + .build() + builtins.setLineReader(reader) + commands.setReader(reader) + factory.setTerminal(terminal) + val widgets = TailTipWidgets( + reader, + { line: CmdLine? -> systemRegistry.commandDescription(line) }, 5, TipType.COMPLETER + ) + widgets.enable() + val keyMap = reader.keyMaps["main"]!! + keyMap.bind(Reference("tailtip-toggle"), KeyMap.alt("s")) + + val prompt = "ServerPackCreator> " + val rightPrompt: String? = null + + // start the shell and process input until the user quits with Ctrl-D + var line: String? + while (true) { + try { + systemRegistry.cleanUp() + line = reader.readLine(prompt, rightPrompt, null as MaskingCallback?, null) + systemRegistry.execute(line) + } catch (e: UserInterruptException) { + // Ignore + } catch (e: EndOfFileException) { + return + } catch (e: Exception) { + systemRegistry.trace(e) + } + } + } + } catch (t: Throwable) { + log.error("Error initializing terminal.", t) + } + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/Command.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/Command.kt new file mode 100644 index 0000000000000000000000000000000000000000..bcd1bdf7f681e2adaec9740f2559e84cf6711922 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/Command.kt @@ -0,0 +1,24 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +interface Command : Runnable { + +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/ConfigGenCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/ConfigGenCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..94983763914351779dd9e402926b8d4119d27f51 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/ConfigGenCommand.kt @@ -0,0 +1,84 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import de.griefed.serverpackcreator.api.ApiWrapper +import de.griefed.serverpackcreator.api.utilities.common.JarUtilities +import de.griefed.serverpackcreator.app.Mode +import de.griefed.serverpackcreator.app.cli.ConfigurationEditor +import org.xml.sax.SAXException +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.io.IOException +import javax.xml.parsers.ParserConfigurationException + +@CommandLine.Command( + name = "cgen", mixinStandardHelpOptions = true, + description = ["Interactively generate a new server pack configuration."], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class ConfigGenCommand( + private val apiWrapper: ApiWrapper = ApiWrapper.api(), + private val configurationEditor: ConfigurationEditor = ConfigurationEditor( + apiWrapper.configurationHandler, + apiWrapper.apiProperties, + apiWrapper.versionMeta) +) : Command { + + override fun run() { + createDefaultConfig() + runConfigurationEditor() + } + + /** + * Run in [Mode.CGEN] and allow the user to load, edit and create a + * `serverpackcreator.conf`-file using the CLI. + * + * @throws IOException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but + * an error occurred during the parsing of a manifest. + * @throws ParserConfigurationException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but + * an error occurred during the parsing of a manifest. + * @throws SAXException When the [de.griefed.serverpackcreator.api.versionmeta.VersionMeta] had to be instantiated, but + * an error occurred during the parsing of a manifest. + * @author Griefed + */ + @Throws(IOException::class, ParserConfigurationException::class, SAXException::class) + private fun runConfigurationEditor() { + configurationEditor.continuedRunOptions() + } + + /** + * Check whether a `serverpackcreator.conf`-file exists. If it doesn't exist, and we are not + * running in [Mode.CLI] or [Mode.CGEN], create an unconfigured default one which can + * then be loaded into the GUI. + * + * @return `true` if a `serverpackcreator.conf`-file was created. + * @author Griefed + */ + private fun createDefaultConfig() { + if (!apiWrapper.apiProperties.defaultConfig.exists()) { + JarUtilities.copyFileFromJar( + "de/griefed/resources/${apiWrapper.apiProperties.defaultConfig.name}", + apiWrapper.apiProperties.defaultConfig, this.javaClass + ) + } + } + +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HelpCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HelpCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..1dd42f86ee81bd4d599d956630b757ebdc42d579 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HelpCommand.kt @@ -0,0 +1,70 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import de.griefed.serverpackcreator.api.utilities.common.readText +import de.griefed.serverpackcreator.app.Mode +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.io.IOException + +@CommandLine.Command( + name = "printHelp", mixinStandardHelpOptions = true, + description = ["Print a list of arguments to start ServerPackCreator with, as well as some general help."], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class HelpCommand : Command { + + override fun run() { + printHelp() + } + + /** + * Prints the help-text to the console. The help text contains information about: + * + * * running ServerPackCreator in different modes: + * + * * [Mode.CGEN] + * * [Mode.UPDATE] + * * [Mode.CLI] + * * [Mode.WEB] + * * [Mode.GUI] + * * [Mode.SETUP] + * + * * available languages + * * where to report issues + * * where to get support + * * where to find the wiki + * * how to support me + * + * + * @author Griefed + */ + private fun printHelp() { + try { + println( + HelpCommand::class.java.getResourceAsStream("/de/griefed/resources/cli_help.txt")!!.readText() + ) + } catch (e: IOException) { + throw RuntimeException(e) + } + } + +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HomeDirCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HomeDirCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..2dd2e2b20bbe26c6bcfba23c198deb076bfe7a78 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/HomeDirCommand.kt @@ -0,0 +1,66 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import de.griefed.serverpackcreator.api.utilities.common.SystemUtilities +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.io.File +import java.util.* +import java.util.prefs.Preferences + +@Suppress("DuplicatedCode") +@CommandLine.Command( + name = "homeDir", mixinStandardHelpOptions = true, + description = [ + "Change the home-directory for ServerPackCreator.", + "Changing the home-directory requires a restart of ServerPackCreator afterwards." + ], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class HomeDirCommand : Command { + override fun run() { + changeHomeDirectory() + } + + private fun changeHomeDirectory() { + val scanner = Scanner(System.`in`) + println("Enter the full path to the new ServerPackCreator home-directory.") + if (SystemUtilities.IS_WINDOWS) { + println("Don't forget to escape any \\ in your paths, so 'C:\\Some\\Path' becomes 'C:\\\\Some\\\\Path'.") + } + + var path: String + do { + print("Path: ") + path = scanner.nextLine() + if (!File(path).isDirectory) { + println("Directory '$path' does not exist.") + } + } while (!File(path).isDirectory) + + Preferences.userRoot().node("ServerPackCreator").put( + "de.griefed.serverpackcreator.home", + path + ) + + println("You MUST restart ServerPackCreator for this change to take full effect.") + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/LanguageCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/LanguageCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ecc631186c27146013dce828edf2c8f7c8bc050 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/LanguageCommand.kt @@ -0,0 +1,65 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import Translations +import de.comahe.i18n4k.Locale +import de.griefed.serverpackcreator.api.ApiWrapper +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.util.* + +@CommandLine.Command( + name = "lang", mixinStandardHelpOptions = true, + description = [ + "Change the language to use for ServerPackCreator.", + "Mostly affects the GUI of ServerPackCreator, but the CLI-mode.", + "A restart of ServerPackCreator is recommended after changing the language." + ], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class LanguageCommand(private val apiWrapper: ApiWrapper = ApiWrapper.api()) : Command { + override fun run() { + printAvailableLanguages() + chooseAndSwitchLanguage() + } + + private fun printAvailableLanguages() { + for (locale in Translations.locales) { + println(locale) + } + } + + private fun chooseAndSwitchLanguage() { + val scanner = Scanner(System.`in`) + println("Choose one of the available languages above.") + + var userLocale: String + do { + print("Language: ") + userLocale = scanner.next() + if (!Translations.locales.map { entry -> entry.language }.contains(userLocale)) { + println("Unsupported locale $userLocale.") + } + } while (!Translations.locales.map { entry -> entry.language }.contains(userLocale)) + val lang = scanner.nextLine() + apiWrapper.apiProperties.changeLocale(Locale(lang)) + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/RunHeadlessCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/RunHeadlessCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..f1922890d0bbbd3d2516264b375f351d5659f25b --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/RunHeadlessCommand.kt @@ -0,0 +1,142 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import de.griefed.serverpackcreator.api.ApiWrapper +import de.griefed.serverpackcreator.api.config.PackConfig +import org.apache.logging.log4j.kotlin.cachedLoggerOf +import org.xml.sax.SAXException +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.io.File +import java.io.IOException +import java.util.* +import javax.xml.parsers.ParserConfigurationException + +@Suppress("DuplicatedCode") +@CommandLine.Command( + name = "run", mixinStandardHelpOptions = true, + description = [ + "Run a config check and server pack generation using the default server pack config.", + "The default config file is expected at '</path/to/ServerPackCreator-home-directory/serverpackcreator.conf'.", + "Windows Users: You can use / instead of \\ in your paths, too." + ], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class RunHeadlessCommand(private val apiWrapper: ApiWrapper = ApiWrapper.api()) : Command { + private val log by lazy { cachedLoggerOf(this.javaClass) } + + override fun run() { + runHeadless() + } + + @CommandLine.Command( + mixinStandardHelpOptions = true, subcommands = [CommandLine.HelpCommand::class], + description = [ + "Run a config check and server pack generation using a specified server pack config.", + "You will be asked to enter the path to the desired config after starting this command." + ] + ) + fun withSpecificConfig( + @CommandLine.Option( + names = ["-c", "--config"], + description = [ + "The path to the config file.", + "Windows Users: You can use / instead of \\ in your paths, too." + ], + required = false + ) configFile: String?, + @CommandLine.Option( + names = ["-d", "--destination"], + description = [ + "A destination in which the server pack will be created in.", + "All folders, including parent folders, will be created in the process.", + "Windows Users: You can use / instead of \\ in your paths, too." + ], + required = false + ) destination: File? + ) { + val config = if (configFile == null) { + requestConfigFile() + } else { + File(configFile) + } + runHeadless(config, Optional.ofNullable(destination)) + } + + @CommandLine.Command( + mixinStandardHelpOptions = true, subcommands = [CommandLine.HelpCommand::class], + description = [ + "Run server pack generations for all configs in the config-directory.", + "The config-directory is inside ServerPackCreators home-directory." + ] + ) + fun withAllInConfigDir() { + val configs = apiWrapper.apiProperties.configsDirectory.listFiles() + for (config in configs) { + runHeadless(config) + } + } + + private fun requestConfigFile(): File { + val scanner = Scanner(System.`in`) + println("Enter the full path to the new ServerPackCreator home-directory.") + + var path: String + do { + print("Path: ") + path = scanner.nextLine() + if (!File(path).isFile) { + println("File '$path' does not exist.") + } + } while (!File(path).isFile) + return File(path) + } + + @Throws(IOException::class, ParserConfigurationException::class, SAXException::class) + fun runHeadless( + config: File = apiWrapper.apiProperties.defaultConfig, + destination: Optional<File> = Optional.empty() + ) { + if (!config.isFile) { + log.warn("${config.absolutePath} not found...") + } else { + val packConfig = PackConfig() + packConfig.customDestination = destination + val check = apiWrapper.configurationHandler.checkConfiguration(config, packConfig) + if (!check.allChecksPassed) { + println("Encountered the following errors/problems with the config:") + for (error in check.encounteredErrors) { + println(error) + } + } else { + val generation = apiWrapper.serverPackHandler.run(packConfig) + if (!generation.success) { + println("Error generating Server Pack:") + for (error in generation.errors) { + println(error) + } + } else { + println("Successfully generated Server Pack: ${generation.serverPack.absolutePath}") + } + } + } + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/SetupCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/SetupCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..c69d27c30155035977d6df6ea46595fa72e7b7b4 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/SetupCommand.kt @@ -0,0 +1,41 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import de.griefed.serverpackcreator.api.ApiWrapper +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen + +@CommandLine.Command( + name = "setup", mixinStandardHelpOptions = true, + description = [ + "Force-run the ServerPackCreator API setup, generating and providing all required working- and template-files and folders." + ], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class SetupCommand(private val apiWrapper: ApiWrapper = ApiWrapper.api()) : Command { + override fun run() { + forceApiSetup() + } + + private fun forceApiSetup() { + apiWrapper.setup(force = true) + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/UpdateCommand.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/UpdateCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..eecfe73e854c523f4143bbe5cb85d280e2e2b702 --- /dev/null +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/cli/commands/UpdateCommand.kt @@ -0,0 +1,224 @@ +/* Copyright (C) 2024 Griefed + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE + */ +package de.griefed.serverpackcreator.app.cli.commands + +import Translations +import com.install4j.api.Util +import com.install4j.api.context.UserCanceledException +import com.install4j.api.launcher.ApplicationLauncher +import com.install4j.api.launcher.Variables +import com.install4j.api.update.ApplicationDisplayMode +import com.install4j.api.update.UpdateDescriptor +import com.install4j.api.update.UpdateDescriptorEntry +import de.griefed.serverpackcreator.api.ApiWrapper +import de.griefed.serverpackcreator.app.updater.UpdateChecker +import org.apache.logging.log4j.kotlin.cachedLoggerOf +import picocli.CommandLine +import picocli.shell.jline3.PicocliCommands.ClearScreen +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Paths +import java.util.concurrent.ExecutionException + +@CommandLine.Command( + name = "update", mixinStandardHelpOptions = true, + description = [ + "Check for available updates.", + "If you installed ServerPackCreator using the official installers, and if an update is available, the update will be installed automatically." + ], + subcommands = [ClearScreen::class, CommandLine.HelpCommand::class] +) +class UpdateCommand(private val updateChecker: UpdateChecker = UpdateChecker(ApiWrapper.api().apiProperties)) : Command { + private val log by lazy { cachedLoggerOf(this.javaClass) } + private var i4JUpdatable = false + private var i4JDownload = false + private var i4JExecute = false + + init { + checkForUpdateWithApi() + } + + override fun run() { + checkAndRunUpdate() + } + + private fun checkAndRunUpdate() { + val updateAvailable = updateChecker.updateCheck(true) + if (updateAvailable) { + return + } + if (i4JUpdatable && !i4JDownload && !i4JExecute) { + checkForUpdateI4J() + if (i4JUpdatable) { + if (i4JDownload) { + downloadAndUpdate() + } else if (i4JExecute) { + executeUpdate() + } + } + } + } + + private fun executeUpdate() { + // The arguments that are passed to the installer switch the default GUI mode to an unattended + // mode with a progress bar. "-q" activates unattended mode, and "-splash Updating hello world ..." + // shows a progress bar with the specified title. + Thread { + com.install4j.api.update.UpdateChecker.executeScheduledUpdate( + mutableListOf( + "-q", + "Updating ServerPackCreator ...", + "-alerts" + ), true, null + ) + }.start() + } + + private fun downloadAndUpdate() { + // Here the background update downloader is launched + // Note the third argument which makes the call to the background update downloader blocking. + // The callback receives progress information from the update downloader and changes the text on the button + try { + ApplicationLauncher.launchApplication("524", null, true, object : ApplicationLauncher.Callback { + override fun exited(exitValue: Int) { + } + + override fun prepareShutdown() { + } + + override fun createProgressListener(): ApplicationLauncher.ProgressListener { + return object : ApplicationLauncher.ProgressListenerAdapter() { + var downloading: Boolean = false + override fun actionStarted(id: String) { + downloading = id == "downloadFile" + } + + override fun percentCompleted(value: Int) { + if (downloading) { + printProgress(value) + } + } + + override fun indeterminateProgress(indeterminateProgress: Boolean) { + printProgress(-1) + } + } + } + }) + // At this point, the update downloader has returned, and we can check if the "Schedule update installation" + // action has registered an update installer for execution + // We now switch to the EDT in done() for terminating the application + + if (com.install4j.api.update.UpdateChecker.isUpdateScheduled()) { + println(Translations.update_dialog_update_message.toString()) + // We execute the update immediately, but you could ask the user whether the update should be + // installed now. The scheduling of update installers is persistent, so this will also work + // after a restart of the launcher. + executeUpdate() + } else { + log.error(Translations.update_dialog_update_failed_message.toString()) + } + } catch (e: InterruptedException) { + log.error("Update interrupted.", e) + } catch (e: ExecutionException) { + log.error(Translations.update_dialog_update_failed_cause(e.cause!!.message.toString())) + log.error("Update could not be executed.", e) + } + + } + + private fun printProgress(value: Int) { + if (value == -1) { + println("Downloading...") + } else { + println("$value%...") + } + } + + private fun checkForUpdateI4J() { + // Here, the "Standalone update downloader" application is launched in a new process. + // The ID of the installer application is shown in the install4j IDE on the Installer->Screens & Actions step + // when the "Show IDs" toggle button is selected. + // Use the "Integration wizard" button on the "Launcher integration" tab in the configuration + // panel of the installer application, to get such a code snippet. + try { + ApplicationLauncher.launchApplication("462", null, false, null) + // This call returns immediately, because the "blocking" argument is set to false + } catch (e: IOException) { + log.error("Error launching updater.", e) + } + } + + private fun checkForUpdateWithApi() { + try { + if (isI4JUpdatable()) { + // The compiler variable sys.updatesUrl holds the URL where the updates.xml file is hosted. + // That URL is defined on the "Installer->Auto Update Options" step. + // The same compiler variable is used by the "Check for update" actions that are contained in the update + // downloaders. + val updateUrl: String = Variables.getCompilerVariable("sys.updatesUrl") + val updateDescriptor: UpdateDescriptor = + com.install4j.api.update.UpdateChecker.getUpdateDescriptor(updateUrl, ApplicationDisplayMode.GUI) + + try { + // If getPossibleUpdateEntry returns a non-null value, the version number in the updates.xml file + // is greater than the version number of the local installation. + val updateDescriptorEntry: UpdateDescriptorEntry? = updateDescriptor.possibleUpdateEntry + + // only installers and single bundle archives on macOS are supported for background updates + if (updateDescriptorEntry != null && (!updateDescriptorEntry.isArchive || updateDescriptorEntry.isSingleBundle)) { + if (!updateDescriptorEntry.isDownloaded) { + // An update is available for download + i4JDownload = true + } else if (com.install4j.api.update.UpdateChecker.isUpdateScheduled()) { + // The update has been downloaded, but the installation did not succeed yet. + i4JExecute = true + } + } + } catch (e: InterruptedException) { + log.error("Update interrupted.", e) + } catch (e: ExecutionException) { + val cause = e.cause + // UserCanceledException means that the user has canceled the proxy dialog + if (cause !is UserCanceledException) { + log.error("Update could not be executed: ${e.message}.") + } + } + + } else { + i4JUpdatable = false + } + } catch (ncdfe: NoClassDefFoundError) { + i4JUpdatable = false + log.debug("Not an install4j installation.") + } + } + + fun isI4JUpdatable(): Boolean { + try { + val installationDirectory = Paths.get(Variables.getInstallerVariable("sys.installationDir").toString()) + i4JUpdatable = true + return !Files.getFileStore(installationDirectory).isReadOnly && (Util.isWindows() || Util.isMacOS() || (Util.isLinux() && !Util.isArchive())) + } catch (ex: IOException) { + log.error("Error checking for install4j updatability.", ex) + } + return false + } +} \ No newline at end of file diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/gui/window/UpdateDialogs.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/gui/window/UpdateDialogs.kt index 04065cdf5867a582e2c386a5b3f5081f57bd3e52..f6a0974549762150003004bf5ac44492c6f1c5c0 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/gui/window/UpdateDialogs.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/gui/window/UpdateDialogs.kt @@ -41,7 +41,6 @@ import java.awt.datatransfer.Clipboard import java.awt.datatransfer.StringSelection import java.awt.event.ActionListener import java.io.IOException -import java.net.URISyntaxException import java.nio.file.Files import java.nio.file.Paths import java.util.* @@ -190,7 +189,7 @@ class UpdateDialogs( } } - private fun isUpdatable(): Boolean { + private fun isI4JUpdatable(): Boolean { try { val installationDirectory = Paths.get(Variables.getInstallerVariable("sys.installationDir").toString()) i4JUpdatable = true @@ -203,7 +202,7 @@ class UpdateDialogs( private fun checkForUpdateWithApi() { try { - if (isUpdatable()) { + if (isI4JUpdatable()) { // Here we check for updates in the background with the API. object : SwingWorker<UpdateDescriptorEntry, Any?>() { @Throws(Exception::class) diff --git a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/updater/UpdateChecker.kt b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/updater/UpdateChecker.kt index 0fd1832de9f79a538f5d2c7e6d7503291aae85c5..0bf5b2676c03cad0f71ab6697f3a158a66a0d1de 100644 --- a/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/updater/UpdateChecker.kt +++ b/serverpackcreator-app/src/main/kotlin/de/griefed/serverpackcreator/app/updater/UpdateChecker.kt @@ -83,10 +83,7 @@ class UpdateChecker(private val apiProperties: ApiProperties) { * @return The update, if available, as well as the download URL. * @author Griefed */ - fun checkForUpdate( - version: String, - preReleaseCheck: Boolean - ): Optional<Update> { + fun checkForUpdate(version: String, preReleaseCheck: Boolean): Optional<Update> { if (version.equals("dev", ignoreCase = true) || gitHub == null) { log.warn("Not checking for updates. Either using a dev-version, or GitHub Checking is not initialized.") return Optional.empty<Update>() @@ -102,7 +99,7 @@ class UpdateChecker(private val apiProperties: ApiProperties) { * @param logToConsole Whether to log update information to console or to logs. * @author Griefed */ - fun updateCheck(logToConsole: Boolean = false) { + fun updateCheck(logToConsole: Boolean = false): Boolean { refresh() val update: Optional<Update> = checkForUpdate( apiProperties.apiVersion, @@ -126,5 +123,7 @@ class UpdateChecker(private val apiProperties: ApiProperties) { log.info("No updates available.") } } + + return update.isPresent } } \ No newline at end of file diff --git a/serverpackcreator-app/src/main/resources/de/griefed/resources/gui/LICENSE-AGREEMENT b/serverpackcreator-app/src/main/resources/de/griefed/resources/gui/LICENSE-AGREEMENT index 8ec620bcc4690832eb3d840d9e9d1345a0002e77..4626602205366ae59a5d52b258f1dc0e0c40f44b 100644 --- a/serverpackcreator-app/src/main/resources/de/griefed/resources/gui/LICENSE-AGREEMENT +++ b/serverpackcreator-app/src/main/resources/de/griefed/resources/gui/LICENSE-AGREEMENT @@ -474,7 +474,7 @@ Used libraries / dependencies licenses: ------------------------------------------------------- -(1 of 38) +(1 of 40) Group: com.cronutils Name: cron-utils Version: 9.2.1 @@ -497,7 +497,7 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(2 of 38) +(2 of 40) Group: com.electronwill.night-config Name: toml Version: 3.7.2 @@ -515,176 +515,9 @@ License: GNU Lesser General Public License v3.0 URL: https://www.gnu.org/licenses/lgpl-3.0.txt - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. - - ####################################### -(3 of 38) +(3 of 40) Group: com.fasterxml.jackson.core Name: jackson-databind Version: 2.17.0 @@ -927,7 +760,7 @@ from the source code management (SCM) system project uses. ####################################### -(4 of 38) +(4 of 40) Group: com.fasterxml.jackson.module Name: jackson-module-kotlin Version: 2.17.1 @@ -979,10 +812,10 @@ from the source code management (SCM) system project uses. ####################################### -(5 of 38) +(5 of 40) Group: com.formdev Name: flatlaf -Version: 3.4 +Version: 3.5 POM Project URL: https://github.com/JFormDesigner/FlatLaf @@ -1197,7 +1030,7 @@ Embedded license: ####################################### -(6 of 38) +(6 of 40) Group: com.formdev Name: flatlaf-extras Version: 3.4 @@ -1415,7 +1248,7 @@ Embedded license: ####################################### -(7 of 38) +(7 of 40) Group: com.formdev Name: flatlaf-fonts-inter Version: 4.0 @@ -1731,7 +1564,7 @@ OTHER DEALINGS IN THE FONT SOFTWARE. ####################################### -(8 of 38) +(8 of 40) Group: com.formdev Name: flatlaf-fonts-jetbrains-mono Version: 2.304 @@ -1953,7 +1786,7 @@ Embedded license: ####################################### -(9 of 38) +(9 of 40) Group: com.formdev Name: flatlaf-fonts-roboto Version: 2.137 @@ -2375,7 +2208,7 @@ Embedded license: ####################################### -(10 of 38) +(10 of 40) Group: com.formdev Name: flatlaf-fonts-roboto-mono Version: 3.000 @@ -2797,10 +2630,10 @@ Embedded license: ####################################### -(11 of 38) +(11 of 40) Group: com.formdev Name: flatlaf-intellij-themes -Version: 3.4 +Version: 3.5 POM Project URL: https://github.com/JFormDesigner/FlatLaf @@ -3015,7 +2848,7 @@ Embedded license: ####################################### -(12 of 38) +(12 of 40) Group: com.formdev Name: svgSalamander Version: 1.1.4 @@ -3043,7 +2876,33 @@ URL: https://opensource.org/licenses/BSD-2-Clause ####################################### -(13 of 38) +(13 of 40) +Group: com.github.MCRcortex +Name: nekodetector +Version: Version-1.1-pre +POM Project URL: https://github.com/MCRcortex/nekodetector + + +POM License: MIT License + - https://opensource.org/licenses/MIT + + +POM license(s): + + +License: MIT License +URL: https://opensource.org/licenses/MIT + + +####################################### + +(14 of 40) +Group: com.install4j +Name: install4j-runtime +Version: 10.0.9 +####################################### + +(15 of 40) Group: com.miglayout Name: miglayout-swing Version: 11.3 @@ -3063,7 +2922,7 @@ URL: https://opensource.org/licenses/0BSD ####################################### -(14 of 38) +(16 of 40) Group: commons-io Name: commons-io Version: 2.16.1 @@ -3291,19 +3150,30 @@ The Apache Software Foundation (https://www.apache.org/). ####################################### -(15 of 38) +(17 of 40) Group: de.comahe.i18n4k Name: i18n4k-core -Version: 0.7.0 -No license information found +Version: 0.9.0 +POM Project URL: https://comahe-de.github.io/i18n4k/ + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(16 of 38) +(18 of 40) Group: de.comahe.i18n4k Name: i18n4k-core-jvm -Version: 0.7.0 +Version: 0.9.0 POM Project URL: https://comahe-de.github.io/i18n4k/ @@ -3320,25 +3190,67 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(17 of 38) +(19 of 40) Group: de.jensklingenberg.ktorfit Name: ktorfit-lib -Version: 1.14.0 -No license information found +Version: 2.0.1 +POM Project URL: https://github.com/Foso/Ktorfit + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 + + +####################################### + +(20 of 40) +Group: info.picocli +Name: picocli-shell-jline3 +Version: 4.7.6 +POM Project URL: https://picocli.info + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(18 of 38) +(21 of 40) Group: io.github.microutils Name: kotlin-logging Version: 3.0.5 -No license information found +POM Project URL: https://github.com/oshai/kotlin-logging + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(19 of 38) +(22 of 40) Group: net.java.balloontip Name: balloontip Version: 1.2.4.1 @@ -3358,7 +3270,7 @@ URL: https://opensource.org/licenses/BSD-3-Clause ####################################### -(20 of 38) +(23 of 40) Group: net.lingala.zip4j Name: zip4j Version: 2.11.5 @@ -3381,7 +3293,7 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(21 of 38) +(24 of 40) Group: org.apache.logging.log4j Name: log4j-api-kotlin Version: 1.4.0 @@ -3608,7 +3520,7 @@ The Apache Software Foundation (http://www.apache.org/). ####################################### -(22 of 38) +(25 of 40) Group: org.apache.logging.log4j Name: log4j-core Version: 2.23.1 @@ -3836,7 +3748,7 @@ Copyright 2005-2006 Tim Fennell ####################################### -(23 of 38) +(26 of 40) Group: org.bouncycastle Name: bcpkix-jdk18on Version: 1.78 @@ -3856,7 +3768,7 @@ URL: https://www.bouncycastle.org/licence.html ####################################### -(24 of 38) +(27 of 40) Group: org.javassist Name: javassist Version: 3.30.2-GA @@ -3895,19 +3807,10 @@ URL: https://www.mozilla.org/en-US/MPL/1.1 ####################################### -(25 of 38) +(28 of 40) Group: org.jetbrains.kotlin Name: kotlin-bom -Version: 1.9.23 -No license information found - - -####################################### - -(26 of 38) -Group: org.jetbrains.kotlin -Name: kotlin-reflect -Version: 1.9.23 +Version: 2.0.20 POM Project URL: https://kotlinlang.org/ @@ -3924,9 +3827,9 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(27 of 38) +(29 of 40) Group: org.jetbrains.kotlin -Name: kotlin-stdlib +Name: kotlin-reflect Version: 1.9.23 POM Project URL: https://kotlinlang.org/ @@ -3944,10 +3847,10 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(28 of 38) +(30 of 40) Group: org.jetbrains.kotlin Name: kotlin-stdlib -Version: 2.0.0-RC1 +Version: 2.0.20 POM Project URL: https://kotlinlang.org/ @@ -3964,16 +3867,27 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(29 of 38) +(31 of 40) Group: org.jetbrains.kotlinx Name: kotlinx-coroutines-core -Version: 1.8.0 -No license information found +Version: 1.8.1 +POM Project URL: https://github.com/Kotlin/kotlinx.coroutines + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(30 of 38) +(32 of 40) Group: org.jetbrains.kotlinx Name: kotlinx-coroutines-swing Version: 1.8.0 @@ -3993,16 +3907,27 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(31 of 38) +(33 of 40) Group: org.jetbrains.kotlinx Name: kotlinx-datetime Version: 0.5.0 -No license information found +POM Project URL: https://github.com/Kotlin/kotlinx-datetime + + +POM License: Apache License, Version 2.0 + - https://www.apache.org/licenses/LICENSE-2.0 + + +POM license(s): + + +License: Apache License, Version 2.0 +URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(32 of 38) +(34 of 40) Group: org.pf4j Name: pf4j Version: 3.11.0 @@ -4019,7 +3944,7 @@ URL: https://www.apache.org/licenses/LICENSE-2.0 ####################################### -(33 of 38) +(35 of 40) Group: org.postgresql Name: postgresql Version: 42.7.3 @@ -4171,10 +4096,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ####################################### -(34 of 38) +(36 of 40) Group: org.springframework.boot Name: spring-boot-devtools -Version: 3.3.0 +Version: 3.3.2 POM Project URL: https://spring.io/projects/spring-boot @@ -4387,7 +4312,7 @@ Embedded license: See the License for the specific language governing permissions and limitations under the License. -Spring Boot 3.3.0 +Spring Boot 3.3.2 Copyright (c) 2012-2024 VMware, Inc. This product is licensed to you under the Apache License, Version 2.0 @@ -4396,10 +4321,10 @@ the License. ####################################### -(35 of 38) +(37 of 40) Group: org.springframework.boot Name: spring-boot-starter-data-jpa -Version: 3.3.0 +Version: 3.3.2 POM Project URL: https://spring.io/projects/spring-boot @@ -4612,7 +4537,7 @@ Embedded license: See the License for the specific language governing permissions and limitations under the License. -Spring Boot 3.3.0 +Spring Boot 3.3.2 Copyright (c) 2012-2024 VMware, Inc. This product is licensed to you under the Apache License, Version 2.0 @@ -4621,10 +4546,10 @@ the License. ####################################### -(36 of 38) +(38 of 40) Group: org.springframework.boot Name: spring-boot-starter-log4j2 -Version: 3.3.1 +Version: 3.3.2 POM Project URL: https://spring.io/projects/spring-boot @@ -4837,7 +4762,7 @@ Embedded license: See the License for the specific language governing permissions and limitations under the License. -Spring Boot 3.3.1 +Spring Boot 3.3.2 Copyright (c) 2012-2024 VMware, Inc. This product is licensed to you under the Apache License, Version 2.0 @@ -4846,10 +4771,10 @@ the License. ####################################### -(37 of 38) +(39 of 40) Group: org.springframework.boot Name: spring-boot-starter-web -Version: 3.3.1 +Version: 3.3.2 POM Project URL: https://spring.io/projects/spring-boot @@ -5062,7 +4987,7 @@ Embedded license: See the License for the specific language governing permissions and limitations under the License. -Spring Boot 3.3.1 +Spring Boot 3.3.2 Copyright (c) 2012-2024 VMware, Inc. This product is licensed to you under the Apache License, Version 2.0 @@ -5071,7 +4996,7 @@ the License. ####################################### -(38 of 38) +(40 of 40) Group: tokyo.northside Name: tipoftheday Version: 0.4.2 diff --git a/spc.install4j b/spc.install4j index 4ba77d355be3c4fec15b6441b66418d9892ce5e4..cec9c796c28cb59bc25e4f1b25a236a0811c05d0 100644 --- a/spc.install4j +++ b/spc.install4j @@ -889,7 +889,7 @@ return console.askYesNo(message, true); </screen> </screens> </application> - <application name="Standalone update downloader" id="380" beanClass="com.install4j.runtime.beans.applications.CustomApplication" launchInNewProcess="false"> + <application name="Standalone update downloader GUI" id="380" beanClass="com.install4j.runtime.beans.applications.CustomApplication" launchInNewProcess="false"> <serializedBean> <property name="customIconImageFiles"> <add> @@ -1489,7 +1489,7 @@ return true;</property> </group> </screens> </application> - <application name="Background update downloader" id="442" beanClass="com.install4j.runtime.beans.applications.CustomApplication"> + <application name="Background update downloader GUI" id="442" beanClass="com.install4j.runtime.beans.applications.CustomApplication"> <serializedBean> <property name="customIconImageFiles"> <add> @@ -1766,6 +1766,884 @@ file.getParent() != null || (file.getName().endsWith(".app") && director </screen> </startup> </application> + <application name="Standalone update downloader CLI" id="462" beanClass="com.install4j.runtime.beans.applications.CustomApplication" launchInNewProcess="false"> + <serializedBean> + <property name="customIconImageFiles"> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_16.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_32.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_48.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_128.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_256.png</string> + </object> + </add> + </property> + <property name="executableDirectory"> + <object class="java.io.File"> + <string>.</string> + </object> + </property> + <property name="executableName" type="string">updater</property> + <property name="executionMode" type="enum" class="com.install4j.runtime.beans.applications.ExecutionMode" value="CONSOLE" /> + <property name="useCustomIcon" type="boolean" value="true" /> + <property name="windowTitle" type="string">${i18n:updater.WindowTitle("${compiler:sys.fullName}")}</property> + </serializedBean> + <startup> + <screen id="523" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0" /> + </startup> + <screens> + <screen name="Welcome" id="463" beanClass="com.install4j.runtime.beans.screens.FormScreen" styleId="7"> + <serializedBean> + <property name="title" type="string">${i18n:updater.WelcomeTitle("${compiler:sys.fullName}")}</property> + </serializedBean> + <formComponents> + <formComponent id="464" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + <property name="labelText" type="string">${i18n:updater.WelcomeInfoText("${compiler:sys.fullName}")}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + </formComponents> + </screen> + <screen name="Check for update" id="465" beanClass="com.install4j.runtime.beans.screens.FormScreen"> + <serializedBean> + <property name="subTitle" type="string">${i18n:updater.CheckForUpdateSubtitle}</property> + <property name="title" type="string">${i18n:updater.CheckForUpdateTitle}</property> + </serializedBean> + <postActivation>context.getWizardContext().setControlButtonVisible(ControlButtonType.NEXT, false); +context.getWizardContext().setControlButtonVisible(ControlButtonType.PREVIOUS, false); +context.goForward(1, true, true); +</postActivation> + <actions> + <action id="466" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none"> + <serializedBean> + <property name="progressChangeType" type="enum" class="com.install4j.runtime.beans.actions.control.ProgressChangeType" value="SET_INDETERMINATE" /> + </serializedBean> + </action> + <action id="467" beanClass="com.install4j.runtime.beans.actions.update.CheckForUpdateAction" actionElevationType="none" failureStrategy="quit"> + <serializedBean> + <property name="url" type="string">${installer:updatesUrl?:${compiler:sys.updatesUrl}}</property> + <property name="variable" type="string">updateDescriptor</property> + </serializedBean> + </action> + <action id="468" beanClass="com.install4j.runtime.beans.actions.control.SleepAction" actionElevationType="none" /> + <action name="Update descriptor entry" id="469" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry()</property> + </object> + </property> + <property name="variableName" type="string">updateDescriptorEntry</property> + </serializedBean> + </action> + <group name="Update available" id="470" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("updateDescriptorEntry") != null</property> + </object> + </property> + </serializedBean> + <beans> + <action name="New version" id="471" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion()</property> + </object> + </property> + <property name="variableName" type="string">updaterNewVersion</property> + </serializedBean> + </action> + <action name="Download size" id="472" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileSizeVerbose()</property> + </object> + </property> + <property name="variableName" type="string">updaterDownloadSize</property> + </serializedBean> + </action> + <action name="Comment" id="473" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getComment()</property> + </object> + </property> + <property name="variableName" type="string">updaterComment</property> + </serializedBean> + </action> + <action name="Download URL" id="474" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm()</property> + </object> + </property> + <property name="variableName" type="string">updaterDownloadUrl</property> + </serializedBean> + </action> + <action name="Archive" id="475" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive() ? Boolean.TRUE : Boolean.FALSE</property> + </object> + </property> + <property name="variableName" type="string">isArchive</property> + </serializedBean> + </action> + <action name="DMG" id="476" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName().toLowerCase().endsWith(".dmg")</property> + </object> + </property> + <property name="variableName" type="string">isDmg</property> + </serializedBean> + </action> + </beans> + </group> + </actions> + <formComponents> + <formComponent id="477" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" useExternalParametrization="true" externalParametrizationName="Directory" externalParametrizationMode="include"> + <serializedBean> + <property name="initialStatusMessage" type="string">${i18n:updater.CheckForUpdateLabel}</property> + </serializedBean> + <externalParametrizationPropertyNames> + <propertyName>statusVisible</propertyName> + <propertyName>initialStatusMessage</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + </formComponents> + </screen> + <group name="Up to date" id="478" beanClass="com.install4j.runtime.beans.groups.ScreenGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("updateDescriptorEntry") == null</property> + </object> + </property> + </serializedBean> + <beans> + <screen name="Up to date notification" id="479" beanClass="com.install4j.runtime.beans.screens.FormScreen" styleId="7" finishScreen="true"> + <serializedBean> + <property name="title" type="string">${i18n:updater.UpToDateTitle}</property> + </serializedBean> + <formComponents> + <formComponent id="480" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + <property name="labelText" type="string">${i18n:updater.UpToDateInfoText("${compiler:sys.fullName}")}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + </formComponents> + </screen> + </beans> + </group> + <group name="Update available" id="481" beanClass="com.install4j.runtime.beans.groups.ScreenGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("updateDescriptorEntry") != null</property> + </object> + </property> + </serializedBean> + <beans> + <screen name="New version available" id="482" beanClass="com.install4j.runtime.beans.screens.FormScreen"> + <serializedBean> + <property name="subTitle" type="string">${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")}</property> + <property name="title" type="string">${i18n:updater.NewVersionAvailableTitle}</property> + </serializedBean> + <condition>!context.getBooleanVariable("skipNewVersionAvailable")</condition> + <formComponents> + <formComponent id="483" beanClass="com.install4j.runtime.beans.formcomponents.KeyValuePairComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.CurrentVersionLabel}</property> + <property name="valueLabelColor"> + <object class="java.awt.Color"> + <int>128</int> + <int>0</int> + <int>0</int> + <int>255</int> + </object> + </property> + <property name="valueLabelFontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" /> + <property name="valueLabelFontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" /> + <property name="valueLabelText" type="string">${installer:sys.version}</property> + </serializedBean> + </formComponent> + <group id="484" beanClass="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup"> + <beans> + <formComponent id="485" beanClass="com.install4j.runtime.beans.formcomponents.KeyValuePairComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.NewVersionLabel}</property> + <property name="valueLabelColor"> + <object class="java.awt.Color"> + <int>0</int> + <int>128</int> + <int>0</int> + <int>255</int> + </object> + </property> + <property name="valueLabelFontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" /> + <property name="valueLabelFontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" /> + <property name="valueLabelText" type="string">${installer:updaterNewVersion}</property> + </serializedBean> + </formComponent> + <formComponent id="486" beanClass="com.install4j.runtime.beans.formcomponents.HyperlinkActionLabelComponent" insetLeft="5"> + <serializedBean> + <property name="actionScript"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.goForward(1, false, false);</property> + </object> + </property> + <property name="hyperlinkText" type="string">${i18n:updater.ShowComments}</property> + </serializedBean> + <visibilityScript> ((String)context.getVariable("updaterComment")).length() > 0</visibilityScript> + </formComponent> + </beans> + </group> + <formComponent id="487" beanClass="com.install4j.runtime.beans.formcomponents.SpacerComponent" /> + <formComponent id="488" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.DownloadLocationLabel}</property> + </serializedBean> + </formComponent> + <formComponent id="489" beanClass="com.install4j.runtime.beans.formcomponents.DirectoryChooserComponent"> + <serializedBean> + <property name="initialFile" type="string">${installer:sys.downloadsDir}</property> + <property name="labelText" type="string">${i18n:updater.DownloadToLabel}</property> + <property name="manualEntryAllowed" type="boolean" value="false" /> + <property name="variableName" type="string">updaterDownloadLocation</property> + </serializedBean> + </formComponent> + <formComponent id="490" beanClass="com.install4j.runtime.beans.formcomponents.KeyValuePairComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.DownloadSizeLabel}</property> + <property name="valueLabelText" type="string">${installer:updaterDownloadSize}</property> + </serializedBean> + </formComponent> + </formComponents> + </screen> + <screen name="Update message" id="491" beanClass="com.install4j.runtime.beans.screens.FormScreen"> + <serializedBean> + <property name="scrollable" type="boolean" value="false" /> + <property name="subTitle" type="string">${i18n:updater.CommentsSubTitle}</property> + <property name="title" type="string">${i18n:updater.CommentsTitle}</property> + </serializedBean> + <condition>false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen. +</condition> + <validation>if (context.isConsole()) { + context.goBackInHistory(1); +} +return true;</validation> + <postActivation>WizardContext wizardContext = context.getWizardContext(); +wizardContext.setControlButtonVisible(ControlButtonType.NEXT, false); +wizardContext.setControlButtonVisible(ControlButtonType.CANCEL, false);</postActivation> + <formComponents> + <formComponent id="492" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + <property name="labelText" type="string">${i18n:updater.CommentsLabel}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="493" beanClass="com.install4j.runtime.beans.formcomponents.HtmlDisplayFormComponent" useExternalParametrization="true" externalParametrizationName="HTML display" externalParametrizationMode="include"> + <serializedBean> + <property name="displayedText" type="string">${installer:updaterComment}</property> + <property name="fillVertical" type="boolean" value="true" /> + <property name="textSource" type="enum" class="com.install4j.runtime.beans.screens.components.TextSource" value="DIRECT" /> + </serializedBean> + <externalParametrizationPropertyNames> + <propertyName>textSource</propertyName> + <propertyName>displayedText</propertyName> + <propertyName>displayedTextFile</propertyName> + <propertyName>variableName</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="494" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent"> + <serializedBean> + <property name="consoleScript"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">console.waitForEnter(); +return true; +</property> + </object> + </property> + </serializedBean> + </formComponent> + </formComponents> + </screen> + <screen name="Download new version" id="495" beanClass="com.install4j.runtime.beans.screens.FormScreen"> + <serializedBean> + <property name="subTitle" type="string">${i18n:updater.DownloadSubTitle}</property> + <property name="title" type="string">${i18n:updater.DownloadTitle}</property> + </serializedBean> + <postActivation>context.getWizardContext().setControlButtonVisible(ControlButtonType.NEXT, false); +context.getWizardContext().setControlButtonVisible(ControlButtonType.PREVIOUS, false); +context.goForward(1, true, true); +</postActivation> + <actions> + <action name="Download location" id="496" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("updaterDownloadLocation") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName()</property> + </object> + </property> + <property name="variableName" type="string">updaterDownloadFile</property> + </serializedBean> + </action> + <action id="497" beanClass="com.install4j.runtime.beans.actions.net.DownloadFileAction" actionElevationType="elevated" failureStrategy="quit"> + <serializedBean> + <property name="targetFile"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="url" type="string">${installer:updaterDownloadUrl}</property> + </serializedBean> + </action> + <action id="498" beanClass="com.install4j.runtime.beans.actions.files.SetModeAction" actionElevationType="elevated"> + <serializedBean> + <property name="files" type="array" class="java.io.File" length="1"> + <element index="0"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </element> + </property> + <property name="mode" type="string">755</property> + </serializedBean> + </action> + </actions> + <formComponents> + <formComponent id="499" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" useExternalParametrization="true" externalParametrizationName="Directory" externalParametrizationMode="include"> + <externalParametrizationPropertyNames> + <propertyName>statusVisible</propertyName> + <propertyName>initialStatusMessage</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + </formComponents> + </screen> + <group name="Finish" id="500" beanClass="com.install4j.runtime.beans.groups.ScreenGroup"> + <beans> + <screen name="Finish" id="501" beanClass="com.install4j.runtime.beans.screens.FormScreen" styleId="7" finishScreen="true"> + <serializedBean> + <property name="title" type="string">${i18n:updater.FinishTitle}</property> + </serializedBean> + <condition>!(context.getBooleanVariable("isArchive") && context.getBooleanVariable("isDmg"))</condition> + <actions> + <group name="Execute installer" id="502" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">!context.getBooleanVariable("isArchive") && ((Integer)context.getVariable("updaterLaunchSelection")).intValue() == 0</property> + </object> + </property> + </serializedBean> + <beans> + <action name="Set installer arguments" id="503" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">List<String> args = new ArrayList<String>(); +String installationDirectory = context.getInstallationDirectory().getPath(); +if (context.isUnattended()) { + args.add("-q"); + args.add("-wait"); + args.add("20"); + ProgressInterface progressInterface = context.getProgressInterface(); + if (progressInterface.isUnattendedProgressDialog()) { + if (progressInterface.isAlertsShown()) { + args.add("-alerts"); + } + args.add("-splash"); + args.add("Installing"); + } +} else if (context.isConsole()) { + args.add("-c"); +} + args.add("-dir"); + args.add(installationDirectory); + + return args.toArray(new String[args.size()]); +</property> + </object> + </property> + <property name="variableName" type="string">installerArguments</property> + </serializedBean> + </action> + <action id="504" beanClass="com.install4j.runtime.beans.actions.update.ShutdownCallingLauncherAction" actionElevationType="none" /> + <action id="505" beanClass="com.install4j.runtime.beans.actions.misc.RunExecutableAction" actionElevationType="elevated" failureStrategy="quit" errorMessage="${i18n:updater.LaunchError}"> + <serializedBean> + <property name="arguments" type="array" elementType="string" length="1"> + <element index="0">${installer:installerArguments}</element> + </property> + <property name="executable"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="workingDirectory"> + <object class="java.io.File"> + <string>${installer:updaterDownloadLocation}</string> + </object> + </property> + </serializedBean> + </action> + </beans> + </group> + </actions> + <formComponents> + <formComponent id="506" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="507" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + <property name="labelText" type="string">${i18n:updater.FinishInfoText("${compiler:sys.fullName}")}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="508" beanClass="com.install4j.runtime.beans.formcomponents.LabelComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.LaunchUpdaterQuestion}</property> + </serializedBean> + </formComponent> + <formComponent id="509" beanClass="com.install4j.runtime.beans.formcomponents.SpacerComponent"> + <serializedBean> + <property name="height" type="int" value="5" /> + </serializedBean> + </formComponent> + <formComponent id="510" beanClass="com.install4j.runtime.beans.formcomponents.RadiobuttonsComponent"> + <serializedBean> + <property name="radioButtonLabels" type="array" elementType="string" length="2"> + <element index="0">${i18n:updater.LaunchUpdaterLabel}</element> + <element index="1">${i18n:updater.DoNotLaunchUpdaterLabel}</element> + </property> + <property name="variableName" type="string">updaterLaunchSelection</property> + </serializedBean> + <visibilityScript>!context.getBooleanVariable("isArchive")</visibilityScript> + </formComponent> + <formComponent id="511" beanClass="com.install4j.runtime.beans.formcomponents.HyperlinkActionLabelComponent"> + <serializedBean> + <property name="actionScript"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">Util.showPath((String)context.getVariable("updaterDownloadFile"));</property> + </object> + </property> + <property name="hyperlinkText" type="string">${i18n:updater.OpenContainingFolderLabel}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + </formComponent> + <formComponent id="512" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent"> + <serializedBean> + <property name="detailVisible" type="boolean" value="false" /> + <property name="hideInitially" type="boolean" value="true" /> + </serializedBean> + </formComponent> + </formComponents> + </screen> + <screen name="Finish DMG Archive" id="513" beanClass="com.install4j.runtime.beans.screens.FormScreen" styleId="7" finishScreen="true"> + <serializedBean> + <property name="title" type="string">${i18n:updater.FinishTitle}</property> + </serializedBean> + <condition>context.getBooleanVariable("isArchive") && context.getBooleanVariable("isDmg")</condition> + <actions> + <group name="Execute installer" id="514" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getBooleanVariable("updaterOpenDmg")</property> + </object> + </property> + </serializedBean> + <beans> + <action id="515" beanClass="com.install4j.runtime.beans.actions.update.ShutdownCallingLauncherAction" actionElevationType="none" /> + <action name="Open DMG" id="516" beanClass="com.install4j.runtime.beans.actions.control.RunScriptAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">Util.showPath((String)context.getVariable("updaterDownloadFile")); +return true;</property> + </object> + </property> + </serializedBean> + </action> + </beans> + </group> + </actions> + <formComponents> + <formComponent id="517" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="518" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="20" useExternalParametrization="true" externalParametrizationName="Header" externalParametrizationMode="include"> + <serializedBean> + <property name="hideIfBlank" type="boolean" value="true" /> + <property name="labelText" type="string">${i18n:updater.FinishInfoText("${compiler:sys.fullName}")}</property> + </serializedBean> + <visibilityScript>!context.isConsole()</visibilityScript> + <externalParametrizationPropertyNames> + <propertyName>labelText</propertyName> + </externalParametrizationPropertyNames> + </formComponent> + <formComponent id="519" beanClass="com.install4j.runtime.beans.formcomponents.LabelComponent"> + <serializedBean> + <property name="labelText" type="string">${i18n:updater.LaunchUpdaterQuestion}</property> + </serializedBean> + </formComponent> + <formComponent id="520" beanClass="com.install4j.runtime.beans.formcomponents.SpacerComponent"> + <serializedBean> + <property name="height" type="int" value="5" /> + </serializedBean> + </formComponent> + <formComponent id="521" beanClass="com.install4j.runtime.beans.formcomponents.CheckboxComponent"> + <serializedBean> + <property name="checkboxText" type="string">${i18n:updater.OpenContainingFolderLabel}</property> + <property name="initiallySelected" type="boolean" value="true" /> + <property name="variableName" type="string">updaterOpenDmg</property> + </serializedBean> + </formComponent> + <formComponent id="522" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent"> + <serializedBean> + <property name="detailVisible" type="boolean" value="false" /> + <property name="hideInitially" type="boolean" value="true" /> + </serializedBean> + </formComponent> + </formComponents> + </screen> + </beans> + </group> + </beans> + </group> + </screens> + </application> + <application name="Background update downloader CLI" id="524" beanClass="com.install4j.runtime.beans.applications.CustomApplication"> + <serializedBean> + <property name="customIconImageFiles"> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_16.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_32.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_48.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_128.png</string> + </object> + </add> + <add> + <object class="com.install4j.api.beans.ExternalFile"> + <string>${compiler:sys.install4jHome}/resource/updater_256.png</string> + </object> + </add> + </property> + <property name="executableName" type="string">bgupdater</property> + <property name="useCustomIcon" type="boolean" value="true" /> + <property name="vmParameters" type="string">-Dapple.awt.UIElement=true</property> + <property name="windowTitle" type="string">${compiler:sys.fullName}</property> + </serializedBean> + <startup> + <screen id="525" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0"> + <actions> + <action name="Check prerequisites" id="526" beanClass="com.install4j.runtime.beans.actions.control.RunScriptAction" rollbackBarrierExitCode="0" failureStrategy="quit"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">import java.nio.file.*; + +Path dir = context.getInstallationDirectory().toPath(); +// quit if the current installation is on a read only file system, for example a disk image on macOS +// or if the directory is not writable on Linux/Unix. +// If there is no "Request privileges" action in the installer, the condition should also +// check Files.isWritable(dir) +return !Files.getFileStore(dir).isReadOnly() && ((Util.isWindows() && !Util.isArchive()) || Util.isMacOS() || (Util.isLinux() && !Util.isArchive())); +</property> + </object> + </property> + </serializedBean> + </action> + <action id="527" beanClass="com.install4j.runtime.beans.actions.update.CheckForUpdateAction" actionElevationType="none" failureStrategy="quit"> + <serializedBean> + <property name="url" type="string">${compiler:sys.updatesUrl}</property> + <property name="variable" type="string">updateDescriptor</property> + </serializedBean> + </action> + <action name="Update descriptor entry" id="528" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction" failureStrategy="quit"> + <serializedBean> + <property name="failIfNull" type="boolean" value="true" /> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">UpdateDescriptorEntry entry = ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry(); + +if (entry == null) { + return null; +} else if (entry.isArchive() && !entry.isSingleBundle()) { + // only installers and single bundle archives on macOS are supported + return null; +} else if (entry.isDownloaded()) { + // update has been downloaded already + return null; +} else { + return entry; +}</property> + </object> + </property> + <property name="variableName" type="string">updateDescriptorEntry</property> + </serializedBean> + </action> + <group name="Update available" id="529" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("updateDescriptorEntry") != null</property> + </object> + </property> + </serializedBean> + <beans> + <action name="New version" id="530" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion()</property> + </object> + </property> + <property name="variableName" type="string">updaterNewVersion</property> + </serializedBean> + </action> + <action name="Download URL" id="531" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm()</property> + </object> + </property> + <property name="variableName" type="string">updaterDownloadUrl</property> + </serializedBean> + </action> + <action name="Download location" id="532" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">context.getVariable("sys.updateStorageDir") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName()</property> + </object> + </property> + <property name="variableName" type="string">updaterDownloadFile</property> + </serializedBean> + </action> + <action id="533" beanClass="com.install4j.runtime.beans.actions.net.DownloadFileAction" failureStrategy="quit"> + <serializedBean> + <property name="targetFile"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="url" type="string">${installer:updaterDownloadUrl}</property> + </serializedBean> + </action> + <group name="Installer" id="534" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">!((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive()</property> + </object> + </property> + </serializedBean> + <beans> + <action id="535" beanClass="com.install4j.runtime.beans.actions.files.SetModeAction" actionElevationType="elevated"> + <serializedBean> + <property name="files" type="array" class="java.io.File" length="1"> + <element index="0"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </element> + </property> + <property name="mode" type="string">755</property> + </serializedBean> + </action> + <action id="536" beanClass="com.install4j.runtime.beans.actions.update.ScheduleUpdateAction" actionElevationType="none" failureStrategy="quit"> + <serializedBean> + <property name="installerFile"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="version" type="string">${installer:updaterNewVersion}</property> + </serializedBean> + </action> + </beans> + </group> + <group name="Single Bundle Archive" id="537" beanClass="com.install4j.runtime.beans.groups.ActionGroup"> + <serializedBean> + <property name="conditionExpression"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive()</property> + </object> + </property> + </serializedBean> + <beans> + <action name="Staging Directory" id="538" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction"> + <serializedBean> + <property name="script"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">String dirName = context.getVariable("updaterDownloadFile") + "_dir"; +new File(dirName).mkdirs(); +return dirName;</property> + </object> + </property> + <property name="variableName" type="string">updaterStagingDir</property> + </serializedBean> + </action> + <action name="Delete Staging Directory" id="539" beanClass="com.install4j.runtime.beans.actions.files.DeleteFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0"> + <serializedBean> + <property name="backupForRollback" type="boolean" value="false" /> + <property name="files" type="array" class="java.io.File" length="1"> + <element index="0"> + <object class="java.io.File"> + <string>${installer:updaterStagingDir}</string> + </object> + </element> + </property> + <property name="recursive" type="boolean" value="true" /> + </serializedBean> + <condition>new File((String)context.getVariable("updaterStagingDir")).exists()</condition> + </action> + <action id="540" beanClass="com.install4j.runtime.beans.actions.files.ExtractDmgFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit"> + <serializedBean> + <property name="archiveFile"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="destinationDirectory"> + <object class="java.io.File"> + <string>${installer:updaterStagingDir}</string> + </object> + </property> + <property name="fileFilter"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">// only extract app bundle, no other top level files + +import com.install4j.api.unix.UnixFileSystem; + +File realFile = new File(dmgMountPoint, file.getPath()); + +return file.getParent() != null || (file.getName().endsWith(".app") && realFile.isDirectory() && !UnixFileSystem.getFileInformation(realFile).isLink());</property> + </object> + </property> + </serializedBean> + <condition>((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")</condition> + </action> + <action id="541" beanClass="com.install4j.runtime.beans.actions.files.ExtractTarFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit"> + <serializedBean> + <property name="archiveFile"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </property> + <property name="destinationDirectory"> + <object class="java.io.File"> + <string>${installer:updaterStagingDir}</string> + </object> + </property> + <property name="fileFilter"> + <object class="com.install4j.api.beans.ScriptProperty"> + <property name="value" type="string">// only extract app bundle, no other top level files +file.getParent() != null || (file.getName().endsWith(".app") && directory)</property> + </object> + </property> + </serializedBean> + <condition>!((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")</condition> + </action> + <action id="542" beanClass="com.install4j.runtime.beans.actions.update.ScheduleUpdateAction" actionElevationType="none" failureStrategy="quit"> + <serializedBean> + <property name="installerFile"> + <object class="java.io.File"> + <string>${installer:updaterStagingDir}</string> + </object> + </property> + <property name="version" type="string">${installer:updaterNewVersion}</property> + </serializedBean> + </action> + <action name="Delete archive" id="543" beanClass="com.install4j.runtime.beans.actions.files.DeleteFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0"> + <serializedBean> + <property name="backupForRollback" type="boolean" value="false" /> + <property name="files" type="array" class="java.io.File" length="1"> + <element index="0"> + <object class="java.io.File"> + <string>${installer:updaterDownloadFile}</string> + </object> + </element> + </property> + </serializedBean> + </action> + </beans> + </group> + </beans> + </group> + </actions> + </screen> + </startup> + </application> </applications> <styles defaultStyleId="1"> <style name="Standard" id="1" beanClass="com.install4j.runtime.beans.styles.FormStyle">