Skip to content

Commit

Permalink
support shell with bytes output
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Dec 22, 2023
1 parent 8f038fe commit a28b068
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
10 changes: 8 additions & 2 deletions adbutils/_adb.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"""Created on Fri May 06 2022 10:58:29 by codeskyblue
"""

from __future__ import annotations

import os
import socket
import subprocess
Expand Down Expand Up @@ -119,14 +121,18 @@ def read_string_block(self) -> str:
size = int(length, 16)
return self.read_string(size)

def read_until_close(self, encoding: str = "utf-8") -> str:
def read_until_close(self, encoding: str | None = "utf-8") -> Union[str, bytes]:
"""
read until connection close
:param encoding: default utf-8, if pass None, return bytes
"""
content = b""
while True:
chunk = self.read(4096)
if not chunk:
break
content += chunk
return content.decode(encoding, errors='replace')
return content.decode(encoding, errors='replace') if encoding else content

def check_okay(self):
data = self.read_string(4)
Expand Down
25 changes: 19 additions & 6 deletions adbutils/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"""Created on Fri May 06 2022 10:33:39 by codeskyblue
"""

from __future__ import annotations

import abc
import dataclasses
import datetime
Expand Down Expand Up @@ -176,13 +178,16 @@ def shell(self,
cmdargs: Union[str, list, tuple],
stream: bool = False,
timeout: Optional[float] = _DEFAULT_SOCKET_TIMEOUT,
rstrip=True) -> typing.Union[AdbConnection, str]:
encoding: str | None = "utf-8",
rstrip=True) -> typing.Union[AdbConnection, str, bytes]:
"""Run shell inside device and get it's content
Args:
rstrip (bool): strip the last empty line (Default: True)
stream (bool): return stream instead of string output (Default: False)
timeout (float): set shell timeout
encoding (str): set output encoding (Default: utf-8), set None to make return bytes
rstrip (bool): strip the last empty line, only work when encoding is set
Returns:
string of output when stream is False
Expand All @@ -205,15 +210,23 @@ def shell(self,
c.check_okay()
if stream:
return c
output = c.read_until_close()
return output.rstrip() if rstrip else output
output = c.read_until_close(encoding=encoding)
if encoding:
return output.rstrip() if rstrip else output
return output

def shell2(self,
cmdargs: Union[str, list, tuple],
timeout: Optional[float] = _DEFAULT_SOCKET_TIMEOUT,
encoding: str | None = "utf-8",
rstrip=False) -> ShellReturn:
"""
Run shell command with detail output
Args:
cmdargs (str | list | tuple): command args
timeout (float): set shell timeout, seconds
encoding (str): set output encoding (Default: utf-8), set None to make return bytes
rstrip (bool): strip the last empty line, only work when encoding is set
Returns:
ShellOutput
Expand All @@ -226,13 +239,13 @@ def shell2(self,
assert isinstance(cmdargs, str)
MAGIC = "X4EXIT:"
newcmd = cmdargs + f"; echo {MAGIC}$?"
output = self.shell(newcmd, timeout=timeout, rstrip=True)
rindex = output.rfind(MAGIC)
output = self.shell(newcmd, timeout=timeout, encoding=encoding, rstrip=True)
rindex = output.rfind(MAGIC if encoding else MAGIC.encode())
if rindex == -1: # normally will not possible
raise AdbError("shell output invalid", output)
returncoode = int(output[rindex + len(MAGIC):])
output = output[:rindex]
if rstrip:
if rstrip and encoding:
output = output.rstrip()
return ShellReturn(command=cmdargs,
returncode=returncoode,
Expand Down
3 changes: 2 additions & 1 deletion adbutils/_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
"""Created on Fri May 06 2022 11:39:40 by codeskyblue
"""
from __future__ import annotations

__all__ = [
"Network", "DeviceEvent", "ForwardItem", "ReverseItem", "FileInfo",
Expand Down Expand Up @@ -89,7 +90,7 @@ class ShellReturn:
"""
command: str
returncode: int
output: str
output: str | bytes


@dataclass
Expand Down
9 changes: 9 additions & 0 deletions tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ def test_shell(device: AdbDevice):
output = device.shell("pwd", rstrip=False)
assert output in ["/\n", "/\r\n"]


def test_shell_without_encoding(device: AdbDevice):
output = device.shell("echo -n hello", encoding=None)
assert output == b"hello"

ret = device.shell2("echo -n hello", encoding=None)
assert ret.output == b"hello"


def test_shell_stream(device: AdbDevice):
c = device.shell(["echo", "-n", "hello world"], stream=True)
output = c.read_until_close()
Expand Down

0 comments on commit a28b068

Please sign in to comment.