mirror of
https://github.com/amir1376/ab-download-manager.git
synced 2025-02-20 11:43:24 +08:00
add nsis installer
This commit is contained in:
parent
a1c8f54bc7
commit
2788b6cc76
@ -17,4 +17,5 @@ dependencies{
|
||||
implementation(libs.semver)
|
||||
implementation("ir.amirab.util:platform:1")
|
||||
implementation("ir.amirab.plugin:git-version-plugin:1")
|
||||
implementation("ir.amirab.plugin:installer-plugin:1")
|
||||
}
|
@ -1,21 +1,20 @@
|
||||
package buildlogic
|
||||
|
||||
import io.github.z4kn4fein.semver.Version
|
||||
import ir.amirab.installer.InstallerTargetFormat
|
||||
import ir.amirab.util.platform.Platform
|
||||
import org.jetbrains.compose.desktop.application.dsl.JvmApplicationDistributions
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import java.io.File
|
||||
|
||||
|
||||
object CiUtils {
|
||||
fun getTargetFileName(
|
||||
packageName: String,
|
||||
appVersion: Version,
|
||||
target: TargetFormat,
|
||||
target: InstallerTargetFormat?,
|
||||
): String {
|
||||
val fileExtension = when (target) {
|
||||
// we use archived for app image distribution
|
||||
TargetFormat.AppImage -> {
|
||||
// we use archived for app image distribution ( app image is a folder actually so there is no installer so we zip it instead)
|
||||
null -> {
|
||||
when (Platform.getCurrentPlatform()) {
|
||||
Platform.Desktop.Linux -> "tar.gz"
|
||||
Platform.Desktop.MacOS -> "tar.gz"
|
||||
@ -28,7 +27,7 @@ object CiUtils {
|
||||
}
|
||||
|
||||
val platformName = when (target) {
|
||||
TargetFormat.AppImage -> Platform.getCurrentPlatform()
|
||||
null -> Platform.getCurrentPlatform()
|
||||
else -> {
|
||||
val packageFileExt = target.fileExtensionWithoutDot()
|
||||
requireNotNull(Platform.fromExecutableFileExtension(packageFileExt)) {
|
||||
@ -41,9 +40,10 @@ object CiUtils {
|
||||
|
||||
fun getFileOfPackagedTarget(
|
||||
baseOutputDir: File,
|
||||
target: TargetFormat,
|
||||
target: InstallerTargetFormat,
|
||||
): File {
|
||||
val folder = baseOutputDir.resolve(target.outputDirName)
|
||||
val folder = baseOutputDir
|
||||
// val folder = baseOutputDir.resolve(target.outputDirName)
|
||||
val exeFile = kotlin.runCatching {
|
||||
folder.walk().first {
|
||||
it.name.endsWith(target.fileExt)
|
||||
@ -89,7 +89,7 @@ object CiUtils {
|
||||
fun movePackagedAndCreateSignature(
|
||||
appVersion: Version,
|
||||
packageName: String,
|
||||
target: TargetFormat,
|
||||
target: InstallerTargetFormat,
|
||||
basePackagedAppsDir: File,
|
||||
outputDir: File,
|
||||
) {
|
||||
@ -148,4 +148,4 @@ object CiUtils {
|
||||
*/
|
||||
}
|
||||
|
||||
private fun TargetFormat.fileExtensionWithoutDot() = fileExt.substring(".".length)
|
||||
private fun InstallerTargetFormat.fileExtensionWithoutDot() = fileExt.substring(".".length)
|
20
compositeBuilds/plugins/installer-plugin/build.gradle.kts
Normal file
20
compositeBuilds/plugins/installer-plugin/build.gradle.kts
Normal file
@ -0,0 +1,20 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
version = 1
|
||||
group = "ir.amirab.plugin"
|
||||
dependencies {
|
||||
implementation("ir.amirab.util:platform:1")
|
||||
implementation(libs.handlebarsJava)
|
||||
}
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("installer-plugin") {
|
||||
id = "ir.amirab.installer-plugin"
|
||||
implementationClass = "ir.amirab.installer.InstallerPlugin"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package ir.amirab.installer
|
||||
|
||||
import ir.amirab.installer.extensiion.InstallerPluginExtension
|
||||
import ir.amirab.installer.tasks.windows.NsisTask
|
||||
import ir.amirab.installer.utils.Constants
|
||||
import ir.amirab.util.platform.Platform
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.create
|
||||
import org.gradle.kotlin.dsl.register
|
||||
|
||||
class InstallerPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
val extension = target.extensions.create("installerPlugin", InstallerPluginExtension::class)
|
||||
target.afterEvaluate {
|
||||
registerTasks(target, extension)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerTasks(
|
||||
project: Project,
|
||||
extension: InstallerPluginExtension
|
||||
) {
|
||||
val windowConfig = extension.windowsConfig
|
||||
val createInstallerTaskName = Constants.CREATE_INSTALLER_TASK_NAME
|
||||
val createInstallerNsisTaskName = "${createInstallerTaskName}Nsis"
|
||||
if (windowConfig != null) {
|
||||
project.tasks
|
||||
.register<NsisTask>(createInstallerNsisTaskName)
|
||||
.configure {
|
||||
dependsOn(extension.taskDependencies.toTypedArray())
|
||||
this.nsisTemplate.set(requireNotNull(windowConfig.nsisTemplate) { "Nsis Template not provided" })
|
||||
this.commonParams.set(windowConfig)
|
||||
this.extraParams.set(windowConfig.extraParams)
|
||||
this.destFolder.set(extension.outputFolder.get().asFile)
|
||||
this.outputFileName.set(requireNotNull(windowConfig.outputFileName) { " outputFileName not provided " })
|
||||
this.sourceFolder.set(requireNotNull(windowConfig.inputDir) { "inputDir not provided" })
|
||||
}
|
||||
}
|
||||
project.tasks.register(createInstallerTaskName) {
|
||||
// when we want to create installer we need to prepare its input first!
|
||||
when (val platform = Platform.getCurrentPlatform()) {
|
||||
Platform.Desktop.Linux -> {
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
Platform.Desktop.MacOS -> {
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
Platform.Desktop.Windows -> {
|
||||
if (windowConfig != null) {
|
||||
dependsOn(createInstallerNsisTaskName)
|
||||
}
|
||||
}
|
||||
|
||||
else -> error("unsupported platform: $platform")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package ir.amirab.installer
|
||||
|
||||
import ir.amirab.util.platform.Platform
|
||||
|
||||
|
||||
enum class InstallerTargetFormat(
|
||||
val id: String,
|
||||
val targetOS: Platform,
|
||||
) {
|
||||
Deb("deb", Platform.Desktop.Linux),
|
||||
Rpm("rpm", Platform.Desktop.Linux),
|
||||
Dmg("dmg", Platform.Desktop.MacOS),
|
||||
Pkg("pkg", Platform.Desktop.MacOS),
|
||||
Exe("exe", Platform.Desktop.Windows),
|
||||
Msi("msi", Platform.Desktop.Windows);
|
||||
|
||||
val isCompatibleWithCurrentOS: Boolean by lazy { isCompatibleWith(Platform.getCurrentPlatform()) }
|
||||
|
||||
fun isCompatibleWith(os: Platform): Boolean = os == targetOS
|
||||
|
||||
val outputDirName: String
|
||||
get() = id
|
||||
|
||||
val fileExt: String
|
||||
get() {
|
||||
return ".$id"
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package ir.amirab.installer.extensiion
|
||||
|
||||
import ir.amirab.installer.InstallerTargetFormat
|
||||
import ir.amirab.installer.utils.Constants
|
||||
import ir.amirab.util.platform.Platform
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class InstallerPluginExtension {
|
||||
@get:Inject
|
||||
internal abstract val project: Project
|
||||
|
||||
abstract val outputFolder: DirectoryProperty
|
||||
|
||||
internal val taskDependencies = mutableListOf<Any>()
|
||||
|
||||
fun dependsOn(vararg tasks: Any) {
|
||||
taskDependencies.addAll(tasks)
|
||||
}
|
||||
|
||||
internal var windowsConfig: WindowsConfig? = null
|
||||
private set
|
||||
|
||||
fun windows(
|
||||
config: WindowsConfig.() -> Unit
|
||||
) {
|
||||
if (Platform.getCurrentPlatform() != Platform.Desktop.Windows) return
|
||||
val windowsConfig = if (this.windowsConfig == null) {
|
||||
WindowsConfig().also {
|
||||
this.windowsConfig = it
|
||||
}
|
||||
} else {
|
||||
this.windowsConfig!!
|
||||
}
|
||||
windowsConfig.config()
|
||||
}
|
||||
|
||||
val createInstallerTask: TaskProvider<Task> by lazy {
|
||||
project.tasks.named(Constants.CREATE_INSTALLER_TASK_NAME)
|
||||
}
|
||||
|
||||
fun isThisPlatformSupported() = when (Platform.getCurrentPlatform()) {
|
||||
Platform.Desktop.Windows -> windowsConfig != null
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun getCreatedInstallerTargetFormats(): List<InstallerTargetFormat> {
|
||||
return buildList<InstallerTargetFormat> {
|
||||
when (Platform.getCurrentPlatform()) {
|
||||
Platform.Desktop.Windows -> {
|
||||
if (windowsConfig != null) {
|
||||
add(InstallerTargetFormat.Exe)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class WindowsConfig(
|
||||
var appName: String? = null,
|
||||
var appDisplayName: String? = null,
|
||||
var appVersion: String? = null,
|
||||
var appDisplayVersion: String? = null,
|
||||
var iconFile: File? = null,
|
||||
var licenceFile: File? = null,
|
||||
|
||||
var outputFileName: String? = null,
|
||||
|
||||
var inputDir: File? = null,
|
||||
|
||||
var nsisTemplate: File? = null,
|
||||
|
||||
var extraParams: Map<String, Any> = emptyMap()
|
||||
) : Serializable
|
||||
|
@ -0,0 +1,91 @@
|
||||
package ir.amirab.installer.tasks.windows
|
||||
|
||||
import com.github.jknack.handlebars.Context
|
||||
import com.github.jknack.handlebars.Handlebars
|
||||
import ir.amirab.installer.extensiion.WindowsConfig
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.mapProperty
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
|
||||
abstract class NsisTask : DefaultTask() {
|
||||
|
||||
@get:InputDirectory
|
||||
abstract val sourceFolder: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val destFolder: DirectoryProperty
|
||||
|
||||
@get:Input
|
||||
abstract val outputFileName: Property<String>
|
||||
|
||||
@get:InputFile
|
||||
abstract val nsisTemplate: Property<File>
|
||||
|
||||
@get:Input
|
||||
abstract val commonParams: Property<WindowsConfig>
|
||||
|
||||
@get:Input
|
||||
val extraParams: MapProperty<String, Any> = project.objects.mapProperty<String, Any>()
|
||||
|
||||
@get:Internal
|
||||
abstract val nsisExecutable: Property<File>
|
||||
|
||||
init {
|
||||
nsisExecutable.convention(
|
||||
project.provider { File("C:\\Program Files (x86)\\NSIS\\makensis.exe") }
|
||||
)
|
||||
}
|
||||
|
||||
private fun createHandleBarContext(): Context {
|
||||
val commonParams = commonParams.get()
|
||||
val common = mapOf(
|
||||
"app_name" to commonParams.appName!!,
|
||||
"app_display_name" to commonParams.appDisplayName!!,
|
||||
"app_version" to commonParams.appVersion!!,
|
||||
"app_display_version" to commonParams.appDisplayVersion!!,
|
||||
"license_file" to commonParams.licenceFile!!,
|
||||
"icon_file" to commonParams.iconFile!!,
|
||||
)
|
||||
val overrides = mapOf(
|
||||
"input_dir" to sourceFolder.get().asFile.absolutePath,
|
||||
"output_file" to "${destFolder.file(outputFileName).get().asFile.path}.exe",
|
||||
)
|
||||
return Context.newContext(
|
||||
extraParams
|
||||
.get()
|
||||
.plus(common)
|
||||
.plus(overrides)
|
||||
)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val executable = nsisExecutable.get()
|
||||
val scriptTemplate = nsisTemplate.get()
|
||||
val handlebars = Handlebars()
|
||||
val context = createHandleBarContext()
|
||||
val script = handlebars.compileInline(
|
||||
scriptTemplate.readText()
|
||||
).apply(context)
|
||||
logger.debug("NSIS Script:")
|
||||
logger.debug(script)
|
||||
project.exec {
|
||||
executable(
|
||||
executable,
|
||||
)
|
||||
args("-")
|
||||
standardInput = ByteArrayInputStream(script.toByteArray())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package ir.amirab.installer.utils
|
||||
|
||||
internal object Constants {
|
||||
const val CREATE_INSTALLER_TASK_NAME = "createInstaller"
|
||||
}
|
@ -6,3 +6,4 @@ dependencyResolutionManagement{
|
||||
}
|
||||
}
|
||||
include("git-version-plugin")
|
||||
include("installer-plugin")
|
@ -1,8 +1,10 @@
|
||||
import buildlogic.*
|
||||
import buildlogic.versioning.*
|
||||
import ir.amirab.installer.InstallerTargetFormat
|
||||
import org.jetbrains.changelog.Changelog
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import ir.amirab.util.platform.Platform
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat.*
|
||||
|
||||
plugins {
|
||||
id(MyPlugins.kotlin)
|
||||
@ -12,9 +14,9 @@ plugins {
|
||||
id(Plugins.changeLog)
|
||||
id(Plugins.ksp)
|
||||
id(Plugins.aboutLibraries)
|
||||
id("ir.amirab.installer-plugin")
|
||||
// id(MyPlugins.proguardDesktop)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.decompose)
|
||||
implementation(libs.decompose.jbCompose)
|
||||
@ -102,7 +104,7 @@ compose {
|
||||
mainClass = "$desktopPackageName.AppKt"
|
||||
nativeDistributions {
|
||||
modules("java.instrument", "jdk.unsupported")
|
||||
targetFormats(TargetFormat.Msi, TargetFormat.Deb)
|
||||
targetFormats(Msi, Deb)
|
||||
if (Platform.getCurrentPlatform() == Platform.Desktop.Linux) {
|
||||
// filekit library requires this module in linux.
|
||||
modules("jdk.security.auth")
|
||||
@ -114,21 +116,21 @@ compose {
|
||||
val menuGroupName = getPrettifiedAppName()
|
||||
licenseFile.set(rootProject.file("LICENSE"))
|
||||
linux {
|
||||
debPackageVersion = getAppVersionStringForPackaging(TargetFormat.Deb)
|
||||
rpmPackageVersion = getAppVersionStringForPackaging(TargetFormat.Rpm)
|
||||
debPackageVersion = getAppVersionStringForPackaging(Deb)
|
||||
rpmPackageVersion = getAppVersionStringForPackaging(Rpm)
|
||||
appCategory = "Network"
|
||||
iconFile = project.file("icons/icon.png")
|
||||
menuGroup = menuGroupName
|
||||
shortcut = true
|
||||
}
|
||||
macOS {
|
||||
pkgPackageVersion = getAppVersionStringForPackaging(TargetFormat.Pkg)
|
||||
dmgPackageVersion = getAppVersionStringForPackaging(TargetFormat.Dmg)
|
||||
pkgPackageVersion = getAppVersionStringForPackaging(Pkg)
|
||||
dmgPackageVersion = getAppVersionStringForPackaging(Dmg)
|
||||
iconFile = project.file("icons/icon.icns")
|
||||
}
|
||||
windows {
|
||||
exePackageVersion = getAppVersionStringForPackaging(TargetFormat.Exe)
|
||||
msiPackageVersion = getAppVersionStringForPackaging(TargetFormat.Msi)
|
||||
exePackageVersion = getAppVersionStringForPackaging(Exe)
|
||||
msiPackageVersion = getAppVersionStringForPackaging(Msi)
|
||||
upgradeUuid = properties["INSTALLER.WINDOWS.UPGRADE_UUID"]?.toString()
|
||||
iconFile = project.file("icons/icon.ico")
|
||||
console = false
|
||||
@ -142,6 +144,32 @@ compose {
|
||||
}
|
||||
}
|
||||
|
||||
installerPlugin {
|
||||
dependsOn("createReleaseDistributable")
|
||||
outputFolder.set(layout.buildDirectory.dir("custom-installer"))
|
||||
windows {
|
||||
appName = getAppName()
|
||||
appDisplayName = getPrettifiedAppName()
|
||||
appVersion = getAppVersionStringForPackaging(Exe)
|
||||
appDisplayVersion = getAppVersionString()
|
||||
inputDir = project.file("build/compose/binaries/main-release/app/${getAppName()}")
|
||||
outputFileName = getAppName()
|
||||
licenceFile = rootProject.file("LICENSE")
|
||||
iconFile = project.file("icons/icon.ico")
|
||||
nsisTemplate = project.file("resources/installer/nsis-script-template.nsi")
|
||||
extraParams = mapOf(
|
||||
"app_publisher" to "abdownloadmanager.com",
|
||||
"app_version_with_build" to "${getAppVersionStringForPackaging(Exe)}.0",
|
||||
"source_code_url" to "https://github.com/amir1376/ab-download-manager",
|
||||
"project_website" to "www.abdownloadmanager.com",
|
||||
"copyright" to "© 2024-present AB Download Manager App",
|
||||
"header_image_file" to project.file("resources/installer/abdm-header-image.bmp"),
|
||||
"sidebar_image_file" to project.file("resources/installer/abdm-sidebar-image.bmp")
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// generate a file with these constants
|
||||
buildConfig {
|
||||
@ -240,27 +268,51 @@ val createDistributableAppArchive by tasks.registering {
|
||||
val createBinariesForCi by tasks.registering {
|
||||
val nativeDistributions = compose.desktop.application.nativeDistributions
|
||||
val mainRelease = nativeDistributions.outputBaseDir.dir("main-release")
|
||||
dependsOn("packageReleaseDistributionForCurrentOS")
|
||||
if (installerPlugin.isThisPlatformSupported()) {
|
||||
dependsOn(installerPlugin.createInstallerTask)
|
||||
inputs.dir(installerPlugin.outputFolder)
|
||||
} else {
|
||||
dependsOn("packageReleaseDistributionForCurrentOS")
|
||||
inputs.dir(mainRelease)
|
||||
}
|
||||
dependsOn(createDistributableAppArchive)
|
||||
inputs.property("appVersion", getAppVersionString())
|
||||
inputs.dir(mainRelease)
|
||||
inputs.dir(distributableAppArchiveDir)
|
||||
outputs.dir(ciDir.binariesDir)
|
||||
doLast {
|
||||
val output = ciDir.binariesDir.get().asFile
|
||||
val packageName = appPackageNameByComposePlugin
|
||||
output.deleteRecursively()
|
||||
val allowedTarget = nativeDistributions.targetFormats.filter { it.isCompatibleWithCurrentOS }
|
||||
for (target in allowedTarget) {
|
||||
CiUtils.movePackagedAndCreateSignature(
|
||||
getAppVersion(),
|
||||
packageName,
|
||||
target,
|
||||
mainRelease.get().asFile,
|
||||
output,
|
||||
)
|
||||
|
||||
if (installerPlugin.isThisPlatformSupported()) {
|
||||
val targets = installerPlugin.getCreatedInstallerTargetFormats()
|
||||
for (target in targets) {
|
||||
CiUtils.movePackagedAndCreateSignature(
|
||||
getAppVersion(),
|
||||
packageName,
|
||||
target,
|
||||
installerPlugin.outputFolder.get().asFile,
|
||||
output,
|
||||
)
|
||||
}
|
||||
logger.lifecycle("app packages for '${targets.joinToString(", ") { it.name }}' written in $output using the installer plugin")
|
||||
} else {
|
||||
val allowedTargets = nativeDistributions
|
||||
.targetFormats.filter { it.isCompatibleWithCurrentOS }
|
||||
.map {
|
||||
it.toInstallerTargetFormat()
|
||||
}
|
||||
for (target in allowedTargets) {
|
||||
CiUtils.movePackagedAndCreateSignature(
|
||||
getAppVersion(),
|
||||
packageName,
|
||||
target,
|
||||
mainRelease.get().asFile.resolve(target.outputDirName),
|
||||
output,
|
||||
)
|
||||
}
|
||||
logger.lifecycle("app packages for '${allowedTargets.joinToString(", ") { it.name }}' written in $output using compose packager tool")
|
||||
}
|
||||
logger.lifecycle("app packages for '${allowedTarget.joinToString(", ") { it.name }}' written in $output")
|
||||
val appArchiveDistributableDir = distributableAppArchiveDir.get().asFile
|
||||
CiUtils.copyAndHashToDestination(
|
||||
distributableAppArchiveDir.get().asFile.resolve(
|
||||
@ -272,7 +324,7 @@ val createBinariesForCi by tasks.registering {
|
||||
CiUtils.getTargetFileName(
|
||||
packageName,
|
||||
getAppVersion(),
|
||||
TargetFormat.AppImage,
|
||||
null, // this is not an installer (it will be automatically converted to current os name
|
||||
)
|
||||
)
|
||||
logger.lifecycle("distributable app archive written in ${output}")
|
||||
@ -299,3 +351,15 @@ val createReleaseFolderForCi by tasks.registering {
|
||||
dependsOn(createBinariesForCi, createChangeNoteForCi)
|
||||
}
|
||||
// ======= end of GitHub action stuff
|
||||
|
||||
fun TargetFormat.toInstallerTargetFormat(): InstallerTargetFormat {
|
||||
return when (this) {
|
||||
AppImage -> error("$this is not recognized as installer")
|
||||
Deb -> InstallerTargetFormat.Deb
|
||||
Rpm -> InstallerTargetFormat.Rpm
|
||||
Dmg -> InstallerTargetFormat.Dmg
|
||||
Pkg -> InstallerTargetFormat.Pkg
|
||||
Exe -> InstallerTargetFormat.Exe
|
||||
Msi -> InstallerTargetFormat.Msi
|
||||
}
|
||||
}
|
||||
|
BIN
desktop/app/resources/installer/abdm-header-image.bmp
Normal file
BIN
desktop/app/resources/installer/abdm-header-image.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
desktop/app/resources/installer/abdm-sidebar-image.bmp
Normal file
BIN
desktop/app/resources/installer/abdm-sidebar-image.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
212
desktop/app/resources/installer/nsis-script-template.nsi
Normal file
212
desktop/app/resources/installer/nsis-script-template.nsi
Normal file
@ -0,0 +1,212 @@
|
||||
Unicode True
|
||||
RequestExecutionLevel user
|
||||
SetCompressor /SOLID lzma
|
||||
!include "LogicLib.nsh"
|
||||
!include "MUI2.nsh"
|
||||
|
||||
|
||||
!define APP_PUBLISHER "{{ app_publisher }}"
|
||||
!define APP_NAME "{{ app_name }}"
|
||||
!define APP_DISPLAY_NAME "{{ app_display_name }}"
|
||||
!define APP_VERSION "{{ app_version }}"
|
||||
!define APP_VERSION_WITH_BUILD "{{ app_version_with_build }}"
|
||||
!define APP_DISPLAY_VERSION "{{ app_display_version }}"
|
||||
!define SOURCE_CODE_URL "{{ source_code_url }}"
|
||||
!define PROJECT_WEBSITE "{{ project_website }}"
|
||||
!define COPYRIGHT "{{ copyright }}"
|
||||
|
||||
!define INPUT_DIR "{{ input_dir }}"
|
||||
!define LICENSE_FILE "{{ license_file }}"
|
||||
!define MAIN_BINARY_NAME "${APP_NAME}"
|
||||
|
||||
!define SIDEBAR_IMAGE "{{ sidebar_image_file }}"
|
||||
!define HEADER_IMAGE "{{ header_image_file }}"
|
||||
!define ICON_FILE "{{ icon_file }}"
|
||||
|
||||
!define REG_UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
|
||||
!define REG_RUN_KEY "Software\Microsoft\Windows\CurrentVersion\Run\${APP_NAME}"
|
||||
!define REG_APP_KEY "Software\${APP_NAME}"
|
||||
|
||||
; icon for this installer!
|
||||
|
||||
Icon "${ICON_FILE}"
|
||||
!define MUI_ICON "${ICON_FILE}"
|
||||
!define MUI_UNICON "${ICON_FILE}"
|
||||
|
||||
!if "${SIDEBAR_IMAGE}" != ""
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "${SIDEBAR_IMAGE}"
|
||||
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${SIDEBAR_IMAGE}"
|
||||
!endif
|
||||
|
||||
!if "${HEADER_IMAGE}" != ""
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP "${HEADER_IMAGE}"
|
||||
|
||||
!define MUI_UNHEADERIMAGE
|
||||
!define MUI_UNHEADERIMAGE_BITMAP "${HEADER_IMAGE}"
|
||||
!endif
|
||||
|
||||
VIProductVersion "${APP_VERSION_WITH_BUILD}"
|
||||
VIAddVersionKey "ProductName" "${APP_DISPLAY_NAME}"
|
||||
VIAddVersionKey "FileDescription" "${APP_DISPLAY_NAME}"
|
||||
VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||
VIAddVersionKey "FileVersion" "${APP_VERSION_WITH_BUILD}"
|
||||
VIAddVersionKey "ProductVersion" "${APP_VERSION_WITH_BUILD}"
|
||||
|
||||
Name "${APP_DISPLAY_NAME}"
|
||||
OutFile "{{ output_file }}"
|
||||
|
||||
InstallDir "$LOCALAPPDATA\${APP_NAME}"
|
||||
|
||||
|
||||
|
||||
!define INSTALL_DIR `$INSTDIR`
|
||||
Function .onInit
|
||||
|
||||
; Call RestorePreviousInstallLocation
|
||||
|
||||
FunctionEnd
|
||||
|
||||
; configure instfiles page
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
||||
!define MUI_INSTFILESPAGE_NOAUTOCLOSE
|
||||
|
||||
; configure finish page
|
||||
!define MUI_FINISHPAGE_LINK "Open project in GitHub"
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "${SOURCE_CODE_URL}"
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION RunMainBinary
|
||||
|
||||
;Installation Pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
;Uninstallation Pages
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
; set language
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
; a macro clear files to cleanup installation folder
|
||||
!macro clearFiles
|
||||
RmDir /r "${INSTALL_DIR}\app"
|
||||
RmDir /r "${INSTALL_DIR}\runtime"
|
||||
Delete "${INSTALL_DIR}\${MAIN_BINARY_NAME}.exe"
|
||||
Delete "${INSTALL_DIR}\${MAIN_BINARY_NAME}.ico"
|
||||
Delete "${INSTALL_DIR}\uninstall.exe"
|
||||
RmDir "${INSTALL_DIR}"
|
||||
!macroend
|
||||
|
||||
Function RunMainBinary
|
||||
Exec "${INSTALL_DIR}\${MAIN_BINARY_NAME}.exe"
|
||||
FunctionEnd
|
||||
|
||||
!macro GetBestExecutableName result
|
||||
StrCpy ${result} "${MAIN_BINARY_NAME}.exe"
|
||||
!macroend
|
||||
|
||||
; Function RestorePreviousInstallLocation
|
||||
; ReadRegStr $4 SHCTX "${REG_APP_KEY}" "InstallPath"
|
||||
; ${if} $4 != ""
|
||||
; StrCpy $INSTDIR $4
|
||||
; ${endif}
|
||||
; FunctionEnd
|
||||
|
||||
; I should improve this.
|
||||
!macro closeApp
|
||||
!insertmacro GetBestExecutableName $1
|
||||
DetailPrint "Stopping Executable $1"
|
||||
; I don't wanna kill myself!
|
||||
${If} "$EXEFILE" != "$1"
|
||||
ExecWait 'taskkill /F /IM "$1"' $0
|
||||
${Else}
|
||||
DetailPrint "It seems that installer file name is same as app executable name"
|
||||
DetailPrint "Please close app manually"
|
||||
; don't sleep the script for nothing.
|
||||
StrCpy $0 "1"
|
||||
${EndIf}
|
||||
${If} $0 == "0"
|
||||
Sleep 500
|
||||
BringToFront ; when we sleep it seems that window goes down
|
||||
DetailPrint "Current app stopped successfully"
|
||||
${Endif}
|
||||
!macroend
|
||||
|
||||
!macro CreateStartMenu
|
||||
createDirectory "$SMPROGRAMS\${APP_DISPLAY_NAME}"
|
||||
createShortCut "$SMPROGRAMS\${APP_DISPLAY_NAME}\${APP_DISPLAY_NAME}.lnk" "${INSTALL_DIR}\${MAIN_BINARY_NAME}.exe" "" "${INSTALL_DIR}\${MAIN_BINARY_NAME}.ico"
|
||||
!macroend
|
||||
|
||||
!macro RemoveStartMenu
|
||||
RmDir /r "$SMPROGRAMS\${APP_DISPLAY_NAME}"
|
||||
!macroend
|
||||
|
||||
!macro CreateDesktopShortcut
|
||||
CreateShortcut "$DESKTOP\${APP_DISPLAY_NAME}.lnk" "${INSTALL_DIR}\${MAIN_BINARY_NAME}.exe" "" "${INSTALL_DIR}\${MAIN_BINARY_NAME}.ico"
|
||||
!macroend
|
||||
|
||||
!macro RemoveDesktopShortCut
|
||||
Delete "$DESKTOP\${APP_DISPLAY_NAME}.lnk"
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
Section "${APP_DISPLAY_NAME}"
|
||||
SectionInstType RO
|
||||
|
||||
DetailPrint "Closing app (if any)"
|
||||
!insertmacro closeApp
|
||||
DetailPrint "clearing old app (if any)"
|
||||
!insertmacro clearFiles
|
||||
DetailPrint "writing new data"
|
||||
SetOutPath "${INSTALL_DIR}"
|
||||
CreateDirectory "${INSTALL_DIR}"
|
||||
|
||||
WriteUninstaller "${INSTALL_DIR}\uninstall.exe"
|
||||
|
||||
File /nonfatal /r "${INPUT_DIR}\"
|
||||
|
||||
|
||||
; Registry information for add/remove programs
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "DisplayName" "${APP_DISPLAY_NAME}"
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "DisplayIcon" "$\"${INSTALL_DIR}\${MAIN_BINARY_NAME}.exe$\""
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "DisplayVersion" "${APP_VERSION}"
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "Publisher" "${APP_PUBLISHER}"
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "InstallLocation" "$\"${INSTALL_DIR}$\""
|
||||
WriteRegStr SHCTX "${REG_UNINSTALL_KEY}" "UninstallString" "$\"${INSTALL_DIR}\uninstall.exe$\""
|
||||
WriteRegDWORD SHCTX "${REG_UNINSTALL_KEY}" "NoModify" "1"
|
||||
WriteRegDWORD SHCTX "${REG_UNINSTALL_KEY}" "NoRepair" "1"
|
||||
|
||||
; Registry keys for app installation path and version
|
||||
WriteRegStr SHCTX "${REG_APP_KEY}" "InstallPath" "${INSTALL_DIR}"
|
||||
WriteRegStr SHCTX "${REG_APP_KEY}" "Version" "${APP_VERSION}"
|
||||
SectionEnd
|
||||
|
||||
Section "Start Menu"
|
||||
!insertmacro CreateStartMenu
|
||||
SectionEnd
|
||||
|
||||
Section "Desktop Shortcut"
|
||||
!insertmacro CreateDesktopShortcut
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
!insertmacro closeApp
|
||||
!insertmacro clearFiles
|
||||
|
||||
!insertmacro RemoveStartMenu
|
||||
!insertmacro RemoveDesktopShortCut
|
||||
|
||||
DeleteRegKey SHCTX "${REG_UNINSTALL_KEY}"
|
||||
DeleteRegKey SHCTX "${REG_APP_KEY}"
|
||||
|
||||
; remove auto start on boot registry
|
||||
DeleteRegValue SHCTX "${REG_RUN_KEY}" "${APP_NAME}"
|
||||
SectionEnd
|
@ -117,6 +117,8 @@ arrow-opticKsp = { module = "io.arrow-kt:arrow-optics-ksp-plugin", version.ref =
|
||||
androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
|
||||
osThemeDetector = { module = "com.github.Dansoftowner:jSystemThemeDetector", version.ref = "osThemeDetector" }
|
||||
|
||||
handlebarsJava = "com.github.jknack:handlebars:4.4.0"
|
||||
|
||||
[plugins]
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
|
||||
|
Loading…
x
Reference in New Issue
Block a user