Alexey Tsvetkov
4 years ago
committed by
GitHub
12 changed files with 303 additions and 20 deletions
@ -0,0 +1,39 @@
|
||||
package org.jetbrains.compose.desktop.application.internal |
||||
|
||||
import org.gradle.api.Project |
||||
import org.gradle.api.provider.Provider |
||||
import org.jetbrains.compose.desktop.application.dsl.Application |
||||
import org.jetbrains.compose.desktop.application.dsl.NativeDistributions |
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat |
||||
|
||||
internal fun packageVersionFor( |
||||
project: Project, |
||||
app: Application, |
||||
targetFormat: TargetFormat |
||||
): Provider<String?> = |
||||
project.provider { |
||||
app.nativeDistributions.packageVersionFor(targetFormat) |
||||
?: project.version.toString().takeIf { it != "unspecified" } |
||||
} |
||||
|
||||
private fun NativeDistributions.packageVersionFor( |
||||
targetFormat: TargetFormat |
||||
): String? { |
||||
val formatSpecificVersion: String? = when (targetFormat) { |
||||
TargetFormat.AppImage -> null |
||||
TargetFormat.Deb -> linux.debPackageVersion |
||||
TargetFormat.Rpm -> linux.rpmPackageVersion |
||||
TargetFormat.Dmg -> macOS.dmgPackageVersion |
||||
TargetFormat.Pkg -> macOS.pkgPackageVersion |
||||
TargetFormat.Exe -> windows.exePackageVersion |
||||
TargetFormat.Msi -> windows.msiPackageVersion |
||||
} |
||||
val osSpecificVersion: String? = when (targetFormat.targetOS) { |
||||
OS.Linux -> linux.packageVersion |
||||
OS.MacOS -> macOS.packageVersion |
||||
OS.Windows -> windows.packageVersion |
||||
} |
||||
return formatSpecificVersion |
||||
?: osSpecificVersion |
||||
?: packageVersion |
||||
} |
@ -0,0 +1,164 @@
|
||||
package org.jetbrains.compose.desktop.application.internal.validation |
||||
|
||||
import org.gradle.api.GradleException |
||||
import org.gradle.api.Project |
||||
import org.jetbrains.compose.desktop.application.dsl.Application |
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat |
||||
import org.jetbrains.compose.desktop.application.internal.OS |
||||
import org.jetbrains.compose.desktop.application.internal.packageVersionFor |
||||
|
||||
internal fun Project.validatePackageVersions(app: Application) { |
||||
val errors = ErrorsCollector() |
||||
|
||||
for (targetFormat in app.nativeDistributions.targetFormats) { |
||||
val packageVersion = packageVersionFor(project, app, targetFormat).orNull |
||||
if (packageVersion == null) { |
||||
errors.addError(targetFormat, "no version was specified") |
||||
continue |
||||
} |
||||
|
||||
val versionChecker: VersionChecker? = when (targetFormat) { |
||||
TargetFormat.AppImage -> null |
||||
TargetFormat.Deb -> DebVersionChecker |
||||
TargetFormat.Rpm -> RpmVersionChecker |
||||
TargetFormat.Msi, TargetFormat.Exe -> WindowsVersionChecker |
||||
TargetFormat.Dmg, TargetFormat.Pkg -> MacVersionChecker |
||||
} |
||||
|
||||
versionChecker?.apply { |
||||
if (!isValid(packageVersion)) { |
||||
errors.addError( |
||||
targetFormat, |
||||
"'$packageVersion' is not a valid version", |
||||
correctFormat = correctFormat |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (errors.errors.isNotEmpty()) { |
||||
throw GradleException(errors.errors.joinToString("\n")) |
||||
} |
||||
} |
||||
|
||||
private class ErrorsCollector { |
||||
private val myErrors = arrayListOf<String>() |
||||
|
||||
val errors: List<String> |
||||
get() = myErrors |
||||
|
||||
fun addError( |
||||
targetFormat: TargetFormat, |
||||
error: String, |
||||
correctFormat: String? = null |
||||
) { |
||||
val msg = buildString { |
||||
appendln("* Illegal version for '$targetFormat': $error.") |
||||
if (correctFormat != null) { |
||||
appendln(" * Correct format: $correctFormat") |
||||
} |
||||
appendln(" * You can specify the correct version using DSL properties: " + |
||||
dslPropertiesFor(targetFormat).joinToString(", ") |
||||
) |
||||
} |
||||
myErrors.add(msg) |
||||
} |
||||
} |
||||
|
||||
private fun dslPropertiesFor( |
||||
targetFormat: TargetFormat |
||||
): List<String> { |
||||
val nativeDistributions = "nativeDistributions" |
||||
val linux = "$nativeDistributions.linux" |
||||
val macOS = "$nativeDistributions.macOS" |
||||
val windows = "$nativeDistributions.windows" |
||||
val packageVersion = "packageVersion" |
||||
|
||||
val formatSpecificProperty: String? = when (targetFormat) { |
||||
TargetFormat.AppImage -> null |
||||
TargetFormat.Deb -> "$linux.debPackageVersion" |
||||
TargetFormat.Rpm -> "$linux.rpmPackageVersion" |
||||
TargetFormat.Dmg -> "$macOS.dmgPackageVersion" |
||||
TargetFormat.Pkg -> "$macOS.pkgPackageVersion" |
||||
TargetFormat.Exe -> "$windows.exePackageVersion" |
||||
TargetFormat.Msi -> "$windows.msiPackageVersion" |
||||
} |
||||
val osSettingsProperty: String = when (targetFormat.targetOS) { |
||||
OS.Linux -> "$linux.$packageVersion" |
||||
OS.MacOS -> "$macOS.$packageVersion" |
||||
OS.Windows -> "$windows.$packageVersion" |
||||
} |
||||
val appSpecificProperty = "$nativeDistributions.$packageVersion" |
||||
return listOfNotNull( |
||||
formatSpecificProperty, |
||||
osSettingsProperty, |
||||
appSpecificProperty, |
||||
) |
||||
} |
||||
|
||||
private interface VersionChecker { |
||||
val correctFormat: String |
||||
fun isValid(version: String): Boolean |
||||
} |
||||
|
||||
private object DebVersionChecker : VersionChecker { |
||||
override val correctFormat = """|'[EPOCH:]UPSTREAM_VERSION[-DEBIAN_REVISION]', where: |
||||
| * EPOCH is an optional non-negative integer; |
||||
| * UPSTREAM_VERSION may contain only alphanumerics and the characters '.', '+', '-', '~' and must start with a digit; |
||||
| * DEBIAN_REVISION is optional and may contain only alphanumerics and the characters '.', '+', '~'; |
||||
| * see https://www.debian.org/doc/debian-policy/ch-controlfields.html#version for details; |
||||
""".trimMargin() |
||||
|
||||
override fun isValid(version: String): Boolean = |
||||
version.matches(debRegex) |
||||
|
||||
private val debRegex = ( |
||||
/* EPOCH */"([0-9]+:)?" + |
||||
/* UPSTREAM_VERSION */ "[0-9][0-9a-zA-Z.+\\-~]*" + |
||||
/* DEBIAN_REVISION */ "(-[0-9a-zA-Z.+~]+)?").toRegex() |
||||
} |
||||
|
||||
private object RpmVersionChecker : VersionChecker { |
||||
override val correctFormat = "rpm package version must not contain a dash '-'" |
||||
|
||||
override fun isValid(version: String): Boolean = |
||||
!version.contains("-") |
||||
} |
||||
|
||||
private object WindowsVersionChecker : VersionChecker { |
||||
override val correctFormat = """|'MAJOR.MINOR.BUILD', where: |
||||
| * MAJOR is a non-negative integer with a maximum value of 255; |
||||
| * MINOR is a non-negative integer with a maximum value of 255; |
||||
| * BUILD is a non-negative integer with a maximum value of 65535; |
||||
""".trimMargin() |
||||
|
||||
override fun isValid(version: String): Boolean { |
||||
val parts = version.split(".").map { it.toIntOrNull() } |
||||
if (parts.size != 3) return false |
||||
|
||||
return parts[0].isIntInRange(0, 255) |
||||
&& parts[1].isIntInRange(0, 255) |
||||
&& parts[2].isIntInRange(0, 65535) |
||||
} |
||||
|
||||
private fun Int?.isIntInRange(min: Int, max: Int) = |
||||
this != null && this >= min && this <= max |
||||
} |
||||
|
||||
|
||||
private object MacVersionChecker : VersionChecker { |
||||
override val correctFormat = """|'MAJOR[.MINOR][.PATCH]', where: |
||||
| * MAJOR is an integer > 0; |
||||
| * MINOR is an optional non-negative integer; |
||||
| * PATCH is an optional non-negative integer; |
||||
""".trimMargin() |
||||
|
||||
override fun isValid(version: String): Boolean { |
||||
val parts = version.split(".").map { it.toIntOrNull() } |
||||
|
||||
return parts.isNotEmpty() |
||||
&& parts.size <= 3 |
||||
&& parts.all { it != null && it >= 0 } |
||||
&& (parts.first() ?: 0) > 0 |
||||
} |
||||
} |
Loading…
Reference in new issue