Skip to content
Merged
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
147 changes: 98 additions & 49 deletions src/infuse_iot/tools/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import base64
import glob
import pathlib
import sys
from typing import Any
from uuid import UUID
Expand Down Expand Up @@ -537,23 +538,42 @@ def _info_one(self, client: Client):
tablefmt="simple",
)
)

other_apps = get_applications_by_organisation_id.sync(client=client, id=UUID(self.args.org))
assert isinstance(other_apps, list)

diff_info = []
for diff in diffs:
source_app_id = self.args.app
from_release = get_release_by_organisation_id_and_application_id_and_release_id.sync(
client=client, id=UUID(self.args.org), application_id=self.args.app, release_id=diff.from_release_id
client=client, id=UUID(self.args.org), application_id=source_app_id, release_id=diff.from_release_id
)
if not isinstance(from_release, models.ApplicationRelease):
# Try the other applications in the organisation
for other_app in other_apps:
from_release = get_release_by_organisation_id_and_application_id_and_release_id.sync(
client=client,
id=UUID(self.args.org),
application_id=other_app.id,
release_id=diff.from_release_id,
)
if isinstance(from_release, models.ApplicationRelease):
source_app_id = other_app.id
break
if not isinstance(from_release, models.ApplicationRelease):
print(f"Failed to query information about source release {diff.from_release_id}")
continue
from_version = from_release.version
from_version_str = (
f"{from_version.major}.{from_version.minor}.{from_version.revision}+{from_version.build_num:08x}"
)
diff_info.append([from_version_str, diff.file.coap_path, diff.file.len_, diff.file.crc])
diff_info.append(
[f"0x{source_app_id:08x}", from_version_str, diff.file.coap_path, diff.file.len_, diff.file.crc]
)

if len(diff_info) > 0:
print("~~~ Diffs ~~~")
print(tabulate(diff_info, headers=["From Version", "Path", "Length", "CRC"]))
print(tabulate(diff_info, headers=["From App", "From Version", "Path", "Length", "CRC"]))

def _info_all(self, client: Client):
releases = get_releases_by_organisation_id_and_application_id.sync(
Expand Down Expand Up @@ -642,7 +662,7 @@ def upload(self, client: Client):
self._board_name = boards[idx].name
else:
board = get_board_by_id.sync(client=client, id=self._board)
if not isinstance(org, models.Board):
if not isinstance(board, models.Board):
sys.exit(f"Failed to query board for ID {self._board}")
self._board_name = board.name

Expand Down Expand Up @@ -677,24 +697,26 @@ def upload(self, client: Client):
if len(ota_files) != 1:
sys.exit(f"Unexpected OTA file search result {ota_files}")

releases = get_releases_by_organisation_id_and_application_id.sync(
client=client,
id=self._org,
application_id=app_id,
)
if not isinstance(releases, list):
sys.exit(f"Unexpected release query result {releases}")

cloud_release: None | models.ApplicationRelease = None
cloud_releases_by_version: dict[Version, models.ApplicationRelease] = {}
for r in releases:
v = Version(r.version.major, r.version.minor, r.version.revision, r.version.build_num)
cloud_releases_by_version[v] = r
if v == version:
print(f"Found release for application '0x{app_id:08x} {str(version)}' ({r.id})")
cloud_release = r

if cloud_release is None:
def get_all_releases(org: UUID, app_id: int) -> dict[Version, models.ApplicationRelease]:
releases = get_releases_by_organisation_id_and_application_id.sync(
client=client,
id=org,
application_id=app_id,
)
if not isinstance(releases, list):
sys.exit(f"Unexpected release query result {releases}")

by_version: dict[Version, models.ApplicationRelease] = {}
for r in releases:
v = Version(r.version.major, r.version.minor, r.version.revision, r.version.build_num)
by_version[v] = r
return by_version

cloud_releases_by_version = get_all_releases(self._org, app_id)
cloud_release = cloud_releases_by_version.get(version)
if cloud_release is not None:
print(f"Found release for application '0x{app_id:08x} {str(version)}' ({cloud_release.id})")
else:
dialog = (
f"Create release for application '0x{app_id:08x} {str(version)}'"
+ f" in organisation '{self._org_name}' for board '{self._board_name}'?"
Expand Down Expand Up @@ -730,37 +752,64 @@ def upload(self, client: Client):
print(f"Release created with ID '{rsp.id}'")
cloud_release = rsp

def upload_diffs_from_application(
org: UUID,
application: models.Application,
releases_from_version: dict[Version, models.ApplicationRelease],
diff_folder: pathlib.Path,
):
for path in diff_folder.iterdir():
if path.is_dir():
try:
other_app_id = int(path.stem, 16)
except ValueError:
print(f"{path.stem} does not appear to be an application ID")
continue
other_application = get_application_by_organisation_id_and_application_id.sync(
client=client, id=org, application_id=other_app_id
)
if not isinstance(other_application, models.Application):
print(f"Could not retrieve application with ID {path.stem}")
continue
other_application_releases = get_all_releases(org, other_application.id)
upload_diffs_from_application(org, other_application, other_application_releases, path)
continue
elif path.suffix != ".bin":
continue
try:
diff_from_version = Version.from_string(path.stem)
except ValueError:
print(f"Couldn't parse diff files version '{path.stem}'")
continue
from_version = releases_from_version.get(diff_from_version)
if from_version is None:
print(f"Version {diff_from_version} doesn't exist on cloud for application 0x{application.id:08x}")
continue

with open(path, "rb") as f:
diff_file = File(f, str(path), None)

create_body = models.CreateReleaseDiffBody(file=diff_file, from_release_id=from_version.id)
diff_rsp = create_release_diff.sync(
client=client,
id=org,
application_id=app_id,
release_id=cloud_release.id,
body=create_body,
)
prefix = f"{str(diff_from_version)} -> {str(version)}"
if isinstance(diff_rsp, models.Error):
print(f"{prefix}: <{diff_rsp.code}> {diff_rsp.message}")
elif isinstance(diff_rsp, models.ApplicationReleaseDiff):
print(f"{prefix}: Diff created with ID '{diff_rsp.id}'")
else:
print(f"{prefix}: No response")

# Upload any diffs
diff_folder = release.dir / "diffs"
if not diff_folder.exists():
return
for path in diff_folder.iterdir():
if not path.is_file() or path.suffix != ".bin":
continue
try:
diff_from_version = Version.from_string(path.stem)
except ValueError:
print(f"Couldn't parse diff files version '{path.stem}'")
continue
from_version = cloud_releases_by_version.get(diff_from_version)
if from_version is None:
print(f"Version {diff_from_version} doesn't exist on cloud")
continue

with open(path, "rb") as f:
diff_file = File(f, str(path), None)

create_body = models.CreateReleaseDiffBody(file=diff_file, from_release_id=from_version.id)
diff_rsp = create_release_diff.sync(
client=client, id=self._org, application_id=app_id, release_id=cloud_release.id, body=create_body
)
prefix = f"{str(diff_from_version)} -> {str(version)}"
if isinstance(diff_rsp, models.Error):
print(f"{prefix}: <{diff_rsp.code}> {diff_rsp.message}")
elif isinstance(diff_rsp, models.ApplicationReleaseDiff):
print(f"{prefix}: Diff created with ID '{diff_rsp.id}'")
else:
print(f"{prefix}: No response")
upload_diffs_from_application(self._org, application, cloud_releases_by_version, diff_folder)


class SubCommand(InfuseCommand):
Expand Down
Loading