Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/snagflash.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ flash <image_path> <image_offset> [<partition_name>]

Optional environment variables:
- fb-size
- paths-relative-to

If a file named "<image_path>.bmap" exists, snagflash will automatically
parse it and flash only the block ranges described.
Expand All @@ -127,8 +128,11 @@ fb-addr: address in memory of the Fastboot buffer
eraseblk-size: size in bytes of an erase block on the target Flash device

fb-size: size in bytes of the Fastboot buffer, this can only be used to reduce
the U-Boot Fastboot buffer size, not increase it.
the U-Boot Fastboot buffer size, not increase it.

paths-relative-to: controls how relative image paths in flash commands are resolved
CWD (default) paths are relative to the current working directory
THIS_FILE paths are relative to the directory containing the cmdfile
```

## UMS mode
Expand Down
2 changes: 1 addition & 1 deletion src/snagflash/fastboot.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def fastboot(args):
with open(args.interactive_cmdfile, "r") as file:
cmds = file.read(-1).splitlines()

session.run(cmds)
session.run(cmds, args.interactive_cmdfile)

if args.interactive:
if args.protocol == "fastboot":
Expand Down
31 changes: 29 additions & 2 deletions src/snagflash/fastboot_uboot.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class SnagflashFastbootUboot:

Optional environment variables:
- fb-size
- paths-relative-to

If a file named "<image_path>.bmap" exists, snagflash will automatically
parse it and flash only the block ranges described.
Expand All @@ -67,7 +68,11 @@ class SnagflashFastbootUboot:
eraseblk-size: size in bytes of an erase block on the target Flash device

fb-size: size in bytes of the Fastboot buffer, this can only be used to reduce
the U-Boot Fastboot buffer size, not increase it.
the U-Boot Fastboot buffer size, not increase it.

paths-relative-to: controls how relative image paths in flash commands are resolved
CWD (default) paths are relative to the current working directory
THIS_FILE paths are relative to the directory containing the cmdfile
"""

op_pattern = r"[\w\-]+"
Expand All @@ -77,6 +82,7 @@ def __init__(self, fast):
self.fast = fast
self.env = {}
self.checked = False
self.cmdfile = None

def err(self, msg: str):
print(f"CLI Error: {msg}")
Expand Down Expand Up @@ -206,6 +212,24 @@ def preflash_checks(self):

self.checked = True

def resolve_path(self, path: str) -> str:
if os.path.isabs(path):
return path
paths_relative_to = self.env.get("paths-relative-to", "CWD")
if paths_relative_to == "CWD":
pass # path is relative to CWD by default
elif paths_relative_to == "THIS_FILE":
if self.cmdfile is None:
raise SnagflashCmdError(
"paths-relative-to is THIS_FILE but no cmdfile is set"
)
path = os.path.join(os.path.dirname(self.cmdfile), path)
else:
raise SnagflashCmdError(
f"unsupported paths-relative-to value: '{paths_relative_to}'"
)
return path

def cmd_flash(self, args: str):
self.preflash_checks()

Expand All @@ -215,6 +239,8 @@ def cmd_flash(self, args: str):
path = path.strip('"').strip('"')
rest = rest.strip(" ")

path = self.resolve_path(path)

if " " in rest:
offset, sep, part = rest.partition(" ")
part = part.strip(" ")
Expand Down Expand Up @@ -420,7 +446,8 @@ def flash_mmc(
MMC_LBA_SIZE,
)

def run(self, cmds: list):
def run(self, cmds: list, cmdfile: str = None):
self.cmdfile = os.path.abspath(cmdfile) if cmdfile is not None else None
for cmd in cmds:
cmd = cmd.strip()

Expand Down
46 changes: 45 additions & 1 deletion tests/fastboot_uboot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import os
import unittest
import unittest.mock
import tempfile
import random

from snagflash.fastboot_uboot import SnagflashFastbootUboot, MMC_LBA_SIZE
from snagflash.fastboot_uboot import (
SnagflashFastbootUboot,
SnagflashCmdError,
MMC_LBA_SIZE,
)

MAX_IMAGE_LEN = 100000000
MAX_FLASH_OFFSET = 4096
Expand Down Expand Up @@ -79,3 +84,42 @@ def test_flash_range(self):
)

offset += rd_size


class TestResolvePath(unittest.TestCase):
def setUp(self):
self.fb = SnagflashFastbootUboot(unittest.mock.MagicMock())

def test_default_is_cwd(self):
# paths-relative-to unset -> path returned unchanged (relative to CWD)
self.assertEqual(self.fb.resolve_path("img/boot.bin"), "img/boot.bin")

def test_explicit_cwd(self):
self.fb.env["paths-relative-to"] = "CWD"
self.assertEqual(self.fb.resolve_path("img/boot.bin"), "img/boot.bin")

def test_absolute_path_is_untouched(self):
self.fb.env["paths-relative-to"] = "THIS_FILE"
self.fb.cmdfile = "/some/dir/flash.cmds"
self.assertEqual(self.fb.resolve_path("/abs/boot.bin"), "/abs/boot.bin")

def test_this_file_joins_cmdfile_dir(self):
self.fb.env["paths-relative-to"] = "THIS_FILE"
self.fb.cmdfile = "/some/dir/flash.cmds"
self.assertEqual(
self.fb.resolve_path("img/boot.bin"),
os.path.join("/some/dir", "img/boot.bin"),
)

def test_this_file_without_cmdfile_raises(self):
self.fb.env["paths-relative-to"] = "THIS_FILE"
self.fb.cmdfile = None
with self.assertRaises(SnagflashCmdError):
self.fb.resolve_path("img/boot.bin")

def test_unsupported_value_raises(self):
self.fb.env["paths-relative-to"] = (
"this_file" # case-sensitive: lowercase invalid
)
with self.assertRaises(SnagflashCmdError):
self.fb.resolve_path("img/boot.bin")
Loading