pymobiledevice3 5.0.4__py3-none-any.whl → 7.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- misc/understanding_idevice_protocol_layers.md +10 -5
- pymobiledevice3/__main__.py +171 -46
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +22 -21
- pymobiledevice3/cli/activation.py +24 -22
- pymobiledevice3/cli/afc.py +49 -41
- pymobiledevice3/cli/amfi.py +13 -18
- pymobiledevice3/cli/apps.py +71 -65
- pymobiledevice3/cli/backup.py +134 -93
- pymobiledevice3/cli/bonjour.py +31 -29
- pymobiledevice3/cli/cli_common.py +175 -232
- pymobiledevice3/cli/companion_proxy.py +12 -12
- pymobiledevice3/cli/crash.py +95 -52
- pymobiledevice3/cli/developer/__init__.py +62 -0
- pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
- pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
- pymobiledevice3/cli/developer/arbitration.py +50 -0
- pymobiledevice3/cli/developer/condition.py +33 -0
- pymobiledevice3/cli/developer/core_device.py +294 -0
- pymobiledevice3/cli/developer/debugserver.py +244 -0
- pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
- pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
- pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
- pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
- pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
- pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
- pymobiledevice3/cli/developer/simulate_location.py +51 -0
- pymobiledevice3/cli/diagnostics/__init__.py +75 -0
- pymobiledevice3/cli/diagnostics/battery.py +47 -0
- pymobiledevice3/cli/idam.py +42 -0
- pymobiledevice3/cli/lockdown.py +70 -75
- pymobiledevice3/cli/mounter.py +99 -57
- pymobiledevice3/cli/notification.py +38 -26
- pymobiledevice3/cli/pcap.py +36 -20
- pymobiledevice3/cli/power_assertion.py +15 -16
- pymobiledevice3/cli/processes.py +11 -17
- pymobiledevice3/cli/profile.py +120 -75
- pymobiledevice3/cli/provision.py +27 -26
- pymobiledevice3/cli/remote.py +109 -100
- pymobiledevice3/cli/restore.py +134 -129
- pymobiledevice3/cli/springboard.py +50 -50
- pymobiledevice3/cli/syslog.py +145 -65
- pymobiledevice3/cli/usbmux.py +66 -27
- pymobiledevice3/cli/version.py +2 -5
- pymobiledevice3/cli/webinspector.py +232 -156
- pymobiledevice3/exceptions.py +6 -2
- pymobiledevice3/lockdown.py +5 -1
- pymobiledevice3/lockdown_service_provider.py +5 -0
- pymobiledevice3/remote/remote_service_discovery.py +18 -10
- pymobiledevice3/restore/device.py +28 -4
- pymobiledevice3/restore/restore.py +2 -2
- pymobiledevice3/service_connection.py +15 -12
- pymobiledevice3/services/afc.py +731 -220
- pymobiledevice3/services/device_link.py +45 -31
- pymobiledevice3/services/idam.py +20 -0
- pymobiledevice3/services/lockdown_service.py +12 -9
- pymobiledevice3/services/mobile_config.py +1 -0
- pymobiledevice3/services/mobilebackup2.py +6 -3
- pymobiledevice3/services/os_trace.py +97 -55
- pymobiledevice3/services/remote_fetch_symbols.py +13 -8
- pymobiledevice3/services/screenshot.py +2 -2
- pymobiledevice3/services/web_protocol/alert.py +8 -8
- pymobiledevice3/services/web_protocol/automation_session.py +87 -79
- pymobiledevice3/services/web_protocol/cdp_screencast.py +2 -1
- pymobiledevice3/services/web_protocol/driver.py +71 -70
- pymobiledevice3/services/web_protocol/element.py +58 -56
- pymobiledevice3/services/web_protocol/selenium_api.py +47 -47
- pymobiledevice3/services/web_protocol/session_protocol.py +3 -2
- pymobiledevice3/services/web_protocol/switch_to.py +23 -19
- pymobiledevice3/services/webinspector.py +42 -67
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +5 -3
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/RECORD +76 -61
- pymobiledevice3/cli/completions.py +0 -50
- pymobiledevice3/cli/developer.py +0 -1539
- pymobiledevice3/cli/diagnostics.py +0 -110
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
pymobiledevice3/cli/syslog.py
CHANGED
|
@@ -2,38 +2,41 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import posixpath
|
|
4
4
|
import re
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from
|
|
5
|
+
from contextlib import nullcontext
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated, Optional, TextIO
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from typer_injector import InjectingTyper
|
|
11
|
+
|
|
12
|
+
from pymobiledevice3.cli.cli_common import (
|
|
13
|
+
ServiceProviderDep,
|
|
14
|
+
get_last_used_terminal_formatting,
|
|
15
|
+
user_requested_colored_output,
|
|
16
|
+
)
|
|
11
17
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
12
|
-
from pymobiledevice3.services.os_trace import OsTraceService, SyslogLogLevel
|
|
18
|
+
from pymobiledevice3.services.os_trace import OsTraceService, SyslogEntry, SyslogLogLevel
|
|
13
19
|
from pymobiledevice3.services.syslog import SyslogService
|
|
14
20
|
|
|
15
21
|
logger = logging.getLogger(__name__)
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@cli.group()
|
|
24
|
-
def syslog() -> None:
|
|
25
|
-
"""Watch syslog messages"""
|
|
26
|
-
pass
|
|
23
|
+
cli = InjectingTyper(
|
|
24
|
+
name="syslog",
|
|
25
|
+
help="Watch syslog messages",
|
|
26
|
+
no_args_is_help=True,
|
|
27
|
+
)
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
@
|
|
30
|
-
def syslog_live_old(service_provider:
|
|
30
|
+
@cli.command("live-old")
|
|
31
|
+
def syslog_live_old(service_provider: ServiceProviderDep) -> None:
|
|
31
32
|
"""view live syslog lines in raw bytes form from old relay"""
|
|
32
33
|
for line in SyslogService(service_provider=service_provider).watch():
|
|
33
34
|
print(line)
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def format_line(
|
|
37
|
+
def format_line(
|
|
38
|
+
color: bool, pid: int, syslog_entry: SyslogEntry, include_label: bool, image_offset: bool = False
|
|
39
|
+
) -> Optional[str]:
|
|
37
40
|
log_level_colors = {
|
|
38
41
|
SyslogLogLevel.NOTICE.name: "white",
|
|
39
42
|
SyslogLogLevel.INFO.name: "white",
|
|
@@ -50,6 +53,7 @@ def format_line(color, pid, syslog_entry, include_label):
|
|
|
50
53
|
image_name = posixpath.basename(syslog_entry.image_name)
|
|
51
54
|
message = syslog_entry.message
|
|
52
55
|
process_name = posixpath.basename(filename)
|
|
56
|
+
image_offset_str = f"+0x{syslog_entry.image_offset:x}" if image_offset and image_name else ""
|
|
53
57
|
label = ""
|
|
54
58
|
|
|
55
59
|
if (pid != -1) and (syslog_pid != pid):
|
|
@@ -59,17 +63,19 @@ def format_line(color, pid, syslog_entry, include_label):
|
|
|
59
63
|
label = f"[{syslog_entry.label.subsystem}][{syslog_entry.label.category}]"
|
|
60
64
|
|
|
61
65
|
if color:
|
|
62
|
-
timestamp =
|
|
63
|
-
process_name =
|
|
66
|
+
timestamp = typer.style(str(timestamp), "green")
|
|
67
|
+
process_name = typer.style(process_name, "magenta")
|
|
64
68
|
if len(image_name) > 0:
|
|
65
|
-
image_name =
|
|
66
|
-
|
|
69
|
+
image_name = typer.style(image_name, "magenta")
|
|
70
|
+
if image_offset:
|
|
71
|
+
image_offset_str = typer.style(image_offset_str, "blue")
|
|
72
|
+
syslog_pid = typer.style(syslog_pid, "cyan")
|
|
67
73
|
log_level_color = log_level_colors[level]
|
|
68
|
-
level =
|
|
69
|
-
label =
|
|
70
|
-
message =
|
|
74
|
+
level = typer.style(level, log_level_color)
|
|
75
|
+
label = typer.style(label, "cyan")
|
|
76
|
+
message = typer.style(message, log_level_color)
|
|
71
77
|
|
|
72
|
-
line_format = "{timestamp} {process_name}{{{image_name}}}[{pid}] <{level}>: {message}"
|
|
78
|
+
line_format = "{timestamp} {process_name}{{{image_name}{image_offset_str}}}[{pid}] <{level}>: {message}"
|
|
73
79
|
|
|
74
80
|
if include_label:
|
|
75
81
|
line_format += f" {label}"
|
|
@@ -81,6 +87,7 @@ def format_line(color, pid, syslog_entry, include_label):
|
|
|
81
87
|
pid=syslog_pid,
|
|
82
88
|
level=level,
|
|
83
89
|
message=message,
|
|
90
|
+
image_offset_str=image_offset_str,
|
|
84
91
|
)
|
|
85
92
|
|
|
86
93
|
return line
|
|
@@ -89,28 +96,32 @@ def format_line(color, pid, syslog_entry, include_label):
|
|
|
89
96
|
def syslog_live(
|
|
90
97
|
service_provider: LockdownServiceProvider,
|
|
91
98
|
out: Optional[TextIO],
|
|
92
|
-
pid:
|
|
99
|
+
pid: int,
|
|
93
100
|
process_name: Optional[str],
|
|
94
101
|
match: list[str],
|
|
95
102
|
match_insensitive: list[str],
|
|
96
103
|
include_label: bool,
|
|
97
104
|
regex: list[str],
|
|
98
105
|
insensitive_regex: list[str],
|
|
106
|
+
image_offset: bool = False,
|
|
99
107
|
) -> None:
|
|
100
108
|
match_regex = [re.compile(f".*({r}).*", re.DOTALL) for r in regex]
|
|
101
109
|
match_regex += [re.compile(f".*({r}).*", re.IGNORECASE | re.DOTALL) for r in insensitive_regex]
|
|
102
110
|
|
|
103
111
|
def replace(m):
|
|
104
|
-
if len(m.groups()):
|
|
105
|
-
return line.replace(m.group(1),
|
|
106
|
-
return
|
|
112
|
+
if len(m.groups()) and line:
|
|
113
|
+
return line.replace(m.group(1), typer.style(m.group(1), bold=True, underline=True))
|
|
114
|
+
return ""
|
|
107
115
|
|
|
108
116
|
for syslog_entry in OsTraceService(lockdown=service_provider).syslog(pid=pid):
|
|
109
117
|
if process_name and posixpath.basename(syslog_entry.filename) != process_name:
|
|
110
118
|
continue
|
|
111
119
|
|
|
112
|
-
line_no_style = format_line(False, pid, syslog_entry, include_label)
|
|
113
|
-
line = format_line(user_requested_colored_output(), pid, syslog_entry, include_label)
|
|
120
|
+
line_no_style = format_line(False, pid, syslog_entry, include_label, image_offset)
|
|
121
|
+
line = format_line(user_requested_colored_output(), pid, syslog_entry, include_label, image_offset)
|
|
122
|
+
|
|
123
|
+
if line_no_style is None or line is None:
|
|
124
|
+
continue
|
|
114
125
|
|
|
115
126
|
skip = False
|
|
116
127
|
|
|
@@ -122,7 +133,7 @@ def syslog_live(
|
|
|
122
133
|
break
|
|
123
134
|
else:
|
|
124
135
|
if user_requested_colored_output():
|
|
125
|
-
match_line = match_line.replace(m,
|
|
136
|
+
match_line = match_line.replace(m, typer.style(m, bold=True, underline=True))
|
|
126
137
|
line = match_line
|
|
127
138
|
|
|
128
139
|
if match_insensitive is not None:
|
|
@@ -138,7 +149,7 @@ def syslog_live(
|
|
|
138
149
|
last_color_formatting = get_last_used_terminal_formatting(line[:start])
|
|
139
150
|
line = (
|
|
140
151
|
line[:start]
|
|
141
|
-
+
|
|
152
|
+
+ typer.style(line[start:end], bold=True, underline=True)
|
|
142
153
|
+ last_color_formatting
|
|
143
154
|
+ line[end:]
|
|
144
155
|
)
|
|
@@ -163,39 +174,108 @@ def syslog_live(
|
|
|
163
174
|
print(line_no_style, file=out, flush=True)
|
|
164
175
|
|
|
165
176
|
|
|
166
|
-
@
|
|
167
|
-
@click.option("-o", "--out", type=click.File("wt"), help="log file")
|
|
168
|
-
@click.option("--pid", type=click.INT, default=-1, help="pid to filter. -1 for all")
|
|
169
|
-
@click.option("-pn", "--process-name", help="process name to filter")
|
|
170
|
-
@click.option("-m", "--match", multiple=True, help="match expression")
|
|
171
|
-
@click.option("-mi", "--match-insensitive", multiple=True, help="insensitive match expression")
|
|
172
|
-
@click.option("include_label", "--label", is_flag=True, help="should include label")
|
|
173
|
-
@click.option("-e", "--regex", multiple=True, help="filter only lines matching given regex")
|
|
174
|
-
@click.option("-ei", "--insensitive-regex", multiple=True, help="filter only lines matching given regex (insensitive)")
|
|
177
|
+
@cli.command("live")
|
|
175
178
|
def cli_syslog_live(
|
|
176
|
-
service_provider:
|
|
177
|
-
out:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
service_provider: ServiceProviderDep,
|
|
180
|
+
out: Annotated[
|
|
181
|
+
Optional[Path],
|
|
182
|
+
typer.Option(
|
|
183
|
+
"--out",
|
|
184
|
+
"-o",
|
|
185
|
+
help="log file",
|
|
186
|
+
),
|
|
187
|
+
] = None,
|
|
188
|
+
pid: Annotated[
|
|
189
|
+
int,
|
|
190
|
+
typer.Option(help="pid to filter. -1 for all"),
|
|
191
|
+
] = -1,
|
|
192
|
+
process_name: Annotated[
|
|
193
|
+
Optional[str],
|
|
194
|
+
typer.Option(
|
|
195
|
+
"--process-name",
|
|
196
|
+
"-pn",
|
|
197
|
+
help="process name to filter",
|
|
198
|
+
),
|
|
199
|
+
] = None,
|
|
200
|
+
match: Annotated[
|
|
201
|
+
Optional[list[str]],
|
|
202
|
+
typer.Option(
|
|
203
|
+
"--match",
|
|
204
|
+
"-m",
|
|
205
|
+
help="match expression",
|
|
206
|
+
),
|
|
207
|
+
] = None,
|
|
208
|
+
match_insensitive: Annotated[
|
|
209
|
+
Optional[list[str]],
|
|
210
|
+
typer.Option(
|
|
211
|
+
"--match-insensitive",
|
|
212
|
+
"-mi",
|
|
213
|
+
help="case-insensitive match expression",
|
|
214
|
+
),
|
|
215
|
+
] = None,
|
|
216
|
+
include_label: Annotated[
|
|
217
|
+
bool,
|
|
218
|
+
typer.Option(
|
|
219
|
+
"--label",
|
|
220
|
+
help="should include label",
|
|
221
|
+
),
|
|
222
|
+
] = False,
|
|
223
|
+
regex: Annotated[
|
|
224
|
+
Optional[list[str]],
|
|
225
|
+
typer.Option(
|
|
226
|
+
"--regex",
|
|
227
|
+
"-e",
|
|
228
|
+
help="filter only lines matching given regex",
|
|
229
|
+
),
|
|
230
|
+
] = None,
|
|
231
|
+
insensitive_regex: Annotated[
|
|
232
|
+
Optional[list[str]],
|
|
233
|
+
typer.Option(
|
|
234
|
+
"--insensitive-regex",
|
|
235
|
+
"-ei",
|
|
236
|
+
help="filter only lines matching given regex (insensitive)",
|
|
237
|
+
),
|
|
238
|
+
] = None,
|
|
239
|
+
image_offset: Annotated[
|
|
240
|
+
bool,
|
|
241
|
+
typer.Option(
|
|
242
|
+
"--image-offset",
|
|
243
|
+
"-io",
|
|
244
|
+
help="Include image offset in log line",
|
|
245
|
+
),
|
|
246
|
+
] = False,
|
|
185
247
|
) -> None:
|
|
186
248
|
"""view live syslog lines"""
|
|
187
249
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
with out.open("wt") if out else nullcontext() as out_file:
|
|
251
|
+
syslog_live(
|
|
252
|
+
service_provider,
|
|
253
|
+
out_file,
|
|
254
|
+
pid,
|
|
255
|
+
process_name,
|
|
256
|
+
match or [],
|
|
257
|
+
match_insensitive or [],
|
|
258
|
+
include_label,
|
|
259
|
+
regex or [],
|
|
260
|
+
insensitive_regex or [],
|
|
261
|
+
)
|
|
191
262
|
|
|
192
263
|
|
|
193
|
-
@
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
264
|
+
@cli.command("collect")
|
|
265
|
+
def syslog_collect(
|
|
266
|
+
service_provider: ServiceProviderDep,
|
|
267
|
+
out: Annotated[
|
|
268
|
+
Path,
|
|
269
|
+
typer.Argument(
|
|
270
|
+
exists=False,
|
|
271
|
+
dir_okay=True,
|
|
272
|
+
file_okay=False,
|
|
273
|
+
),
|
|
274
|
+
],
|
|
275
|
+
size_limit: int,
|
|
276
|
+
age_limit: int,
|
|
277
|
+
start_time: int,
|
|
278
|
+
) -> None:
|
|
199
279
|
"""
|
|
200
280
|
Collect the system logs into a .logarchive that can be viewed later with tools such as log or Console.
|
|
201
281
|
If the filename doesn't exist, system_logs.logarchive will be created in the given directory.
|
|
@@ -203,12 +283,12 @@ def syslog_collect(service_provider: LockdownClient, out, size_limit, age_limit,
|
|
|
203
283
|
if not os.path.exists(out):
|
|
204
284
|
os.makedirs(out)
|
|
205
285
|
|
|
206
|
-
if
|
|
286
|
+
if out.suffix != ".logarchive":
|
|
207
287
|
logger.warning(
|
|
208
288
|
"given out path doesn't end with a .logarchive - consider renaming to be able to view "
|
|
209
289
|
"the file with the likes of the Console.app and the `log show` utilities"
|
|
210
290
|
)
|
|
211
291
|
|
|
212
292
|
OsTraceService(lockdown=service_provider).collect(
|
|
213
|
-
out, size_limit=size_limit, age_limit=age_limit, start_time=start_time
|
|
293
|
+
str(out), size_limit=size_limit, age_limit=age_limit, start_time=start_time
|
|
214
294
|
)
|
pymobiledevice3/cli/usbmux.py
CHANGED
|
@@ -1,35 +1,53 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import tempfile
|
|
3
|
+
from typing import Annotated, Optional
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import typer
|
|
6
|
+
from typer_injector import InjectingTyper
|
|
5
7
|
|
|
6
8
|
from pymobiledevice3 import usbmux
|
|
7
|
-
from pymobiledevice3.cli.cli_common import USBMUX_OPTION_HELP,
|
|
9
|
+
from pymobiledevice3.cli.cli_common import USBMUX_OPTION_HELP, print_json
|
|
8
10
|
from pymobiledevice3.lockdown import create_using_usbmux
|
|
9
11
|
from pymobiledevice3.tcp_forwarder import UsbmuxTcpForwarder
|
|
10
12
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
cli = InjectingTyper(
|
|
17
|
+
name="usbmux",
|
|
18
|
+
help="Inspect usbmuxd-connected devices and forward TCP ports to them.",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@cli.command("forward")
|
|
24
|
+
def usbmux_forward(
|
|
25
|
+
src_port: Annotated[
|
|
26
|
+
int,
|
|
27
|
+
typer.Argument(min=1, max=0xFFFF),
|
|
28
|
+
],
|
|
29
|
+
dst_port: Annotated[
|
|
30
|
+
int,
|
|
31
|
+
typer.Argument(min=1, max=0xFFFF),
|
|
32
|
+
],
|
|
33
|
+
*,
|
|
34
|
+
usbmux_address: Annotated[
|
|
35
|
+
Optional[str],
|
|
36
|
+
typer.Option(
|
|
37
|
+
"--usbmux",
|
|
38
|
+
help=USBMUX_OPTION_HELP,
|
|
39
|
+
),
|
|
40
|
+
] = None,
|
|
41
|
+
serial: Annotated[
|
|
42
|
+
str,
|
|
43
|
+
typer.Option(help="Device serial/UDID to forward traffic to."),
|
|
44
|
+
],
|
|
45
|
+
daemonize: Annotated[
|
|
46
|
+
bool,
|
|
47
|
+
typer.Option("--daemonize", "-d", help="Run the forwarder in the background."),
|
|
48
|
+
] = False,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Forward a local TCP port to the device via usbmuxd."""
|
|
33
51
|
forwarder = UsbmuxTcpForwarder(serial, dst_port, src_port, usbmux_address=usbmux_address)
|
|
34
52
|
|
|
35
53
|
if daemonize:
|
|
@@ -45,12 +63,33 @@ def usbmux_forward(usbmux_address: str, src_port: int, dst_port: int, serial: st
|
|
|
45
63
|
forwarder.start()
|
|
46
64
|
|
|
47
65
|
|
|
48
|
-
@
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
@cli.command("list")
|
|
67
|
+
def usbmux_list(
|
|
68
|
+
usbmux_address: Annotated[
|
|
69
|
+
Optional[str],
|
|
70
|
+
typer.Option(
|
|
71
|
+
"--usbmux",
|
|
72
|
+
help=USBMUX_OPTION_HELP,
|
|
73
|
+
),
|
|
74
|
+
] = None,
|
|
75
|
+
usb: Annotated[
|
|
76
|
+
bool,
|
|
77
|
+
typer.Option(
|
|
78
|
+
"--usb",
|
|
79
|
+
"-u",
|
|
80
|
+
help="show only USB devices",
|
|
81
|
+
),
|
|
82
|
+
] = False,
|
|
83
|
+
network: Annotated[
|
|
84
|
+
bool,
|
|
85
|
+
typer.Option(
|
|
86
|
+
"--network",
|
|
87
|
+
"-n",
|
|
88
|
+
help="show only network devices",
|
|
89
|
+
),
|
|
90
|
+
] = False,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""List devices known to usbmuxd (USB and Wi-Fi)."""
|
|
54
93
|
connected_devices = []
|
|
55
94
|
for device in usbmux.list_devices(usbmux_address=usbmux_address):
|
|
56
95
|
udid = device.serial
|