-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Kaspresso plugin #417
base: master
Are you sure you want to change the base?
Add Kaspresso plugin #417
Changes from all commits
ee5755d
863ba3f
9b6cd4a
29fe1cf
d4e627a
537f89f
3be8743
c4def6c
2c22a44
af29ff2
5ea1b01
1a02316
6a0c52d
1467593
8ed449d
2a86a0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.kaspersky.adbserver.desktop | ||
|
||
import com.kaspersky.adbserver.common.api.CommandResult | ||
import java.nio.file.Path | ||
|
||
/** | ||
* @param adbPath - path to adb binary | ||
*/ | ||
class AdbCommandPerformer( | ||
private val adbPath: Path, | ||
private val cmdCommandPerformer: CmdCommandPerformer, | ||
) { | ||
|
||
/** | ||
* Be aware it's a synchronous method | ||
* @param command - adb command without path to adb binaries | ||
*/ | ||
fun perform(command: String): CommandResult { | ||
return cmdCommandPerformer.perform("$adbPath $command") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import java.lang.UnsupportedOperationException | |
|
||
internal class CommandExecutorImpl( | ||
private val cmdCommandPerformer: CmdCommandPerformer, | ||
private val adbCommandPerformer: AdbCommandPerformer, | ||
private val deviceName: String, | ||
private val adbServerPort: String?, | ||
private val logger: Logger | ||
|
@@ -19,9 +20,9 @@ internal class CommandExecutorImpl( | |
return when (command) { | ||
is CmdCommand -> cmdCommandPerformer.perform(command.body) | ||
is AdbCommand -> { | ||
val adbCommand = "adb ${ adbServerPort?.let { "-P $adbServerPort " } ?: "" }-s $deviceName ${command.body}" | ||
logger.d("The created adbCommand=$adbCommand") | ||
cmdCommandPerformer.perform(adbCommand) | ||
val adbCommand = "${ adbServerPort?.let { "-P $adbServerPort " } ?: "" }-s $deviceName ${command.body}" | ||
logger.d("The created adbCommand=adb $adbCommand") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be cool to print out actual adb path since it's configurable. Otherwise it may mislead someone during adb related issues debugging There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this good idea. I'm add print adb path to log at server startup. |
||
adbCommandPerformer.perform(adbCommand) | ||
} | ||
else -> throw UnsupportedOperationException("The command=$command is unsupported command") | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,31 +3,66 @@ package com.kaspersky.adbserver.desktop | |
import com.kaspersky.adbserver.common.api.ExecutorResultStatus | ||
import com.kaspersky.adbserver.common.log.LoggerFactory | ||
import com.kaspersky.adbserver.common.log.logger.DesktopLogger | ||
import java.util.concurrent.atomic.AtomicBoolean | ||
import java.util.regex.Pattern | ||
import kotlin.concurrent.thread | ||
|
||
internal class Desktop( | ||
class Desktop( | ||
private val cmdCommandPerformer: CmdCommandPerformer, | ||
private val adbCommandPerformer: AdbCommandPerformer, | ||
private val presetEmulators: List<String>, | ||
private val adbServerPort: String?, | ||
private val logger: DesktopLogger | ||
) { | ||
|
||
companion object { | ||
private const val PAUSE_MS = 500L | ||
private val DEVICE_PATTERN = Pattern.compile("^([a-zA-Z0-9\\-:.]+)(\\s+)(device)") | ||
} | ||
|
||
private val devices: MutableCollection<DeviceMirror> = mutableListOf() | ||
private var isRunning = AtomicBoolean(false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it accessed from multiple threads? |
||
|
||
fun startDevicesObserving() { | ||
/** | ||
* Start Desktop server. | ||
* Blocking current thread while server working | ||
* @throws IllegalStateException - if server already running | ||
*/ | ||
fun startDevicesObservingSync() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I would just mention that this method is blocking in documentation as you did in AdbCommandPerformer::perform. I think blocking behavior is an expected one. Another hint is that there's startDevicesObservingAsync There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I'm add documentation to this methods |
||
if (!isRunning.compareAndSet(false, true)) error("Desktop already running") | ||
startDevicesObservingInternal() | ||
} | ||
|
||
/** | ||
* Start Desktop server asynchronously | ||
* @throws IllegalStateException - if server already running | ||
*/ | ||
fun startDevicesObservingAsync() { | ||
if (!isRunning.compareAndSet(false, true)) error("Desktop already running") | ||
thread { | ||
startDevicesObservingInternal() | ||
} | ||
} | ||
|
||
/** | ||
* Stop Desktop server | ||
* @throws IllegalStateException - if server already stopped | ||
*/ | ||
fun stopDevicesObserving() { | ||
if (!isRunning.compareAndSet(true, false)) error("Desktop already stopped") | ||
} | ||
|
||
private fun startDevicesObservingInternal() { | ||
logger.d("start") | ||
while (true) { | ||
while (isRunning.get()) { | ||
val namesOfAttachedDevicesByAdb = getAttachedDevicesByAdb() | ||
namesOfAttachedDevicesByAdb.forEach { deviceName -> | ||
if (devices.find { client -> client.deviceName == deviceName } == null) { | ||
logger.i("New device has been found: $deviceName. Initialize connection to the device...") | ||
val deviceMirror = | ||
DeviceMirror.create( | ||
cmdCommandPerformer, | ||
adbCommandPerformer, | ||
deviceName, | ||
adbServerPort, | ||
LoggerFactory.getDesktopLoggerReflectingDevice(logger, deviceName) | ||
|
@@ -47,18 +82,22 @@ internal class Desktop( | |
} | ||
Thread.sleep(PAUSE_MS) | ||
} | ||
|
||
devices.forEach { client -> | ||
client.stopConnectionToDevice() | ||
} | ||
devices.clear() | ||
} | ||
|
||
private fun getAttachedDevicesByAdb(): List<String> { | ||
val pattern = Pattern.compile("^([a-zA-Z0-9\\-:.]+)(\\s+)(device)") | ||
val commandResult = cmdCommandPerformer.perform("adb devices") | ||
val commandResult = adbCommandPerformer.perform("devices") | ||
if (commandResult.status != ExecutorResultStatus.SUCCESS) { | ||
return emptyList() | ||
} | ||
val adbDevicesCommandResult: String = commandResult.description | ||
return adbDevicesCommandResult.lines() | ||
.asSequence() | ||
.map { pattern.matcher(it) } | ||
.map { DEVICE_PATTERN.matcher(it) } | ||
.filter { matcher -> matcher.find() } | ||
.map { matcher -> matcher.group(1) } | ||
.filter { foundEmulator -> presetEmulators.isEmpty() || presetEmulators.contains(foundEmulator) } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
enableFeaturePreview("VERSION_CATALOGS") | ||
|
||
rootProject.name = "build-logic" | ||
|
||
include("android") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
plugins { | ||
`kotlin-dsl` | ||
`java-gradle-plugin` | ||
} | ||
|
||
dependencies { | ||
implementation(libs.androidPlugin) | ||
implementation(projects.adbServer.adbserverCommon) | ||
implementation(projects.adbServer.adbserverDesktop) | ||
} | ||
|
||
// TODO setup maven publication | ||
group = "com.kaspersky.kaspresso" | ||
gradlePlugin { | ||
plugins { | ||
create("SignerPlugin") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a SignerPlugin |
||
id = "com.kaspersky.kaspresso" | ||
implementationClass = "com.kaspersky.kaspresso.plugin.KaspressoPlugin" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.kaspersky.kaspresso.plugin | ||
|
||
import com.kaspersky.adbserver.common.log.LoggerFactory | ||
import com.kaspersky.adbserver.common.log.logger.LogLevel | ||
import com.kaspersky.adbserver.desktop.AdbCommandPerformer | ||
import com.kaspersky.adbserver.desktop.CmdCommandPerformer | ||
import com.kaspersky.adbserver.desktop.Desktop | ||
import org.gradle.api.logging.Logger | ||
import java.nio.file.Path | ||
|
||
internal class DesktopServerHolder(private val logger: Logger) { | ||
companion object { | ||
private const val DESKTOP_NAME = "kaspresso-plugin-adb-server" | ||
} | ||
|
||
private var desktop: Desktop? = null | ||
|
||
@Synchronized | ||
fun start(workingDirectory: Path, adbPath: Path) { | ||
check(desktop == null) { "Desktop already started" } | ||
|
||
logger.debug("Starting Desktop server. workingDir=$workingDirectory, adbPath=$adbPath") | ||
|
||
val cmdCommandPerformer = CmdCommandPerformer(DESKTOP_NAME, workingDirectory) | ||
val adbCommandPerformer = AdbCommandPerformer(adbPath, cmdCommandPerformer) | ||
val logger = LoggerFactory.getDesktopLogger(LogLevel.VERBOSE, DESKTOP_NAME, GradleFullLogger(logger)) | ||
desktop = Desktop( | ||
cmdCommandPerformer = cmdCommandPerformer, | ||
adbCommandPerformer = adbCommandPerformer, | ||
presetEmulators = emptyList(), | ||
adbServerPort = null, | ||
logger = logger | ||
) | ||
.apply { startDevicesObservingAsync() } | ||
} | ||
|
||
@Synchronized | ||
fun stop() { | ||
check(desktop != null) { "Desktop not started" } | ||
desktop!!.stopDevicesObserving() | ||
desktop = null | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I found
CmdCommandPerformer
exists already