Implemented multi-binary app packaging (#648)
This commit is contained in:
committed by
GitHub
parent
2496dea5c2
commit
8556103eb1
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
// Resolves an AppManifestBinding::binary filename (without extension) to its installed path
|
||||
// under this fixed, predictable location, mirroring what each platform's own loader
|
||||
// (app_posix_loader_service.cpp / app_esp32_loader_service.cpp) already resolves a plain
|
||||
// ".so"/".elf" AppLocation::location straight through unchanged - so setting location.location
|
||||
// to this exact path means neither loader needs to guess which of a package's several binaries
|
||||
// an AppManifest refers to.
|
||||
inline std::string app_resolve_binary_path(const std::string& install_dir, const std::string& binary) {
|
||||
#ifdef ESP_PLATFORM
|
||||
return install_dir + "/bin/" CONFIG_IDF_TARGET "/" + binary + ".elf";
|
||||
#else
|
||||
return install_dir + "/bin/posix-" TACTILITY_POSIX_ARCH "/" + binary + ".so";
|
||||
#endif
|
||||
}
|
||||
@@ -3,8 +3,11 @@
|
||||
|
||||
#include <app/instance.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/package_manifest.h>
|
||||
#include <app/private/fd_table.h>
|
||||
|
||||
#include <TactilityCpp/Allocator.h>
|
||||
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/freertos/semphr.h>
|
||||
@@ -13,6 +16,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* A dedicated completion signal(1) for one app instance's task, given as the
|
||||
@@ -57,8 +61,16 @@ struct AppInstanceRecord {
|
||||
AppFdTable fd_table {};
|
||||
};
|
||||
|
||||
/** A registered installed package - see app_manager_add_package() (app/manager.h). */
|
||||
struct AppPackageRecord {
|
||||
struct PackageManifest package;
|
||||
std::vector<std::string> app_ids;
|
||||
};
|
||||
|
||||
struct AppLedger {
|
||||
std::unordered_map<std::string, const AppManifest*> manifests;
|
||||
// OptExternalAllocator: bigger entries than `manifests`, and unlike `instances` isn't on the app start/stop hot path.
|
||||
std::unordered_map<std::string, AppPackageRecord, std::hash<std::string>, std::equal_to<std::string>, tt::OptExternalAllocator<std::pair<const std::string, AppPackageRecord>>> packages;
|
||||
std::unordered_map<uint32_t, AppInstanceRecord> instances;
|
||||
uint32_t next_instance_id = 1;
|
||||
Mutex mutex {};
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <app/metadata.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
/** Shared helpers + per-format parsers for app_metadata_parse() (source/app_metadata_parsing.cpp)
|
||||
* - split out like the old tt::app manifest parser (AppManifestParsing/V1/V2.cpp) that this is
|
||||
* modelled on, one file per format plus a shared dispatcher. */
|
||||
|
||||
bool app_metadata_get_value(const std::map<std::string, std::string>& properties, const std::string& key, std::string& out_value);
|
||||
|
||||
bool app_metadata_is_valid_format_version(const std::string& version);
|
||||
bool app_metadata_is_valid_name(const std::string& name);
|
||||
bool app_metadata_is_valid_version_name(const std::string& version);
|
||||
bool app_metadata_is_valid_version_code(const std::string& version);
|
||||
bool app_metadata_is_valid_stack_size(const std::string& value);
|
||||
|
||||
/** Validates a comma-separated list of device ids (alphanumeric + '-' items, matching Devices/<id> folder names). */
|
||||
bool app_metadata_is_valid_device_id_list(const std::string& value);
|
||||
|
||||
/** Copies @a value into @a dest (a fixed-size buffer of @a dest_size bytes, including the NULL
|
||||
* terminator) if it fits.
|
||||
* @retval false @a value doesn't fit in @a dest_size bytes - @a dest is left untouched */
|
||||
bool app_metadata_copy_bounded(char* dest, size_t dest_size, const std::string& value);
|
||||
|
||||
/** Parses a V1 (sectioned INI, e.g. "[app]versionName=...") manifest map into @a out_metadata. */
|
||||
bool app_metadata_parse_v1(const std::map<std::string, std::string>& properties, struct AppMetadata& out_metadata);
|
||||
|
||||
/** Parses a V2 (flat dot-notation, e.g. "app.version.name=...") manifest map into @a out_metadata. */
|
||||
bool app_metadata_parse_v2(const std::map<std::string, std::string>& properties, struct AppMetadata& out_metadata);
|
||||
|
||||
bool app_metadata_validate_string(const std::string& value, bool (*is_valid_char)(char));
|
||||
@@ -0,0 +1,56 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <app/package_manifest.h>
|
||||
|
||||
#include <TactilityCpp/Allocator.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** Shared helpers + parser for app_package_manifest_parse() (source/package_manifest_parsing.cpp). */
|
||||
|
||||
bool app_package_manifest_get_value(const std::map<std::string, std::string>& properties, const std::string& key, std::string& out_value);
|
||||
|
||||
bool app_package_manifest_is_valid_format_version(const std::string& version);
|
||||
bool app_package_manifest_is_valid_version_name(const std::string& version);
|
||||
bool app_package_manifest_is_valid_version_code(const std::string& version);
|
||||
bool app_package_manifest_is_valid_bool(const std::string& value);
|
||||
|
||||
/** Validates a comma-separated list of device ids (alphanumeric + '-' items, matching Devices/<id> folder names). */
|
||||
bool app_package_manifest_is_valid_device_id_list(const std::string& value);
|
||||
|
||||
/** Validates a binary filename stem (AppManifestBinding::binary): alphanumeric plus '.', '_', '-'. */
|
||||
bool app_package_manifest_is_valid_binary_name(const std::string& value);
|
||||
|
||||
/** Copies @a value into @a dest (a fixed-size buffer of @a dest_size bytes, including the NULL
|
||||
* terminator) if it fits.
|
||||
* @retval false @a value doesn't fit in @a dest_size bytes - @a dest is left untouched */
|
||||
bool app_package_manifest_copy_bounded(char* dest, size_t dest_size, const std::string& value);
|
||||
|
||||
/** Parses a V2 (flat dot-notation, e.g. "app.version.name=...") manifest map into @a out_package
|
||||
* and (unless @a bindings_capacity is 0) its single AppManifestBinding, out_bindings[0].
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval ERROR_INVALID_ARGUMENT a required key is missing or a value doesn't fit/validate
|
||||
* @retval ERROR_BUFFER_OVERFLOW @a bindings_capacity is nonzero but smaller than needed */
|
||||
error_t package_manifest_parse_v2(const std::map<std::string, std::string>& properties, struct PackageManifest& out_package, struct AppManifestBinding* out_bindings, size_t bindings_capacity);
|
||||
|
||||
/** Parses a V3 (flat dot-notation with 0-indexed "app.N.*" blocks) manifest map into
|
||||
* @a out_package and up to @a bindings_capacity AppManifestBinding entries.
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval ERROR_INVALID_ARGUMENT a required key is missing or a value doesn't fit/validate
|
||||
* @retval ERROR_BUFFER_OVERFLOW @a bindings_capacity is nonzero but smaller than the
|
||||
* manifest's app_manifest_count */
|
||||
error_t package_manifest_parse_v3(const std::map<std::string, std::string>& properties, struct PackageManifest& out_package, struct AppManifestBinding* out_bindings, size_t bindings_capacity);
|
||||
|
||||
bool app_package_manifest_validate_string(const std::string& value, bool (*is_valid_char)(char));
|
||||
|
||||
/** Convenience wrapper around app_package_manifest_parse(): parses @a path once to learn
|
||||
* PackageManifest::app_manifest_count, then resizes @a out_bindings to fit exactly and parses
|
||||
* again to fill it - so the caller never needs to pre-allocate a fixed maximum.
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval ERROR_NOT_FOUND the file doesn't exist / couldn't be opened
|
||||
* @retval ERROR_INVALID_ARGUMENT the file isn't a valid manifest, or a field's value doesn't fit
|
||||
* its fixed-size buffer */
|
||||
error_t app_package_manifest_parse_into(const char* path, struct PackageManifest& out_package, std::vector<struct AppManifestBinding, tt::OptExternalAllocator<struct AppManifestBinding>>& out_bindings);
|
||||
Reference in New Issue
Block a user