Добавить протокол Altera Logic и общие клиенты прошивки
This commit is contained in:
178
tools/firmware-publish/DATABASE.md
Normal file
178
tools/firmware-publish/DATABASE.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# База прошивок как в SETGUI
|
||||
|
||||
Это общий сервис **базы файлов прошивок**: получить список опубликованных
|
||||
образов, выбрать изделие/версию/транспорт, скачать файл, проверить SHA-256 и
|
||||
передать его загрузчику. Также можно опубликовать новый образ в эту же базу.
|
||||
Модуль не зависит от версии самого приложения и от `c/firmware-info`.
|
||||
|
||||
## Состав
|
||||
|
||||
| Файл | Ответственность |
|
||||
|---|---|
|
||||
| [`firmware_database.py`](../../python/setprotocol/firmware_database.py) | Готовый HTTPS-клиент, чтение базы, кэш скачанных образов, публикация в Gitea |
|
||||
| [`firmware_catalog.py`](../../python/setprotocol/firmware_catalog.py) | Общий формат записей базы, используемый SETGUI |
|
||||
| [`firmware_publish.py`](../../python/setprotocol/firmware_publish.py) | Метаданные образа, SHA-256, объединение записей каталога |
|
||||
| [`firmware_db.py`](firmware_db.py) | Самостоятельный консольный запуск без SETGUI |
|
||||
|
||||
Требования: Python 3.10+ и стандартная библиотека. Qt, Windows Credential
|
||||
Manager, установленный SETGUI и библиотеки МК не требуются. Это сервис и CLI;
|
||||
готовое Qt-окно остаётся в SETGUI, а другой GUI подключает сервис по API ниже.
|
||||
|
||||
## Как устроена база
|
||||
|
||||
В текущей конфигурации SETGUI файлы находятся в Gitea Releases репозитория
|
||||
`setcorp/SETRD12-Releases` на `https://git.rd12.ru`. Список файлов лежит в
|
||||
`firmware.releases` файла `update.json` ветки `main`. Запись содержит изделие,
|
||||
версию, транспорт, адрес образа, имя файла, SHA-256, описание и необязательный
|
||||
адрес приложения во Flash. Это файловый каталог; SQL-сервер не нужен.
|
||||
|
||||
Новый сервис использует тот же JSON-контракт, поэтому выпуски видны клиентам
|
||||
SETGUI, поддерживающим указанный транспорт. В текущем SETGUI транспорт `tms`
|
||||
фильтруется; общий сервис его сохраняет. Публикация не добавляет новый
|
||||
загрузочный протокол в приложение или МК.
|
||||
|
||||
```text
|
||||
публикация .hex/.bin → Gitea release asset → скачать и проверить SHA-256
|
||||
↓
|
||||
обновить firmware.releases
|
||||
↓
|
||||
GUI: «Обновить каталог» → выбрать запись → «Скачать и выбрать» → загрузчик МК
|
||||
```
|
||||
|
||||
Для своего сервера задайте `server`, `owner`, `repository`, `branch` и
|
||||
`manifest_path`. Репозиторий, ветка и JSON-файл должны уже существовать.
|
||||
Для пустой базы достаточно файла `{"firmware":{"catalogVersion":0,"releases":[]}}`.
|
||||
Если `update.json` общий с обновлениями приложения, его другие разделы
|
||||
сохраняются при добавлении прошивки.
|
||||
|
||||
## Консоль: проверить, опубликовать, посмотреть, скачать
|
||||
|
||||
Из корня `templates` в PowerShell (параметры сервера стоят перед командой):
|
||||
|
||||
```powershell
|
||||
$db = @('--server', 'https://git.rd12.ru', '--owner', 'setcorp', '--repo', 'SETRD12-Releases')
|
||||
|
||||
# Без сети: проверить файл и сформировать запись каталога.
|
||||
python tools/firmware-publish/firmware_db.py @db preflight --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000
|
||||
|
||||
# Публикация образа в базу (изменяет сервер).
|
||||
python tools/firmware-publish/firmware_db.py @db publish --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000
|
||||
|
||||
# Получить список записей и скачать конкретную.
|
||||
python tools/firmware-publish/firmware_db.py @db list --product MY_DEVICE
|
||||
python tools/firmware-publish/firmware_db.py @db download --product MY_DEVICE --version-code 0x010203 --transport can --cache C:/firmware-cache
|
||||
```
|
||||
|
||||
`MY_DEVICE`, версия, транспорт и адрес — примеры, замените их данными изделия.
|
||||
SCI8 для TMS публикуйте как `.bin` с `--transport tms`, без `--base-address`.
|
||||
Инструмент не конвертирует `.axf/.out` и не проверяет пригодность образа для МК.
|
||||
|
||||
CLI читает логин и пароль/токен из переменных окружения `FIRMWARE_DB_LOGIN` и
|
||||
`FIRMWARE_DB_PASSWORD`. Задавайте их средствами своего секрет-хранилища/CI,
|
||||
а не в файлах проекта и не в аргументах командной строки. Для интерактивного
|
||||
ввода в PowerShell можно использовать:
|
||||
|
||||
```powershell
|
||||
$fwCredential = Get-Credential -Message 'Gitea: логин и пароль либо токен вместо пароля'
|
||||
$env:FIRMWARE_DB_LOGIN = $fwCredential.UserName
|
||||
$env:FIRMWARE_DB_PASSWORD = $fwCredential.GetNetworkCredential().Password
|
||||
# Выполнить нужные команды; после работы убрать переменные из текущего процесса.
|
||||
Remove-Item Env:FIRMWARE_DB_LOGIN, Env:FIRMWARE_DB_PASSWORD
|
||||
```
|
||||
|
||||
Публичный каталог можно читать без входа. Публикация через CLI требует обе
|
||||
переменные. Сервис не извлекает сохранённый пароль SETGUI автоматически.
|
||||
Команда `publish` явно разрешает запись и не запрашивает дополнительного
|
||||
подтверждения; `preflight` ничего не загружает. Старый BAT и конфигурации
|
||||
`firmware-release.cmd` продолжают использовать прежний путь через SETGUI.
|
||||
|
||||
## Портирование в другое Python-приложение
|
||||
|
||||
Подключите `templates/python` в import path приложения; переносите зависимость
|
||||
целиком, не одну копию файла. Сеть и кэш реализованы в сервисе, UI и хранение
|
||||
учётных данных задаёт приложение:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
from setprotocol.firmware_database import (
|
||||
Credentials, FirmwareDatabase, GiteaRepository, GiteaFirmwarePublisher,
|
||||
)
|
||||
from setprotocol.firmware_publish import FirmwarePublication
|
||||
|
||||
repo = GiteaRepository('https://git.rd12.ru', 'setcorp', 'SETRD12-Releases')
|
||||
# login и password получает ваше приложение из формы/хранилища.
|
||||
credentials = Credentials(login, password)
|
||||
database = FirmwareDatabase(repo.manifest_url, Path('firmware'), credentials=credentials)
|
||||
|
||||
# «Обновить каталог»: результат заполнит список в вашем UI.
|
||||
releases = database.read_catalog(product='MY_DEVICE', transport='can')
|
||||
# После выбора пользователем строки списка:
|
||||
selected = releases[selected_index]
|
||||
path = database.download(selected, progress=lambda percent: print(percent))
|
||||
# Передайте path, selected.transport и selected.base_address своему загрузчику.
|
||||
|
||||
# Публикация нового образа: отдельное действие оператора.
|
||||
publisher = GiteaFirmwarePublisher(repo, credentials)
|
||||
publication = FirmwarePublication(
|
||||
Path('build/device.hex'), 'MY_DEVICE', '1.2.3', 0x010203, 'can', 0x08003000,
|
||||
'Описание выпуска',
|
||||
)
|
||||
preview = publisher.preflight(publication) # можно показать перед выпуском
|
||||
entry = publisher.publish(publication)
|
||||
```
|
||||
|
||||
Для публичного каталога передайте `credentials=None`. Для чтения каталога,
|
||||
расположенного вне стандартного Gitea URL, передайте его HTTPS-адрес прямо в
|
||||
`FirmwareDatabase`; `GiteaRepository` нужен сетевому публикатору.
|
||||
|
||||
В Qt выполняйте `read_catalog`, `download`, `publish` в worker/QThread,
|
||||
передавайте прогресс сигналами в главный поток. По аналогии с SETGUI:
|
||||
|
||||
1. Кнопка «Обновить каталог» вызывает `read_catalog`, заполняет combo/table.
|
||||
2. В строке показываются `product`, `version`, `transport`; в деталях —
|
||||
`file_name`, `notes`, `base_address`.
|
||||
3. «Скачать и выбрать» вызывает `download`, возвращает проверенный путь.
|
||||
4. Сигнал в основное окно передаёт путь и выбранную `FirmwareRelease`;
|
||||
окно выставляет файл и транспорт на вкладке прошивки.
|
||||
|
||||
Скачивание не запускает прошивку устройства автоматически. Для C++/Android
|
||||
можно использовать CLI как отдельный процесс на ПК или реализовать клиент
|
||||
этого JSON-контракта на языке платформы; Python-модуль не является C-библиотекой.
|
||||
|
||||
## Поведение и ошибки
|
||||
|
||||
- Кэш: `<cache>/<sha256>/<fileName>`. Одинаковые имена разных образов не
|
||||
конфликтуют. Проверенный кэш используется повторно; незавершённые временные
|
||||
файлы удаляются. Результат появляется только после совпадения SHA-256.
|
||||
- Только HTTPS. Учётные данные отправляются лишь исходному origin (схема,
|
||||
хост, порт); на сторонний CDN и при смене origin в redirect не передаются.
|
||||
Redirect для запросов записи отклоняется.
|
||||
- Публикация использует asset с SHA-256 в имени: новые байты не заменяют файл,
|
||||
на который ещё ссылается старый каталог. `fileName` в каталоге остаётся
|
||||
исходным именем. В этом деталь реализации отличается от старого публикатора
|
||||
SETGUI, но формат каталога совместим.
|
||||
- Каталог меняется только после обратного скачивания образа. Запись проверяет
|
||||
ревизию файла (`sha`). При конфликте операция завершается ошибкой: повторите
|
||||
выпуск после проверки причины. Загруженный asset может остаться без записи
|
||||
каталога; повторный запуск использует его и снова проверит скачивание.
|
||||
- Повтор той же записи не увеличивает `catalogVersion`. Обновление одного
|
||||
`product + versionCode + transport` заменяет запись. Полный rollback и
|
||||
автоматическая очистка старых assets не выполняются.
|
||||
- Текущий upload держит образ в памяти (лимит 128 MiB), чтобы параллельная
|
||||
пересборка не подменила байты между вычислением хэша и отправкой.
|
||||
|
||||
## Проверка
|
||||
|
||||
Из `templates`:
|
||||
|
||||
```powershell
|
||||
$env:PYTHONPATH = "$PWD/python"
|
||||
python -m unittest discover -s python/tests -p test_firmware_database.py -v
|
||||
python -m unittest discover -s python/tests -p test_firmware_publish.py -v
|
||||
```
|
||||
|
||||
Тесты используют сервер в памяти: каталог → публикация → скачивание, повторный
|
||||
выпуск, сохранение других разделов, ошибки SHA-256 и конфликты ревизии,
|
||||
изоляцию авторизации при redirect. Проверка реальной Gitea и загрузка на МК
|
||||
в эти тесты не входят. Перед производственным подключением проверьте выпуск
|
||||
в тестовом репозитории вашей Gitea и чтение каталога целевым GUI.
|
||||
164
tools/firmware-publish/PORTING.md
Normal file
164
tools/firmware-publish/PORTING.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Подключение публикации прошивки к новому проекту
|
||||
|
||||
**Дополнение:** полная независимая библиотека базы прошивок теперь реализована
|
||||
в `python/setprotocol/firmware_database.py`, с CLI `firmware_db.py`.
|
||||
Чтение, скачивание, публикация и перенос GUI описаны в [`DATABASE.md`](DATABASE.md).
|
||||
Ниже сохранено описание интеграции через прежний BAT и SETGUI.
|
||||
|
||||
## Что уже реализовано
|
||||
|
||||
По локальным исходникам на 19 сентября 2026 года общий механизм уже есть.
|
||||
Создавать вторую библиотеку для той же схемы SETGUI не требуется:
|
||||
|
||||
| Компонент | Назначение | Зависимость |
|
||||
|---|---|---|
|
||||
| `c/firmware-info` | Версия реально запущенного образа, 12 слов / 24 байта | C-config проекта, без сети |
|
||||
| `python/setprotocol/firmware_publish.py` | Проверка параметров файла, SHA-256, release tag, запись и обновление каталога | Python stdlib, `firmware_catalog.py` |
|
||||
| `python/setprotocol/firmware_catalog.py` | Модель и чтение `firmware.releases` | Python stdlib |
|
||||
| `tools/firmware-publish/PUBLISH_FIRMWARE.bat` | Конфигурация IDE, транспорты, проверка Git, запуск выпуска | Windows, checkout SETGUI и его `.venv` |
|
||||
| `SETGUI/scripts/publish_firmware.py` | Загрузка в Gitea, скачивание и проверка SHA-256, запись и повторное чтение `update.json` | Общие Python-модули, API и учётные данные SETGUI |
|
||||
|
||||
Модуль `firmware_publish.py` сам не выполняет HTTP-запросы. Старый общий BAT
|
||||
использует сетевой публикатор SETGUI. Для автономного CI без SETGUI теперь
|
||||
используйте `GiteaFirmwarePublisher` из `firmware_database.py` или CLI
|
||||
`firmware_db.py`; одного `firmware_publish.py` для загрузки недостаточно.
|
||||
|
||||
```text
|
||||
проект МК → сборка .hex/.bin → общий BAT → SETGUI/scripts/publish_firmware.py
|
||||
↓
|
||||
setprotocol.firmware_publish
|
||||
↓
|
||||
Gitea release asset → SHA-256 → update.json
|
||||
|
||||
проект МК → firmware-info → обработчик версии → транспорт → клиент
|
||||
```
|
||||
|
||||
Эти две цепочки не синхронизируют версии автоматически. Bootloader и запись
|
||||
Flash — отдельные компоненты (`rs485-boot`, `protocan-boot`, `set-protocol`);
|
||||
публикация файла не добавляет поддержку обновления в устройство.
|
||||
|
||||
## Фактические подключения в этой рабочей папке
|
||||
|
||||
- `KONOR_ds18b20/src/main.c`: `app_send_firmware_info()` и команда `0x03`.
|
||||
`mdk/SETGUI_DS18B20.uvprojx` подключает оба C-файла через `..\lib\c`, config
|
||||
через `..\inc`, generated через `mdk/Generated`, генератор — Before Build.
|
||||
- В текущем checkout `KONOR_ds18b20/lib/c` является Windows junction на общий
|
||||
`newProject/templates/c`. Это локальная связь; её нельзя считать переносимым
|
||||
путём для другого компьютера. `.gitmodules` при этом декларирует `templates`
|
||||
в `lib`: перед переносом нужно сверить реальную раскладку, а не копировать
|
||||
пути из Keil вслепую. Корневой `firmware-release.cmd` у KONOR при проверке
|
||||
отсутствует.
|
||||
- SETGUI импортирует модули публикации из `SETGUI/third_party/templates/python`.
|
||||
Изменение соседнего `newProject/templates/python` само по себе эту копию не
|
||||
обновляет. Версию зависимости в SETGUI обновляют отдельно.
|
||||
- `SETGUI/src/gui_desktop/firmware_update.py` читает каталог через общий parser.
|
||||
Поиск по текущему `SETGUI/src` не обнаружил обработчика `FIRMWARE_INFO` /
|
||||
`firmware_info`: упаковка совместимого ответа ещё не означает, что эта версия
|
||||
клиента запрашивает и показывает расширенный контракт KONOR.
|
||||
- В исходниках сетевого публикатора задан Gitea `https://git.rd12.ru`, владелец
|
||||
`setcorp`, репозиторий `SETRD12-Releases`, ветка `main`, файл `update.json`.
|
||||
Это настройки кода, а не результат проверки доступности сервера.
|
||||
|
||||
## 1. Выбрать раскладку
|
||||
|
||||
Для нового проекта используйте явное расположение зависимости:
|
||||
|
||||
```text
|
||||
workspace/
|
||||
SETGUI/
|
||||
PUBLISH_FIRMWARE.bat
|
||||
.venv/Scripts/python.exe
|
||||
MyFirmware/
|
||||
firmware-release.cmd
|
||||
lib/templates/tools/firmware-publish/PUBLISH_FIRMWARE.bat
|
||||
mdk/build/application.hex
|
||||
```
|
||||
|
||||
Подключите `templates` принятой в проекте системой зависимостей. Скопируйте
|
||||
только конфигурацию из `examples/keil-firmware-release.cmd` или
|
||||
`examples/ccs12-firmware-release.cmd` в корень прошивки. Общий BAT оставьте
|
||||
в зависимости.
|
||||
|
||||
## 2. Заполнить firmware-release.cmd
|
||||
|
||||
Пример для приложения STM32 с bootloader; адрес `0x08003000` является примером
|
||||
и должен совпасть с linker script и настройками загрузчика вашего устройства:
|
||||
|
||||
```bat
|
||||
@echo off
|
||||
set "FW_PROJECT_ROOT=%~dp0"
|
||||
set "FW_SETGUI_ROOT=%~dp0..\SETGUI"
|
||||
set "FW_PRODUCT=MY_DEVICE"
|
||||
set "FW_VERSION=1.2.3"
|
||||
set "FW_VERSION_CODE=0x00010203"
|
||||
set "FW_TRANSPORTS=can rs485"
|
||||
set "FW_BASE_ADDRESS=0x08003000"
|
||||
set "FW_IMAGE=mdk\build\application.hex"
|
||||
set "FW_NOTES=Firmware 1.2.3"
|
||||
```
|
||||
|
||||
`FW_PRODUCT` должен соответствовать идентификатору изделия, с которым клиент
|
||||
выбирает прошивку. Сверьте `FW_VERSION` с C-config; при упаковке версии в три
|
||||
8-битных поля используйте части 0–255. Укажите только реально реализованные
|
||||
транспорты. Parser допускает `can`, `rs485`, `stm32`, `tms`; для их применения
|
||||
нужна соответствующая поддержка клиента и загрузчика.
|
||||
|
||||
Все транспорты одного запуска используют **один и тот же файл**. Если образы
|
||||
для CAN и RS-485 отличаются, заведите разные конфигурации с разными именами
|
||||
файлов и запускайте их отдельно. Одинаковое имя asset в одном release tag
|
||||
нельзя использовать для разных образов.
|
||||
|
||||
Для CCS 12 создайте SCI8 boot `.bin` через C2000 Hex Utility (`--binary --boot
|
||||
--sci8`), задайте `FW_TRANSPORTS=tms` и очистите адрес:
|
||||
`set "FW_BASE_ADDRESS="`. `.out` и `.axf` публикатор не преобразует.
|
||||
|
||||
## 3. Проверить и выпустить
|
||||
|
||||
Подготовьте окружение SETGUI по документации этого проекта. Учётные данные
|
||||
Gitea сохраняются через окно SETGUI «Версия и обновление»; в `.cmd` они не нужны.
|
||||
|
||||
Из корня MyFirmware в cmd.exe:
|
||||
|
||||
```bat
|
||||
call "lib\templates\tools\firmware-publish\PUBLISH_FIRMWARE.bat" --config "firmware-release.cmd" --preflight
|
||||
```
|
||||
|
||||
Для post-build в `mdk` используйте пути `..\lib\templates\...` и
|
||||
`--config "..\firmware-release.cmd"`. В post-build оставляйте `--preflight`.
|
||||
|
||||
Preflight проверяет существование, расширение, размер, метаданные, SHA-256 и
|
||||
схему записи каталога. Он **не разбирает содержимое Intel HEX/SCI8**, не сверяет
|
||||
версию с C-config, адреса с linker script и файл с текущими исходниками.
|
||||
Успех preflight не заменяет Rebuild и загрузку на тестовое устройство.
|
||||
|
||||
После проверки конкретного Release-образа и фиксации его исходников:
|
||||
|
||||
```bat
|
||||
call "lib\templates\tools\firmware-publish\PUBLISH_FIRMWARE.bat" --config "firmware-release.cmd" --publish
|
||||
```
|
||||
|
||||
Скрипт запросит подтверждение. Успех означает загрузку asset, проверку скачанных
|
||||
байтов, обновление каталога и его повторное чтение. Несколько транспортов
|
||||
публикуются последовательно, общей транзакции для всего запуска нет. Откройте
|
||||
базу прошивок SETGUI, обновите каталог и проверьте загрузку на тестовое устройство.
|
||||
|
||||
## 4. Другой сервер или собственный инструмент
|
||||
|
||||
`FW_SETGUI_ROOT` выбирает checkout SETGUI, а не адрес Gitea. Переменная
|
||||
`SETGUI_UPDATE_MANIFEST_URL` меняет URL чтения каталога, но не перенастраивает
|
||||
`WEB_ROOT`, `OWNER`, `RELEASE_REPO` сетевого публикатора. Для другого сервера
|
||||
нужно согласованно перенести сетевой адаптер, адреса чтения и авторизацию.
|
||||
|
||||
Для собственного Python-инструмента добавьте `templates/python` в import path
|
||||
и используйте `FirmwarePublication`, `sha256_file`, `firmware_release_tag`,
|
||||
`firmware_release_entry`, `update_firmware_manifest` из
|
||||
`setprotocol.firmware_publish`. Вызывайте `publication.validate()` до создания
|
||||
записи. Сетевой адаптер должен обеспечить тот же порядок, что SETGUI:
|
||||
|
||||
1. Загрузить образ в release и скачать его обратно, сверить SHA-256.
|
||||
2. Прочитать актуальный manifest, объединить через `update_firmware_manifest`.
|
||||
3. Записать manifest с проверкой исходной ревизии, чтобы не затереть чужое
|
||||
параллельное изменение; конфликт требует повторного чтения и объединения.
|
||||
4. Перечитать каталог через `parse_firmware_catalog` и проверить запись выпуска.
|
||||
|
||||
Не переносите пароли из профиля SETGUI в исходники или конфигурации проекта.
|
||||
@@ -1,10 +1,20 @@
|
||||
# Публикация прошивки из Keil и CCS 12
|
||||
|
||||
**Самостоятельная база прошивок без SETGUI:**
|
||||
[`DATABASE.md`](DATABASE.md) — библиотека и CLI для чтения каталога,
|
||||
скачивания и публикации образов. Ниже описан прежний BAT-путь через SETGUI.
|
||||
|
||||
Архитектура, фактические зависимости и пошаговое подключение нового проекта:
|
||||
[`PORTING.md`](PORTING.md). Общая Python-библиотека подготовки каталога уже
|
||||
находится в `python/setprotocol/firmware_publish.py`; сетевую загрузку выполняет
|
||||
SETGUI.
|
||||
|
||||
Этот комплект связывает проект прошивки с каталогом SETGUI. IDE по-прежнему
|
||||
собирает штатный загрузочный файл, а `PUBLISH_FIRMWARE.bat`:
|
||||
|
||||
1. читает метаданные выпуска из `firmware-release.cmd`;
|
||||
2. проверяет наличие и формат `.hex` или `.bin`;
|
||||
2. проверяет наличие, расширение и размер `.hex` или `.bin` (содержимое
|
||||
Intel HEX/SCI8 и совместимость с устройством не проверяются);
|
||||
3. запускает локальную проверку SETGUI (`--preflight`) либо публикацию
|
||||
(`--publish`);
|
||||
4. для каждого транспорта загружает образ в Gitea, скачивает его обратно,
|
||||
|
||||
82
tools/firmware-publish/firmware_db.py
Normal file
82
tools/firmware-publish/firmware_db.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Standalone firmware database CLI; requires Python 3.10+, no SETGUI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "python"))
|
||||
|
||||
from setprotocol.firmware_database import (
|
||||
Credentials, FirmwareDatabase, GiteaFirmwarePublisher, GiteaRepository,
|
||||
)
|
||||
from setprotocol.firmware_publish import FirmwarePublication, SUPPORTED_TRANSPORTS
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--server", required=True, help="Gitea HTTPS URL")
|
||||
parser.add_argument("--owner", required=True)
|
||||
parser.add_argument("--repo", required=True)
|
||||
parser.add_argument("--branch", default="main")
|
||||
parser.add_argument("--manifest", default="update.json")
|
||||
commands = parser.add_subparsers(dest="command", required=True)
|
||||
catalog = commands.add_parser("list")
|
||||
catalog.add_argument("--product")
|
||||
catalog.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS))
|
||||
download = commands.add_parser("download")
|
||||
download.add_argument("--product", required=True)
|
||||
download.add_argument("--version-code", type=lambda v: int(v, 0), required=True)
|
||||
download.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS), required=True)
|
||||
download.add_argument("--cache", type=Path, default=Path("firmware"))
|
||||
for name in ("preflight", "publish"):
|
||||
command = commands.add_parser(name)
|
||||
command.add_argument("--file", type=Path, required=True)
|
||||
command.add_argument("--product", required=True)
|
||||
command.add_argument("--version", required=True)
|
||||
command.add_argument("--version-code", type=lambda v: int(v, 0), required=True)
|
||||
command.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS), required=True)
|
||||
command.add_argument("--base-address", type=lambda v: int(v, 0))
|
||||
command.add_argument("--notes", default="")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
repository = GiteaRepository(args.server, args.owner, args.repo, args.branch, args.manifest)
|
||||
login = os.environ.get("FIRMWARE_DB_LOGIN")
|
||||
password = os.environ.get("FIRMWARE_DB_PASSWORD")
|
||||
credentials = Credentials(login, password) if login and password else None
|
||||
if args.command in ("list", "download"):
|
||||
database = FirmwareDatabase(repository.manifest_url,
|
||||
getattr(args, "cache", Path("firmware")),
|
||||
credentials=credentials)
|
||||
rows = database.read_catalog(product=args.product, transport=args.transport)
|
||||
if args.command == "list":
|
||||
print(json.dumps([asdict(row) for row in rows], ensure_ascii=False, indent=2))
|
||||
else:
|
||||
rows = [row for row in rows if row.version_code == args.version_code]
|
||||
if len(rows) != 1:
|
||||
raise ValueError("Expected exactly one matching firmware release")
|
||||
print(database.download(rows[0]))
|
||||
else:
|
||||
publication = FirmwarePublication(args.file.resolve(), args.product, args.version,
|
||||
args.version_code, args.transport,
|
||||
args.base_address, args.notes)
|
||||
publisher = GiteaFirmwarePublisher(repository, credentials)
|
||||
if args.command == "publish":
|
||||
if credentials is None:
|
||||
raise ValueError("Set FIRMWARE_DB_LOGIN and FIRMWARE_DB_PASSWORD for publication")
|
||||
result = publisher.publish(publication)
|
||||
else:
|
||||
result = publisher.preflight(publication)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
except (OSError, ValueError, RuntimeError) as error:
|
||||
print(f"Firmware database: {error}", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user