Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Malinskiy committed Dec 1, 2020
2 parents 5ec891b + 0b771dd commit e6477ac
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 1 deletion.
124 changes: 124 additions & 0 deletions src/main/kotlin/com/malinskiy/adam/request/sync/ListFilesRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2020 Anton Malinskiy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.malinskiy.adam.request.sync

import com.malinskiy.adam.Const


class ListFilesRequest(private val directory: String) : SyncShellCommandRequest<List<AndroidFile>>(
cmd = "ls -l $directory"
) {
private val builder = StringBuilder()
private val lslRegex: Regex = ("^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+" + //permissions
"(?:\\d+\\s+)?" + //nlink
"(\\S+)\\s+" + //user
"(\\S+)\\s+" + //group
"([\\d\\s,]*)\\s+" + //size
"(\\d{4}-\\d\\d-\\d\\d)\\s+" + //date
"(\\d\\d:\\d\\d)\\s+" + //time
"(.*)$").toRegex() //

override suspend fun process(bytes: ByteArray, offset: Int, limit: Int) {
val part = String(bytes, 0, limit, Const.DEFAULT_TRANSPORT_ENCODING)
builder.append(part)
}

override fun transform(): List<AndroidFile> {
return builder.lines()
.filter { it.isNotBlank() }
.mapNotNull { lslRegex.find(it) }
.map { match ->
val permissions = match.groupValues[1]
val owner = match.groupValues[2]
val group = match.groupValues[3]
val size = match.groupValues[4].toLongOrNull(10) ?: 0
val date = match.groupValues[5]
val time = match.groupValues[6]
var name = match.groupValues[7]

val type = when (permissions[0]) {
'-' -> AndroidFileType.REGULAR_FILE
'b' -> AndroidFileType.BLOCK_SPECIAL_FILE
'd' -> AndroidFileType.DIRECTORY
'l' -> AndroidFileType.SYMBOLIC_LINK
'c' -> AndroidFileType.CHARACTER_SPECIAL_FILE
's' -> AndroidFileType.SOCKET_LINK
'p' -> AndroidFileType.FIFO
else -> AndroidFileType.OTHER
}

var link: String? = null
if (type == AndroidFileType.SYMBOLIC_LINK) {
val split = name.split("->")
if (split.size != 2) {
throw RuntimeException("Unable to parse the symbolic file entry $name")
}
name = split[0].trim()
link = split[1].trim()
}

AndroidFile(
permissions = permissions,
owner = owner,
group = group,
size = size,
date = date,
time = time,
name = name,
directory = directory,
type = type,
link = link
)
}
}
}

enum class AndroidFileType {
REGULAR_FILE,
DIRECTORY,
BLOCK_SPECIAL_FILE,
CHARACTER_SPECIAL_FILE,
SYMBOLIC_LINK,
SOCKET_LINK,
FIFO,
OTHER,
}

/**
* @property permissions full permissions string, e.g. -rw-rw----
* @property owner file owner, e.g. root
* @property group file group, e.g. sdcard_rw
* @property date e.g. 2020-12-01
* @property time e.g. 22:22
* @property name the file name without path, e.g. testfile.txt
* @property directionality file's directory, e.g. /sdcard/
* @property size file's size, e.g. 1024
* @property type file's type
* @property link if the file is a symbolic link, this field is what the link points to
*/
data class AndroidFile(
val permissions: String,
val owner: String,
val group: String,
val date: String,
val time: String,
val name: String,
val directory: String,
val size: Long,
val type: AndroidFileType,
val link: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class TestRunnerRequest(
private val buffer = ByteArray(Const.MAX_PACKET_LENGTH)

override suspend fun readElement(readChannel: AndroidReadChannel, writeChannel: AndroidWriteChannel): String {
val available = readChannel.readAvailable(buffer, 0, Const.MAX_FILE_PACKET_LENGTH)
val available = readChannel.readAvailable(buffer, 0, Const.MAX_PACKET_LENGTH)

return when {
available > 0 -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (C) 2020 Anton Malinskiy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.malinskiy.adam.request.sync

import assertk.assertThat
import assertk.assertions.containsExactly
import assertk.assertions.isEqualTo
import com.malinskiy.adam.Const
import com.malinskiy.adam.server.AndroidDebugBridgeServer
import io.ktor.utils.io.*
import kotlinx.coroutines.runBlocking
import org.junit.Test

class ListFilesRequestTest {
@Test
fun testReturnsProperContent() {
runBlocking {
val server = AndroidDebugBridgeServer()

val client = server.startAndListen { input, output ->
val transportCmd = input.receiveCommand()
assertThat(transportCmd).isEqualTo("host:transport:serial")
output.respond(Const.Message.OKAY)

val shellCmd = input.receiveCommand()
assertThat(shellCmd).isEqualTo("shell:ls -l /sdcard/")
output.respond(Const.Message.OKAY)

val response = """
total 88
-rwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Alarms
brwxrwx--x 4 root sdcard_rw 4096 2020-10-24 16:29 Android
lrwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 DCIM -> ../Camera
crwxrwx--x 2 root sdcard_rw 4096 2020-12-01 19:11 Download
srwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Movies
prwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Music
drwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Ringtones
Orwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 XXX
""".trimIndent().toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)
output.writeFully(response, 0, response.size)
output.close()
}

val files = client.execute(ListFilesRequest("/sdcard/"), serial = "serial")
assertThat(files).containsExactly(
AndroidFile(
permissions = "-rwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = null,
name = "Alarms",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.REGULAR_FILE
),
AndroidFile(
permissions = "brwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = null,
name = "Android",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.BLOCK_SPECIAL_FILE
),
AndroidFile(
permissions = "lrwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = "../Camera",
name = "DCIM",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.SYMBOLIC_LINK
),
AndroidFile(
permissions = "crwxrwx--x",
directory = "/sdcard/",
date = "2020-12-01",
group = "sdcard_rw",
link = null,
name = "Download",
owner = "root",
size = 4096,
time = "19:11",
type = AndroidFileType.CHARACTER_SPECIAL_FILE
),
AndroidFile(
permissions = "srwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = null,
name = "Movies",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.SOCKET_LINK
),
AndroidFile(
permissions = "prwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = null,
name = "Music",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.FIFO
),
AndroidFile(
permissions = "drwxrwx--x",
directory = "/sdcard/",
date = "2020-10-24",
group = "sdcard_rw",
link = null,
name = "Ringtones",
owner = "root",
size = 4096,
time = "16:29",
type = AndroidFileType.DIRECTORY
)
)

server.dispose()
}
}
}

0 comments on commit e6477ac

Please sign in to comment.