Skip to content

Commit 5537bab

Browse files
Stefan Wiehlera3f
authored andcommitted
driver/usbstoragedriver: add write_files method
write_image, especially with the seek and skip parameters, can be useful for fast iterations during bootloader development: Only the bootloader is copied and the rest of the storage medium stays intact. Some boot firmware however loads subsequent boot stages from a, usually FAT32, filesystem, notably UEFI firmware from the EFI system partition. Make development on such targets easier by adding a write_files method that temporarily mounts the target device using udisks2 and writes the specified files there. Signed-off-by: Stefan Wiehler <stefan.wiehler@missinglinkelectronics.com> Co-authored-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Signed-off-by: Bastian Krause <bst@pengutronix.de>
1 parent 80e748c commit 5537bab

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

doc/configuration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ A :any:`NetworkUSBMassStorage` resource describes a USB memory stick or similar
630630
device available on a remote computer.
631631

632632
The NetworkUSBMassStorage can be used in test cases by calling the
633-
``write_image()``, and ``get_size()`` functions.
633+
``write_files()``, ``write_image()``, and ``get_size()`` functions.
634634

635635
SigrokDevice
636636
~~~~~~~~~~~~

labgrid/driver/usbstoragedriver.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import enum
22
import os
3+
import pathlib
34
import time
45
import subprocess
56

67
import attr
78

89
from ..factory import target_factory
10+
from ..resource.remote import RemoteUSBResource
911
from ..step import step
1012
from ..util.managedfile import ManagedFile
1113
from .common import Driver
1214
from ..driver.exception import ExecutionError
1315

1416
from ..util.helper import processwrapper
17+
from ..util.agentwrapper import AgentWrapper
1518
from ..util import Timeout
1619

1720

@@ -43,11 +46,66 @@ class USBStorageDriver(Driver):
4346
WAIT_FOR_MEDIUM_TIMEOUT = 10.0 # s
4447
WAIT_FOR_MEDIUM_SLEEP = 0.5 # s
4548

49+
def __attrs_post_init__(self):
50+
super().__attrs_post_init__()
51+
self.wrapper = None
52+
4653
def on_activate(self):
47-
pass
54+
host = self.storage.host if isinstance(self.storage, RemoteUSBResource) else None
55+
self.wrapper = AgentWrapper(host)
56+
self.proxy = self.wrapper.load('udisks2')
4857

4958
def on_deactivate(self):
50-
pass
59+
self.wrapper.close()
60+
self.wrapper = None
61+
self.proxy = None
62+
63+
@Driver.check_active
64+
@step(args=['sources', 'target', 'partition', 'target_is_directory'])
65+
def write_files(self, sources, target, partition, target_is_directory=True):
66+
"""
67+
Write the file(s) specified by filename(s) to the
68+
bound USB storage partition.
69+
70+
Args:
71+
sources (List[str]): path(s) to the file(s) to be copied to the bound USB storage
72+
partition.
73+
target (str): target directory or file to copy to
74+
partition (int): mount the specified partition or None to mount the whole disk
75+
target_is_directory (bool): Whether target is a directory
76+
"""
77+
78+
self.devpath = self._get_devpath(partition)
79+
mount_path = self.proxy.mount(self.devpath)
80+
81+
try:
82+
# (pathlib.PurePath(...) / "/") == "/", so we turn absolute paths into relative
83+
# paths with respect to the mount point here
84+
target_rel = target.relative_to(target.root) if target.root is not None else target
85+
target_path = str(pathlib.PurePath(mount_path) / target_rel)
86+
87+
copied_sources = []
88+
89+
for f in sources:
90+
mf = ManagedFile(f, self.storage)
91+
mf.sync_to_resource()
92+
copied_sources.append(mf.get_remote_path())
93+
94+
if target_is_directory:
95+
args = ["cp", "-t", target_path] + copied_sources
96+
else:
97+
if len(sources) != 1:
98+
raise ValueError("single source argument required when target_is_directory=False")
99+
100+
args = ["cp", "-T", copied_sources[0], target_path]
101+
102+
processwrapper.check_output(self.storage.command_prefix + args)
103+
self.proxy.unmount(self.devpath)
104+
except:
105+
# We are going to die with an exception anyway, so no point in waiting
106+
# to make sure everything has been written before continuing
107+
self.proxy.unmount(self.devpath, lazy=True)
108+
raise
51109

52110
@Driver.check_active
53111
@step(args=['filename'])

0 commit comments

Comments
 (0)