From bea9a603526f4cf1b2d20c8a9abc4aaa080806c4 Mon Sep 17 00:00:00 2001 From: Sergey Chelombitko Date: Wed, 31 Jul 2024 19:21:54 +0100 Subject: [PATCH] Simplify ADB lookup --- .../marathon/ConfigurationFactory.kt | 13 ++-- .../com/malinskiy/marathon/MarathonPlugin.kt | 5 +- .../malinskiy/marathon/android/AdbFinder.kt | 52 +++++++++++++ .../malinskiy/marathon/android/SdkFinder.kt | 73 ------------------- .../marathon/android/AndroidConfiguration.kt | 2 +- .../android/ddmlib/DdmlibAndroidDevice.kt | 3 +- .../android/ddmlib/DdmlibDeviceProvider.kt | 9 +-- .../android/ddmlib/shell/CliLogcatReceiver.kt | 4 +- .../marathon/android/AndroidDeviceSpek.kt | 7 +- .../android/AndroidDeviceTestRunnerSpek.kt | 4 +- 10 files changed, 76 insertions(+), 96 deletions(-) create mode 100644 marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/AdbFinder.kt delete mode 100644 marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/SdkFinder.kt diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt index dc6805ecb..d3217343c 100644 --- a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt +++ b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/ConfigurationFactory.kt @@ -8,15 +8,14 @@ import com.malinskiy.marathon.android.DEFAULT_USED_STORAGE_THRESHOLD_PERCENTS import com.malinskiy.marathon.android.serial.SerialStrategy import com.malinskiy.marathon.execution.Configuration import ddmlibModule -import org.gradle.api.Project import java.io.File internal fun createCommonConfiguration( - project: Project, extensionConfig: MarathonExtension, - sdkDirectory: File + adbPath: File, + outputDir: File ): Configuration = Configuration( - outputDir = project.layout.buildDirectory.dir("reports/marathon").get().asFile, + outputDir = outputDir, customAnalyticsTracker = extensionConfig.customAnalyticsTracker, poolingStrategy = extensionConfig.poolingStrategy?.toStrategy(), shardingStrategy = extensionConfig.shardingStrategy?.toStrategy(), @@ -39,10 +38,10 @@ internal fun createCommonConfiguration( testOutputTimeoutMillis = extensionConfig.testOutputTimeoutMillis, noDevicesTimeoutMillis = extensionConfig.noDevicesTimeoutMillis, debug = extensionConfig.debug, - vendorConfiguration = createAndroidConfiguration(extension = extensionConfig, sdkDirectory = sdkDirectory) + vendorConfiguration = createAndroidConfiguration(extensionConfig, adbPath) ) -private fun createAndroidConfiguration(extension: MarathonExtension, sdkDirectory: File): AndroidConfiguration { +private fun createAndroidConfiguration(extension: MarathonExtension, adbPath: File): AndroidConfiguration { val autoGrantPermission = extension.autoGrantPermission ?: DEFAULT_AUTO_GRANT_PERMISSION val instrumentationArgs = extension.instrumentationArgs val applicationPmClear = extension.applicationPmClear ?: DEFAULT_APPLICATION_PM_CLEAR @@ -63,7 +62,7 @@ private fun createAndroidConfiguration(extension: MarathonExtension, sdkDirector val usedStorageThresholdInPercents = extension.usedStorageThresholdInPercents ?: DEFAULT_USED_STORAGE_THRESHOLD_PERCENTS return AndroidConfiguration( - sdkDirectory, + adbPath, listOf(ddmlibModule), autoGrantPermission, instrumentationArgs, diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonPlugin.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonPlugin.kt index 68fd2f66d..d05db510b 100644 --- a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonPlugin.kt +++ b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/MarathonPlugin.kt @@ -7,7 +7,7 @@ import com.android.build.api.variant.Component import com.android.build.api.variant.GeneratesTestApk import com.android.build.api.variant.TestVariant import com.android.build.api.variant.Variant -import com.malinskiy.marathon.android.androidSdkLocation +import com.malinskiy.marathon.android.findAdbPath import com.malinskiy.marathon.worker.MarathonWorker import org.gradle.api.Plugin import org.gradle.api.Project @@ -34,7 +34,8 @@ class MarathonPlugin : Plugin { tasks.register(WORKER_TASK_NAME, MarathonWorkerRunTask::class.java) gradle.projectsEvaluated { - val configuration = createCommonConfiguration(project, marathonConfig, androidSdkLocation) + val outputDir = layout.buildDirectory.dir("reports/marathon").get().asFile + val configuration = createCommonConfiguration(marathonConfig, findAdbPath(projectDir), outputDir) MarathonWorker.initialize(configuration) } } diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/AdbFinder.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/AdbFinder.kt new file mode 100644 index 000000000..deb33cb01 --- /dev/null +++ b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/AdbFinder.kt @@ -0,0 +1,52 @@ +package com.malinskiy.marathon.android + +import com.android.SdkConstants.FN_LOCAL_PROPERTIES +import java.io.File +import java.util.* + +fun findAdbPath(rootDir: File): File { + val localProperties = File(rootDir, FN_LOCAL_PROPERTIES) + val properties = Properties() + + if (localProperties.isFile) { + localProperties.bufferedReader().use { + properties.load(it) + } + } + + return findSdkLocation(properties, rootDir) + ?.resolve("platform-tools") + ?.resolve("adb") + ?: throw RuntimeException("SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.") +} + +private fun findSdkLocation(properties: Properties, rootDir: File): File? { + var sdkDirProp: String? = properties.getProperty("sdk.dir") + if (sdkDirProp != null) { + var sdk = File(sdkDirProp) + if (!sdk.isAbsolute) { + sdk = rootDir.resolve(sdkDirProp) + } + return sdk + } + + sdkDirProp = properties.getProperty("android.dir") + if (sdkDirProp != null) { + return rootDir.resolve(sdkDirProp) + } + + val envVar = System.getenv("ANDROID_HOME") + if (envVar != null) { + var sdk = File(envVar) + if (!sdk.isAbsolute) { + sdk = rootDir.resolve(envVar) + } + return sdk + } + + val property = System.getProperty("android.home") + return when { + property != null -> File(property) + else -> null + } +} diff --git a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/SdkFinder.kt b/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/SdkFinder.kt deleted file mode 100644 index ee455997b..000000000 --- a/marathon-gradle-plugin/src/main/kotlin/com/malinskiy/marathon/android/SdkFinder.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.malinskiy.marathon.android - -import com.android.SdkConstants.FN_LOCAL_PROPERTIES -import com.google.common.base.Charsets -import com.google.common.io.Closeables -import org.gradle.api.Project -import java.io.File -import java.io.FileInputStream -import java.io.FileNotFoundException -import java.io.IOException -import java.io.InputStreamReader -import java.util.* - -val Project.androidSdkLocation: File - get() { - val rootDir = project.rootDir - val localProperties = File(rootDir, FN_LOCAL_PROPERTIES) - val properties = Properties() - - if (localProperties.isFile) { - var reader: InputStreamReader? = null - try { - val fis = FileInputStream(localProperties) - reader = InputStreamReader(fis, Charsets.UTF_8) - properties.load(reader) - } catch (ignored: FileNotFoundException) { - } catch (e: IOException) { - throw RuntimeException( - String.format("Unable to read %1\$s.", localProperties.absolutePath), e - ) - } finally { - try { - Closeables.close(reader, true) - } catch (e: IOException) { - // ignore. - } - } - } - - return findSdkLocation(properties, rootDir) - ?: throw RuntimeException("SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.") - } - -private fun findSdkLocation(properties: Properties, rootDir: File): File? { - var sdkDirProp: String? = properties.getProperty("sdk.dir") - if (sdkDirProp != null) { - var sdk = File(sdkDirProp) - if (!sdk.isAbsolute) { - sdk = rootDir.resolve(sdkDirProp) - } - return sdk - } - - sdkDirProp = properties.getProperty("android.dir") - if (sdkDirProp != null) { - return rootDir.resolve(sdkDirProp) - } - - val envVar = System.getenv("ANDROID_HOME") - if (envVar != null) { - var sdk = File(envVar) - if (!sdk.isAbsolute) { - sdk = rootDir.resolve(envVar) - } - return sdk - } - - val property = System.getProperty("android.home") - return when { - property != null -> File(property) - else -> null - } -} diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt index 732502967..1e26c4c55 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/AndroidConfiguration.kt @@ -14,7 +14,7 @@ const val DEFAULT_INSTALL_OPTIONS = "" const val DEFAULT_USED_STORAGE_THRESHOLD_PERCENTS = 85 data class AndroidConfiguration( - val androidSdk: File, + val adbPath: File, val implementationModules: List, val autoGrantPermission: Boolean = DEFAULT_AUTO_GRANT_PERMISSION, val instrumentationArgs: Map = emptyMap(), diff --git a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibAndroidDevice.kt b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibAndroidDevice.kt index 981f858d4..53266c4a2 100644 --- a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibAndroidDevice.kt +++ b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibAndroidDevice.kt @@ -58,6 +58,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.newFixedThreadPoolContext import kotlinx.coroutines.runBlocking import java.awt.image.BufferedImage +import java.io.File import java.io.IOException import java.util.* import java.util.concurrent.TimeUnit @@ -65,7 +66,7 @@ import kotlin.coroutines.CoroutineContext class DdmlibAndroidDevice( val ddmsDevice: IDevice, - private val adbPath: String, + private val adbPath: File, private val track: Track, private val timer: Timer, private val androidAppInstaller: AndroidAppInstaller, diff --git a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibDeviceProvider.kt b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibDeviceProvider.kt index 0929db9ac..a45d10132 100644 --- a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibDeviceProvider.kt +++ b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibDeviceProvider.kt @@ -26,7 +26,6 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.newFixedThreadPoolContext -import java.nio.file.Paths import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentMap import java.util.concurrent.atomic.AtomicBoolean @@ -66,7 +65,7 @@ class DdmlibDeviceProvider( DdmPreferences.setTimeOut(DEFAULT_DDM_LIB_TIMEOUT) AndroidDebugBridge.initIfNeeded(false) - val absolutePath = Paths.get(vendorConfiguration.androidSdk.absolutePath, "platform-tools", "adb").toFile().absolutePath + val adbPath = vendorConfiguration.adbPath listener = object : AndroidDebugBridge.IDeviceChangeListener { override fun deviceChanged(device: IDevice, changeMask: Int) { @@ -76,7 +75,7 @@ class DdmlibDeviceProvider( val maybeNewAndroidDevice = DdmlibAndroidDevice( device, - absolutePath, + adbPath, track, timer, androidAppInstaller, @@ -113,7 +112,7 @@ class DdmlibDeviceProvider( androidAppInstaller = androidAppInstaller, attachmentManager = attachmentManager, reportsFileManager = fileManager, - adbPath = absolutePath, + adbPath = adbPath, logcatListener = logcatListener, strictRunChecker = strictRunChecker ) @@ -181,7 +180,7 @@ class DdmlibDeviceProvider( } } AndroidDebugBridge.addDeviceChangeListener(listener) - adb = AndroidDebugBridge.createBridge(absolutePath, false) + adb = AndroidDebugBridge.createBridge(adbPath.absolutePath, false) logger.debug { "Created ADB bridge" } var getDevicesCountdown = config.noDevicesTimeoutMillis diff --git a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/shell/CliLogcatReceiver.kt b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/shell/CliLogcatReceiver.kt index c0ec48409..034dc17fc 100644 --- a/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/shell/CliLogcatReceiver.kt +++ b/vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/shell/CliLogcatReceiver.kt @@ -11,7 +11,7 @@ import java.text.SimpleDateFormat import java.util.* class CliLogcatReceiver( - private val adbPath: String, + private val adbPath: File, private val fileManager: FileManager, private val device: IDevice, private val listener: (List) -> Unit @@ -43,7 +43,7 @@ class CliLogcatReceiver( vararg command: String ): Process = spawnProcess( - command = arrayOf(adbPath, "-s", device.serialNumber) + command, + command = arrayOf(adbPath.absolutePath, "-s", device.serialNumber) + command, outputTo = redirectOutputTo ) diff --git a/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceSpek.kt b/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceSpek.kt index 1fc19e9d9..4d9472c73 100644 --- a/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceSpek.kt +++ b/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceSpek.kt @@ -13,6 +13,7 @@ import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.describe import org.jetbrains.spek.api.dsl.it import org.mockito.kotlin.whenever +import java.io.File import java.time.Clock class AndroidDeviceSpek : Spek( @@ -28,7 +29,7 @@ class AndroidDeviceSpek : Spek( whenever(iDevice.getProperty("ro.product.model")).thenReturn(null) DdmlibAndroidDevice( iDevice, - "", + File("adb"), track, timer, appInstaller, @@ -43,7 +44,7 @@ class AndroidDeviceSpek : Spek( whenever(iDevice.getProperty("ro.product.manufacturer")).thenReturn(null) DdmlibAndroidDevice( iDevice, - "", + File("adb"), track, timer, appInstaller, @@ -60,7 +61,7 @@ class AndroidDeviceSpek : Spek( whenever(iDevice.getProperty("ro.build.version.sdk")).thenReturn("INVALID_VERSION") DdmlibAndroidDevice( iDevice, - "", + File("adb"), track, timer, appInstaller, diff --git a/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceTestRunnerSpek.kt b/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceTestRunnerSpek.kt index 92e2567d4..e62fa9846 100644 --- a/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceTestRunnerSpek.kt +++ b/vendor/vendor-android/ddmlib/src/test/kotlin/com/malinskiy/marathon/android/AndroidDeviceTestRunnerSpek.kt @@ -35,7 +35,7 @@ class AndroidDeviceTestRunnerSpek : Spek( val appInstaller = mock() val device = DdmlibAndroidDevice( ddmsDevice, - "", + File("adb"), Track(), SystemTimer(Clock.systemDefaultZone()), appInstaller, @@ -73,7 +73,7 @@ class AndroidDeviceTestRunnerSpek : Spek( noDevicesTimeoutMillis = null, debug = null, vendorConfiguration = AndroidConfiguration( - androidSdk = File(""), + adbPath = File("adb"), implementationModules = emptyList() ) )