Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.itsaky.androidide.build.config

import java.io.File

/**
* Utilities for running shell commands.
*
* @author Akash Yadav
*/
object ShellUtils {
fun which(cmd: String): String? = shC("which '$cmd'")

fun shC(
cmd: String,
workDir: File? = null,
redirectErrorStream: Boolean = true,
): String? {
val proc =
ProcessBuilder("sh", "-c", cmd).run {
if (workDir != null) {
directory(workDir)
}

redirectErrorStream(redirectErrorStream)
start()
}

val exitCode = proc.waitFor()
if (exitCode != 0) {
return null
}

return proc.inputStream
.bufferedReader()
.readText()
.trim()
}
}
125 changes: 65 additions & 60 deletions composite-builds/build-logic/plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,77 +18,82 @@
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform

plugins {
`kotlin-dsl`
`kotlin-dsl`
}

repositories {
google()
gradlePluginPortal()
mavenCentral()
google()
gradlePluginPortal()
mavenCentral()
}

dependencies {
implementation(libs.composite.constants)
implementation(projects.buildLogic.common)
implementation(projects.buildLogic.desugaring)
implementation(projects.buildLogic.propertiesParser)
implementation(libs.composite.constants)
implementation(projects.buildLogic.common)
implementation(projects.buildLogic.desugaring)
implementation(projects.buildLogic.propertiesParser)

implementation("com.android.tools.build:gradle:${libs.versions.agp.asProvider().get()}")
implementation(
"org.jetbrains.kotlin:kotlin-gradle-plugin:${
libs.versions.kotlin.asProvider().get()
}"
)
implementation(libs.maven.publish)
implementation("com.android.tools.build:gradle:${libs.versions.agp.asProvider().get()}")
implementation(
"org.jetbrains.kotlin:kotlin-gradle-plugin:${
libs.versions.kotlin.asProvider().get()
}",
)
implementation(libs.maven.publish)

implementation(libs.common.jkotlin)
implementation(libs.common.antlr4)
implementation(libs.google.gson)
implementation(libs.google.java.format)
implementation(libs.common.jkotlin)
implementation(libs.common.antlr4)
implementation(libs.google.gson)
implementation(libs.google.java.format)
implementation(libs.google.protobuf.gradle)

val arch = DefaultNativePlatform.getCurrentArchitecture()
val brotli4jNatives = DefaultNativePlatform.getCurrentOperatingSystem().let { os ->
when {
os.isMacOsX -> when {
arch.isArm64 -> libs.brotli4j.osx.aarch64
arch.isAmd64 -> libs.brotli4j.osx.x64
else -> throw IllegalStateException("Unsupported OSX architecture: $arch")
}
os.isWindows -> when {
arch.isArm64 -> libs.brotli4j.windows.aarch64
arch.isAmd64 -> libs.brotli4j.windows.x64
else -> throw IllegalStateException("Unsupported Windows architecture: $arch")
}
os.isLinux -> when {
arch.isArm64 -> libs.brotli4j.linux.aarch64
arch.isAmd64 -> libs.brotli4j.linux.x64
else -> throw IllegalStateException("Unsupported Linux architecture: $arch")
}
else -> throw IllegalStateException("Unsupported OS: $os")
}
}
val arch = DefaultNativePlatform.getCurrentArchitecture()
val brotli4jNatives =
DefaultNativePlatform.getCurrentOperatingSystem().let { os ->
when {
os.isMacOsX ->
when {
arch.isArm64 -> libs.brotli4j.osx.aarch64
arch.isAmd64 -> libs.brotli4j.osx.x64
else -> throw IllegalStateException("Unsupported OSX architecture: $arch")
}
os.isWindows ->
when {
arch.isArm64 -> libs.brotli4j.windows.aarch64
arch.isAmd64 -> libs.brotli4j.windows.x64
else -> throw IllegalStateException("Unsupported Windows architecture: $arch")
}
os.isLinux ->
when {
arch.isArm64 -> libs.brotli4j.linux.aarch64
arch.isAmd64 -> libs.brotli4j.linux.x64
else -> throw IllegalStateException("Unsupported Linux architecture: $arch")
}
else -> throw IllegalStateException("Unsupported OS: $os")
}
}

implementation(libs.brotli4j)
runtimeOnly(brotli4jNatives)
implementation(libs.brotli4j)
runtimeOnly(brotli4jNatives)
}

