Updater: resource compression (#3716)

* toolbox: compress: moved decompressor implementation to separate func
* toolbox: compress: callback-based api; cli: storage unpack command
* toolbox: compress: separate r/w contexts for stream api
* targets: f18: sync API
* compress: naming fixes & cleanup
* toolbox: compress: using hs buffer size for stream buffers
* toolbox: tar: heatshrink stream mode
* toolbox: compress: docs & small cleanup
* toolbox: tar: header support for .hs; updater: now uses .hs for resources; .hs.tar: now rewindable
* toolbox: compress: fixed hs stream tail handling
* updater: reworked progress for resources cleanup; rebalanced stage weights
* updater: single-pass decompression; scripts: print resources compression ratio
* updater: fixed warnings
* toolbox: tar: doxygen
* docs: update
* docs: info or tarhs format; scripts: added standalone compression/decompression tool for heatshrink-formatted streams
* scripts: tarhs: fixed parameter handling
* cli: storage extract command; toolbox: tar: guess type based on extension
* unit_tests: added test for streamed raw hs decompressor `compress_decode_streamed`
* unit_tests: compress: added extraction test for .tar.hs
* rpc: autodetect compressed archives
* scripts: minor cleanup of common parts
* scripts: update: now using in-memory intermediate tar stream
* scripts: added hs.py wrapper for heatshrink-related ops (single object and directory-as-tar compression)
* scripts: naming fixes
* Toolbox: export compress_config_heatshrink_default as const symbol
* Toolbox: fix various types naming
* Toolbox: more of types naming fixes
* Toolbox: use size_t in compress io callbacks and structures
* UnitTests: update to match new compress API
* Toolbox: proper path_extract_extension usage

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2024-06-30 13:38:48 +03:00
committed by GitHub
parent a881816673
commit fcbcb6b5a8
25 changed files with 1339 additions and 165 deletions

View File

@@ -5,6 +5,7 @@
#include <lib/toolbox/args.h>
#include <lib/toolbox/md5_calc.h>
#include <lib/toolbox/dir_walk.h>
#include <lib/toolbox/tar/tar_archive.h>
#include <storage/storage.h>
#include <storage/storage_sd_api.h>
#include <power/power_service/power.h>
@@ -33,6 +34,7 @@ static void storage_cli_print_usage(void) {
printf("\tmd5\t - md5 hash of the file\r\n");
printf("\tstat\t - info about file or dir\r\n");
printf("\ttimestamp\t - last modification timestamp\r\n");
printf("\textract\t - extract tar archive to destination\r\n");
};
static void storage_cli_print_error(FS_Error error) {
@@ -496,6 +498,47 @@ static void storage_cli_md5(Cli* cli, FuriString* path) {
furi_record_close(RECORD_STORAGE);
}
static bool tar_extract_file_callback(const char* name, bool is_directory, void* context) {
UNUSED(context);
printf("\t%s %s\r\n", is_directory ? "D" : "F", name);
return true;
}
static void storage_cli_extract(Cli* cli, FuriString* old_path, FuriString* args) {
UNUSED(cli);
FuriString* new_path = furi_string_alloc();
if(!args_read_probably_quoted_string_and_trim(args, new_path)) {
storage_cli_print_usage();
furi_string_free(new_path);
return;
}
Storage* api = furi_record_open(RECORD_STORAGE);
TarArchive* archive = tar_archive_alloc(api);
TarOpenMode tar_mode = tar_archive_get_mode_for_path(furi_string_get_cstr(old_path));
do {
if(!tar_archive_open(archive, furi_string_get_cstr(old_path), tar_mode)) {
printf("Failed to open archive\r\n");
break;
}
uint32_t start_tick = furi_get_tick();
tar_archive_set_file_callback(archive, tar_extract_file_callback, NULL);
printf("Unpacking to %s\r\n", furi_string_get_cstr(new_path));
bool success = tar_archive_unpack_to(archive, furi_string_get_cstr(new_path), NULL);
uint32_t end_tick = furi_get_tick();
printf(
"Decompression %s in %lu ticks \r\n",
success ? "success" : "failed",
end_tick - start_tick);
} while(false);
tar_archive_free(archive);
furi_string_free(new_path);
furi_record_close(RECORD_STORAGE);
}
void storage_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(context);
FuriString* cmd;
@@ -589,6 +632,11 @@ void storage_cli(Cli* cli, FuriString* args, void* context) {
break;
}
if(furi_string_cmp_str(cmd, "extract") == 0) {
storage_cli_extract(cli, path, args);
break;
}
storage_cli_print_usage();
} while(false);