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
95 changes: 90 additions & 5 deletions editor-server/device_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2370,6 +2370,8 @@ def report(percent: int, message: str) -> None:
organized_runtime_dir="$stack_root/runtime"
organized_hardware_dir="$stack_root/hardware"
bundle_dir="$stack_root/.hardware-install-bundle"
replacement_dir="$stack_root/.hardware-source-new"
backup_dir="$stack_root/.hardware-source-backup"
python_dir="$stack_root/python"
service_instance=""
[[ "$instance" == "default" ]] || service_instance="$instance"
Expand Down Expand Up @@ -2404,20 +2406,39 @@ def report(percent: int, message: str) -> None:
exit 3
}
created=false
replaced_snapshot=false
restart_units=()
cleanup_failed_install() {
exit_code=$?
if [[ "$exit_code" -ne 0 && "$created" == true ]]; then
progress 0 "Cleaning the incomplete Hardware package"
rm -rf -- "$hardware_dir"
if [[ "$exit_code" -ne 0 ]]; then
if [[ "$replaced_snapshot" == true && -d "$backup_dir" ]]; then
progress 0 "Restoring the previous Robot Hardware snapshot"
rm -rf -- "$hardware_dir"
mv -- "$backup_dir" "$hardware_dir"
elif [[ "$created" == true ]]; then
progress 0 "Cleaning the incomplete Hardware package"
rm -rf -- "$hardware_dir"
fi
for unit in "${restart_units[@]}"; do
sudo systemctl start "$unit" >/dev/null 2>&1 || true
done
fi
rm -rf -- "$bundle_dir"
rm -rf -- "$bundle_dir" "$replacement_dir"
exit "$exit_code"
}
trap cleanup_failed_install EXIT
case "$bundle_dir" in
"$HOME/Blacknode/devices/"*/.hardware-install-bundle) ;;
*) echo "Unsafe Hardware bundle directory."; exit 2 ;;
esac
case "$replacement_dir" in
"$HOME/Blacknode/devices/"*/.hardware-source-new) ;;
*) echo "Unsafe Hardware replacement directory."; exit 2 ;;
esac
case "$backup_dir" in
"$HOME/Blacknode/devices/"*/.hardware-source-backup) ;;
*) echo "Unsafe Hardware backup directory."; exit 2 ;;
esac
valid_hardware() {
[[ -f "$1/pyproject.toml" \
&& -f "$1/blacknode_robot/__init__.py" \
Expand Down Expand Up @@ -2486,7 +2507,55 @@ def report(percent: int, message: str) -> None:
exit 4
}
fi
progress 25 "Using the existing Robot Hardware package"
installed_hardware_commit="$(
python3 - "$stack_root/install.json" <<'PY'
import json
import sys
from pathlib import Path

try:
payload = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
print(str(payload.get("hardware_commit") or ""))
except (OSError, ValueError, AttributeError):
pass
PY
)"
if [[ -n "$bundle_path" \
&& ! -d "$hardware_dir/.git" \
&& "$installed_hardware_commit" != "$hardware_commit" ]]; then
progress 32 "Replacing the Robot Hardware snapshot"
mapfile -t restart_units < <(
{
systemctl list-unit-files 'blacknode-hardware*.service' --no-legend 2>/dev/null
systemctl list-units --all --type=service 'blacknode-hardware*.service' \
--no-legend 2>/dev/null
} | awk '{print $1}' | sort -u | while read -r unit; do
[[ "$unit" =~ ^blacknode-hardware([-.@][A-Za-z0-9_.@-]+)?\.service$ ]] \
|| continue
directory="$(
systemctl show "$unit" --property=WorkingDirectory --value 2>/dev/null || true
)"
[[ "$directory" == "$hardware_dir" ]] || continue
systemctl is-active --quiet "$unit" || continue
printf '%s\n' "$unit"
done
)
for unit in "${restart_units[@]}"; do
sudo systemctl stop "$unit"
done
rm -rf -- "$replacement_dir" "$backup_dir"
mkdir -p "$replacement_dir"
tar -xzf "$bundle_dir/hardware-source.tar.gz" -C "$replacement_dir" \
--strip-components=1 --no-same-owner --no-same-permissions
mv -- "$hardware_dir" "$backup_dir"
replaced_snapshot=true
if [[ -d "$backup_dir/.blacknode-hardware" ]]; then
mv -- "$backup_dir/.blacknode-hardware" "$replacement_dir/.blacknode-hardware"
fi
mv -- "$replacement_dir" "$hardware_dir"
else
progress 25 "Using the existing Robot Hardware package"
fi
elif [[ -n "$bundle_path" ]]; then
progress 32 "Installing the Robot Hardware package transferred by the editor"
created=true
Expand Down Expand Up @@ -2554,6 +2623,17 @@ def report(percent: int, message: str) -> None:
encoding="utf-8",
)
PY
if [[ "$replaced_snapshot" == true ]]; then
for unit in "${restart_units[@]}"; do
sudo systemctl start "$unit"
systemctl is-active --quiet "$unit" || {
echo "$unit did not restart after the Robot Hardware snapshot update."
exit 6
}
done
rm -rf -- "$backup_dir"
replaced_snapshot=false
fi
created=false
rm -rf -- "$bundle_dir"
printf '__BLACKNODE_HARDWARE_INSTALL__={"hardware_dir":"%s","layout":"%s","stack_mode":"isolated"}\n' \
Expand Down Expand Up @@ -2639,6 +2719,11 @@ def report(percent: int, message: str) -> None:
"hardware_dir": hardware_dir,
"stack_mode": stack_mode,
"layout": layout,
"hardware_commit": (
hardware_bundle.hardware_commit
if hardware_bundle is not None
else ""
),
}
finally:
try:
Expand Down
12 changes: 10 additions & 2 deletions tests/test_editor_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ def fake_run(_connection, command, **kwargs):
r"(?ms)^[^\n]*<<'PY'(?:\s*&)?\n(.*?)^PY$",
uploaded[0],
)
self.assertEqual(len(python_blocks), 2)
self.assertEqual(len(python_blocks), 3)
for index, python_block in enumerate(python_blocks, start=1):
compile(
python_block,
Expand Down Expand Up @@ -1286,6 +1286,14 @@ def fake_run(_connection, command, **_kwargs):
self.assertIn('python_dir="$stack_root/python"', script)
self.assertIn('"$python_dir/bin/python3" -m venv', script)
self.assertIn('--find-links "$bundle_dir/wheelhouse"', script)
self.assertIn('progress 32 "Replacing the Robot Hardware snapshot"', script)
self.assertIn('mv -- "$backup_dir/.blacknode-hardware"', script)
self.assertIn('[[ "$directory" == "$hardware_dir" ]] || continue', script)
self.assertIn(
'progress 0 "Restoring the previous Robot Hardware snapshot"',
script,
)
self.assertEqual(result["hardware_commit"], "a" * 40)
self.assertIn(
'progress 18 "Cleaning the recognized incomplete Robot Hardware download"',
script,
Expand All @@ -1295,7 +1303,7 @@ def fake_run(_connection, command, **_kwargs):
r"(?ms)^[^\n]*<<'PY'(?:\s*&)?\n(.*?)^PY$",
script,
)
self.assertEqual(len(python_blocks), 2)
self.assertEqual(len(python_blocks), 3)
for index, python_block in enumerate(python_blocks, start=1):
compile(python_block, f"<pc-hardware-install-{index}>", "exec")
checked = subprocess.run(
Expand Down