gradlePlugin {
plugins {
create("com.itsaky.androidide.build") {
id = "com.itsaky.androidide.build"
implementationClass = "com.itsaky.androidide.plugins.AndroidIDEPlugin"
}
create("com.itsaky.androidide.build.propsparser") {
id = "com.itsaky.androidide.build.propsparser"
implementationClass = "com.itsaky.androidide.plugins.PropertiesParserPlugin"
}
create("com.itsaky.androidide.build.lexergenerator") {
id = "com.itsaky.androidide.build.lexergenerator"
implementationClass = "com.itsaky.androidide.plugins.LexerGeneratorPlugin"
}
create("com.itsaky.androidide.build.external-assets") {
id = "com.itsaky.androidide.build.external-assets"
implementationClass = "com.itsaky.androidide.plugins.ExternalAssetsPlugin"
}
}
plugins {
create("com.itsaky.androidide.build") {
id = "com.itsaky.androidide.build"
implementationClass = "com.itsaky.androidide.plugins.AndroidIDEPlugin"
}
create("com.itsaky.androidide.build.propsparser") {
id = "com.itsaky.androidide.build.propsparser"
implementationClass = "com.itsaky.androidide.plugins.PropertiesParserPlugin"
}
create("com.itsaky.androidide.build.lexergenerator") {
id = "com.itsaky.androidide.build.lexergenerator"
implementationClass = "com.itsaky.androidide.plugins.LexerGeneratorPlugin"
}
create("com.itsaky.androidide.build.external-assets") {
id = "com.itsaky.androidide.build.external-assets"
implementationClass = "com.itsaky.androidide.plugins.ExternalAssetsPlugin"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,63 +17,70 @@

package com.itsaky.androidide.plugins

import com.android.build.gradle.BaseExtension
import com.itsaky.androidide.build.config.KEY_ALIAS
import com.itsaky.androidide.build.config.KEY_PASS
import com.itsaky.androidide.build.config.KEY_STORE_PASS
import com.android.build.gradle.BaseExtension
import com.itsaky.androidide.build.config.isFDroidBuild
import com.itsaky.androidide.build.config.signingKey
import com.itsaky.androidide.plugins.util.SigningKeyUtils.downloadSigningKey
import com.itsaky.androidide.plugins.util.SigningKeyUtils.getEnvOrProp
import com.itsaky.androidide.build.config.isFDroidBuild
import org.gradle.api.Plugin
import org.gradle.api.Project
import com.itsaky.androidide.build.config.signingKey

/**
* Configures the signing keys to application modules.
*
* @author Akash Yadav
*/
class SigningConfigPlugin : Plugin<Project> {
companion object {
private var warned = false
}

override fun apply(target: Project) {
target.run {

if (isFDroidBuild) {
logger.warn("!!! Do not apply ${javaClass.simpleName} when building or F-Droid.")
return
}
override fun apply(target: Project) {
target.run {
if (isFDroidBuild) {
logger.warn("!!! Do not apply ${javaClass.simpleName} when building or F-Droid.")
return
}

// Download the signing key
downloadSigningKey()
// Download the signing key
downloadSigningKey()

// Create and apply the signing config
extensions.getByType(BaseExtension::class.java).let { extension ->
// Keystore credentials
val alias = getEnvOrProp(KEY_ALIAS)
val storePass = getEnvOrProp(KEY_STORE_PASS)
val keyPass = getEnvOrProp(KEY_PASS)
// Create and apply the signing config
extensions.getByType(BaseExtension::class.java).let { extension ->
// Keystore credentials
val alias = getEnvOrProp(KEY_ALIAS)
val storePass = getEnvOrProp(KEY_STORE_PASS)
val keyPass = getEnvOrProp(KEY_PASS)

val signingKey = signingKey.get().asFile
val signingKey = signingKey.get().asFile

if (alias != null && storePass != null && keyPass != null && signingKey.exists()) {
val config = extension.signingConfigs.create("common") {
storeFile = signingKey
keyAlias = alias
storePassword = storePass
keyPassword = keyPass
}
if (alias != null && storePass != null && keyPass != null && signingKey.exists()) {
val config =
extension.signingConfigs.create("common") {
storeFile = signingKey
keyAlias = alias
storePassword = storePass
keyPassword = keyPass
}

extension.buildTypes.forEach { buildType ->
buildType.signingConfig = config
}
} else {
logger.warn(
"Signing info not configured. keystoreFile=$signingKey[exists=${signingKey.exists()}]"
)
extension.buildTypes.forEach { buildType ->
buildType.signingConfig = config
}
} else {
if (!warned) {
warned = true
logger.warn(
"Signing info not configured. " +
"keystoreFile=$signingKey[exists=${signingKey.exists()}]",
)
}

null
}
}
}
}
}
null
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.itsaky.androidide.plugins.conf

import com.google.protobuf.gradle.ProtobufExtension
import com.itsaky.androidide.build.config.BuildConfig
import com.itsaky.androidide.build.config.ShellUtils
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import java.io.File

fun Project.configureProtoc(
protobuf: ProtobufExtension,
protocVersion: Provider<String>,
) {
if (configureOnDeviceProtoc(protobuf)) return

configureProtocArtifact(protobuf, protocVersion)
}

private fun Project.configureOnDeviceProtoc(protobuf: ProtobufExtension): Boolean {
if (isTermuxAppPackageNameSet() || isTermuxJdk()) {
// this is an on-device build
// find path to the protoc binary

val protocPath = ShellUtils.which("protoc")
if (protocPath == null) {
logger.warn(
"Unable to get path to protoc binary for on-device build." +
" Falling back to using maven artifact, which is likely to fail.",
)
return false
}

val protoc = File(protocPath)
if (!protoc.exists()) {
logger.warn(
"protoc path $protocPath does not exist." +
" Falling back to using maven artifact",
)
return false
}

if (!protoc.canExecute()) {
logger.warn(
"protoc path $protocPath is not executable." +
" Falling back to using maven artifact",
)
return false
}

logger.lifecycle("Using protoc from $protocPath")
protobuf.protoc {
path = protoc.absolutePath
}

return true
}

return false
}

fun Project.configureProtocArtifact(
protobuf: ProtobufExtension,
protocVersion: Provider<String>,
) {
val protocModule = "com.google.protobuf:protoc:${protocVersion.get()}"
logger.lifecycle("Using protoc module: $protocModule")

protobuf.protoc {
artifact = protocModule
}
}

fun isTermuxAppPackageNameSet() = System.getenv("TERMUX_APP__PACKAGE_NAME") == BuildConfig.PACKAGE_NAME

fun isTermuxJdk() =
System.getProperty("java.vendor") == "Termux" ||
System.getProperty("java.vm.vendor") == "Termux"
Loading