Просмотр исходного кода

[FL-2481] Renamed assets->resources; enforcing Manifest build if it does not exist (#1135)

* Renamed assets->resources; enforcing Manifest build if it does not exist
* Rebuild resources from CI
* Added Manifest to repo - be sure to rebuild it with `make -C assets` before committing changes!
* Actually added Manifest.
* Keeping Manifest on assets clean
* Spelling fix in Makefile
hedger 3 лет назад
Родитель
Сommit
57312961e8

+ 1 - 1
.github/workflows/build.yml

@@ -76,7 +76,7 @@ jobs:
         with:
           run: |
             set -e
-            make assets_manifest
+            make assets_rebuild assets_manifest
             git diff --quiet || ( echo "Assets recompilation required."; exit 255 )
 
       - name: 'Build the firmware in docker'

+ 9 - 8
Makefile

@@ -79,7 +79,6 @@ ifeq ($(FORCE), 1)
 endif
 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
 
-
 .PHONY: updater
 updater:
 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all
@@ -97,14 +96,16 @@ updater_package_bin: firmware_all updater
 	@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)"
 
 .PHONY: updater_package
-updater_package: firmware_all updater
-	@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) -a assets/resources --bundlever "$(VERSION_STRING)"
+updater_package: firmware_all updater assets_manifest
+	@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) -r $(PROJECT_ROOT)/assets/resources --bundlever "$(VERSION_STRING)"
 
 .PHONY: assets_manifest
 assets_manifest:
-	@$(MAKE) -C $(PROJECT_ROOT)/assets clean
-	@$(MAKE) -C $(PROJECT_ROOT)/assets
-	@$(PROJECT_ROOT)/scripts/assets.py manifest assets/resources
+	@$(MAKE) -C $(PROJECT_ROOT)/assets manifest
+
+.PHONY: assets_rebuild
+assets_rebuild:
+	@$(MAKE) -C $(PROJECT_ROOT)/assets clean all
 
 .PHONY: flash_radio
 flash_radio:
@@ -124,8 +125,8 @@ flash_radio_fus:
 
 .PHONY: flash_radio_fus_please_i_m_not_going_to_complain
 flash_radio_fus_please_i_m_not_going_to_complain:
-	@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin
-	@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin
+	@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin
+	@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin
 	@$(PROJECT_ROOT)/scripts/ob.py set
 
 .PHONY: lint

+ 1 - 1
applications/updater/util/update_task.c

@@ -19,7 +19,7 @@ static const char* update_task_stage_descr[] = {
     [UpdateTaskStageRadioCommit] = "Applying radio stack",
     [UpdateTaskStageLfsBackup] = "Backing up LFS",
     [UpdateTaskStageLfsRestore] = "Restoring LFS",
-    [UpdateTaskStageAssetsUpdate] = "Updating assets",
+    [UpdateTaskStageResourcesUpdate] = "Updating resources",
     [UpdateTaskStageCompleted] = "Completed!",
     [UpdateTaskStageError] = "Error",
 };

+ 1 - 1
applications/updater/util/update_task.h

@@ -23,7 +23,7 @@ typedef enum {
     UpdateTaskStageRadioCommit,
     UpdateTaskStageLfsBackup,
     UpdateTaskStageLfsRestore,
-    UpdateTaskStageAssetsUpdate,
+    UpdateTaskStageResourcesUpdate,
     UpdateTaskStageCompleted,
     UpdateTaskStageError,
 } UpdateTaskStage;

+ 1 - 2
applications/updater/util/update_task_workers.c

@@ -166,14 +166,13 @@ static bool update_task_post_update(UpdateTask* update_task) {
                 .total_files = 0,
                 .processed_files = 0,
             };
-            update_task_set_progress(update_task, UpdateTaskStageAssetsUpdate, 0);
+            update_task_set_progress(update_task, UpdateTaskStageResourcesUpdate, 0);
 
             path_concat(
                 string_get_cstr(update_task->update_path),
                 string_get_cstr(update_task->manifest->resource_bundle),
                 file_path);
 
-            update_task_set_progress(update_task, UpdateTaskStageProgress, 0);
             TarArchive* archive = tar_archive_alloc(update_task->storage);
             tar_archive_set_file_callback(archive, update_task_resource_unpack_cb, &progress);
             success = tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ);

+ 1 - 1
assets/.gitignore

@@ -1 +1 @@
-/headers
+/headers

+ 10 - 6
assets/Makefile

@@ -3,11 +3,11 @@ PROJECT_ROOT		= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..)
 include				$(PROJECT_ROOT)/assets/assets.mk
 
 .PHONY: all
-all: icons protobuf dolphin
+all: icons protobuf dolphin manifest
 
-$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER)
+$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILER)
 	@echo "\tASSETS\t\t" $@
-	@$(ASSETS_COMPILLER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)"
+	@$(ASSETS_COMPILER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)"
 
 .PHONY: icons
 icons: $(ASSETS)
@@ -22,11 +22,15 @@ protobuf: $(PROTOBUF)
 
 $(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR)
 	@echo "\tDOLPHIN blocking"
-	@$(ASSETS_COMPILLER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
+	@$(ASSETS_COMPILER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
 	@echo "\tDOLPHIN internal"
-	@$(ASSETS_COMPILLER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
+	@$(ASSETS_COMPILER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
 	@echo "\tDOLPHIN external"
-	@$(ASSETS_COMPILLER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)"
+	@$(ASSETS_COMPILER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)"
+
+.PHONY: manifest
+manifest:
+	$(ASSETS_COMPILER) manifest $(RESOURCES_DIR)
 
 .PHONY: dolphin
 dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR)

+ 5 - 1
assets/assets.mk

@@ -1,11 +1,15 @@
 ASSETS_DIR			:= $(PROJECT_ROOT)/assets
-ASSETS_COMPILLER	:= $(PROJECT_ROOT)/scripts/assets.py
+ASSETS_COMPILER		:= $(PROJECT_ROOT)/scripts/assets.py
 ASSETS_COMPILED_DIR	:= $(ASSETS_DIR)/compiled
 ASSETS_SOURCE_DIR	:= $(ASSETS_DIR)/icons
 
 ASSETS_SOURCES		+= $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate')
 ASSETS				+= $(ASSETS_COMPILED_DIR)/assets_icons.c
 
+RESOURCES_DIR		:= $(ASSETS_DIR)/resources
+RESOURCES_MANIFEST	:= $(RESOURCES_DIR)/Manifest
+RESOURCES_FILES		:= $(shell find $(RESOURCES_DIR) ! -name Manifest -type f)
+
 DOLPHIN_SOURCE_DIR			:= $(ASSETS_DIR)/dolphin
 DOLPHIN_INTERNAL_OUTPUT_DIR	:= $(ASSETS_COMPILED_DIR)
 DOLPHIN_EXTERNAL_OUTPUT_DIR	:= $(ASSETS_DIR)/resources/dolphin

+ 240 - 0
assets/resources/Manifest

@@ -0,0 +1,240 @@
+V:0
+T:1650389893
+D:badusb
+D:dolphin
+D:infrared
+D:nfc
+D:subghz
+D:u2f
+F:bb8ffef2d052f171760ce3dc5220cbad:1591:badusb/demo_macos.txt
+F:e538ad2ce5a06ec45e1b5b24824901b1:1552:badusb/demo_windows.txt
+D:dolphin/L1_Boxing_128x64
+D:dolphin/L1_Cry_128x64
+D:dolphin/L1_Furippa1_128x64
+D:dolphin/L1_Laptop_128x51
+D:dolphin/L1_Leaving_sad_128x64
+D:dolphin/L1_Mad_fist_128x64
+D:dolphin/L1_Read_books_128x64
+D:dolphin/L1_Recording_128x51
+D:dolphin/L1_Sleep_128x64
+D:dolphin/L1_Waves_128x50
+D:dolphin/L2_Furippa2_128x64
+D:dolphin/L2_Hacking_pc_128x64
+D:dolphin/L2_Soldering_128x64
+D:dolphin/L3_Furippa3_128x64
+D:dolphin/L3_Hijack_radio_128x64
+D:dolphin/L3_Lab_research_128x54
+F:d1148ab5354eaf4fa7f959589d840932:1563:dolphin/manifest.txt
+F:d37be8444102ec5cde5fe3a85d55b57d:481:dolphin/L1_Boxing_128x64/frame_0.bm
+F:54fb07443bc153ded9589b74d23b4263:461:dolphin/L1_Boxing_128x64/frame_1.bm
+F:e007afe130d699c715b99ce8e5b407bd:531:dolphin/L1_Boxing_128x64/frame_2.bm
+F:a999a9a6c76c66158f1aa5ccb56de7c9:437:dolphin/L1_Boxing_128x64/frame_3.bm
+F:ec6af9cb451ab16c0fa62e95e8134b49:459:dolphin/L1_Boxing_128x64/frame_4.bm
+F:2aa0c1e7bf1131b9dc172aa595ec01f2:450:dolphin/L1_Boxing_128x64/frame_5.bm
+F:bbc8f750d17d156438c5cfe1122ec7f4:442:dolphin/L1_Boxing_128x64/frame_6.bm
+F:f6e51ada3e3285e330714dab5b4277dd:418:dolphin/L1_Boxing_128x64/meta.txt
+F:ab33a6f37209541f3db938d1cfe1706f:889:dolphin/L1_Cry_128x64/frame_0.bm
+F:1b3fdeb404af0f7402caa5a5e091a8f8:911:dolphin/L1_Cry_128x64/frame_1.bm
+F:4db644b173af72f3d371d2bd81f76b05:910:dolphin/L1_Cry_128x64/frame_2.bm
+F:cd4c0ef67a8e514edecd9600242db068:923:dolphin/L1_Cry_128x64/frame_3.bm
+F:ee02e9589e0714d3e2bc0d93aa294ccb:894:dolphin/L1_Cry_128x64/frame_4.bm
+F:7703a7d9745d13b45d73ce4b86b4cdc8:940:dolphin/L1_Cry_128x64/frame_5.bm
+F:ee6de6a0ed903317c4948cb445e0a9a8:915:dolphin/L1_Cry_128x64/frame_6.bm
+F:a3892e45826c66f48d3d64fb81521446:934:dolphin/L1_Cry_128x64/frame_7.bm
+F:680b12cc4dad722d6583b7e710bfc297:516:dolphin/L1_Cry_128x64/meta.txt
+F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_0.bm
+F:5669bee57c7b3d93a1665dd87fd5372a:325:dolphin/L1_Furippa1_128x64/frame_1.bm
+F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L1_Furippa1_128x64/frame_10.bm
+F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L1_Furippa1_128x64/frame_11.bm
+F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L1_Furippa1_128x64/frame_12.bm
+F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L1_Furippa1_128x64/frame_13.bm
+F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L1_Furippa1_128x64/frame_14.bm
+F:535c0eca62703eb7df36f17334a6191b:719:dolphin/L1_Furippa1_128x64/frame_15.bm
+F:7c03af85ade9b791755f3a4d106c2b7c:458:dolphin/L1_Furippa1_128x64/frame_16.bm
+F:41b8fea16ad8705f4594e6119eade395:400:dolphin/L1_Furippa1_128x64/frame_17.bm
+F:2db7fd3da5208a8e41902ae27cf41702:333:dolphin/L1_Furippa1_128x64/frame_18.bm
+F:7e47428442e0f04959fc6afde979936e:351:dolphin/L1_Furippa1_128x64/frame_2.bm
+F:0eb187078f169d7a852e97ecf430aea0:324:dolphin/L1_Furippa1_128x64/frame_3.bm
+F:967c402971a442a5bf28eba804bb3ff4:387:dolphin/L1_Furippa1_128x64/frame_4.bm
+F:175cb930fba0fc86f54a3a109b741708:390:dolphin/L1_Furippa1_128x64/frame_5.bm
+F:f8c3ee1ab657549d1d00c1c72d8d2ff5:407:dolphin/L1_Furippa1_128x64/frame_6.bm
+F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_7.bm
+F:8f649ff34b224f4e564644a4494c54ed:283:dolphin/L1_Furippa1_128x64/frame_8.bm
+F:3ec3c40d26bf8d3e691b1335d20d4ec0:312:dolphin/L1_Furippa1_128x64/frame_9.bm
+F:ebe088426d184cf6651288accd21add6:241:dolphin/L1_Furippa1_128x64/meta.txt
+F:d02fdfd1a3b89da00d2acf32bd09da80:555:dolphin/L1_Laptop_128x51/frame_0.bm
+F:7e29ea503d41023fa3895d15458f106d:557:dolphin/L1_Laptop_128x51/frame_1.bm
+F:eb55e0629de873f537d8412ced528eb4:560:dolphin/L1_Laptop_128x51/frame_2.bm
+F:1516472ab3c140dd5bd4d089caa44747:556:dolphin/L1_Laptop_128x51/frame_3.bm
+F:61172f89cf0a17bd7f978edccdeed166:560:dolphin/L1_Laptop_128x51/frame_4.bm
+F:9d54913928c7e9477b6b8a43f3767621:554:dolphin/L1_Laptop_128x51/frame_5.bm
+F:5243d6272bbb213e9c17af07ee011402:553:dolphin/L1_Laptop_128x51/frame_6.bm
+F:aa68e0f28f117891ba0f4d7613224fc6:560:dolphin/L1_Laptop_128x51/frame_7.bm
+F:9ef1935ab29fe70bbc517f4b602547d7:403:dolphin/L1_Laptop_128x51/meta.txt
+F:6ce34e62c5bf4764a4163101afe63e60:514:dolphin/L1_Leaving_sad_128x64/frame_0.bm
+F:19a0e0c518d222d91d24b8712ab6bb80:526:dolphin/L1_Leaving_sad_128x64/frame_1.bm
+F:837bfb424c8d8a3bfbda7d6a28ba5a5c:316:dolphin/L1_Leaving_sad_128x64/frame_10.bm
+F:1a69b6f63a96e0958837ea8b21db3966:294:dolphin/L1_Leaving_sad_128x64/frame_11.bm
+F:c3ea827593a4563d544dfb7e99d73885:322:dolphin/L1_Leaving_sad_128x64/frame_12.bm
+F:1e3842669191fe9599f830ac133e0751:542:dolphin/L1_Leaving_sad_128x64/frame_2.bm
+F:9161660e6827bd776a15eefa2a8add19:557:dolphin/L1_Leaving_sad_128x64/frame_3.bm
+F:d01a79fdb4f84397d82bf9927aeb71e0:488:dolphin/L1_Leaving_sad_128x64/frame_4.bm
+F:316e30ef319c080fab2a79c21e526319:469:dolphin/L1_Leaving_sad_128x64/frame_5.bm
+F:09a812d59b60b5fe7724057daa14ad60:499:dolphin/L1_Leaving_sad_128x64/frame_6.bm
+F:9eb07b76cc864a0ce2918d68e41d4500:486:dolphin/L1_Leaving_sad_128x64/frame_7.bm
+F:cf8c4cc4abbd700b096037b7ebfd0e31:403:dolphin/L1_Leaving_sad_128x64/frame_8.bm
+F:889728ded689203aa82193e573912d18:317:dolphin/L1_Leaving_sad_128x64/frame_9.bm
+F:2bff1f09ad1e9059a60e08990ca1d414:477:dolphin/L1_Leaving_sad_128x64/meta.txt
+F:c31a882e95ed5c69fd63226db2188710:520:dolphin/L1_Mad_fist_128x64/frame_0.bm
+F:740326828f6ba6e29373943ba835e77f:540:dolphin/L1_Mad_fist_128x64/frame_1.bm
+F:0c9693dda040fd73ca6d773a10924bd8:542:dolphin/L1_Mad_fist_128x64/frame_10.bm
+F:425c1d101debd1e9502db2628640b704:505:dolphin/L1_Mad_fist_128x64/frame_11.bm
+F:aa576f7dbd14ec682f6c50314165fb14:501:dolphin/L1_Mad_fist_128x64/frame_12.bm
+F:712335eabefb8c7bb7fb2f4301419c10:500:dolphin/L1_Mad_fist_128x64/frame_13.bm
+F:b6e11711ea4dcc2e64f267d888f91baf:515:dolphin/L1_Mad_fist_128x64/frame_2.bm
+F:61bdd22a2b1e67efe093b6acf7dfadce:538:dolphin/L1_Mad_fist_128x64/frame_3.bm
+F:20ae06a3ce7a07656e578edb024e2b3f:512:dolphin/L1_Mad_fist_128x64/frame_4.bm
+F:45cf2bd55365a7328df39fe98a496cc9:519:dolphin/L1_Mad_fist_128x64/frame_5.bm
+F:4b8840eebb3a4a1ead69a7130816047e:524:dolphin/L1_Mad_fist_128x64/frame_6.bm
+F:0de4497a5fbf80cc93e523465c5e3122:515:dolphin/L1_Mad_fist_128x64/frame_7.bm
+F:32d8ddeb19bfa415fe283666b1e323a2:517:dolphin/L1_Mad_fist_128x64/frame_8.bm
+F:a42a0578c2d0411500fb3485a3beb536:526:dolphin/L1_Mad_fist_128x64/frame_9.bm
+F:10a521c78168a5928c859494e2a61cd2:349:dolphin/L1_Mad_fist_128x64/meta.txt
+F:61565b7be9a69a60ce2dbae0273df347:653:dolphin/L1_Read_books_128x64/frame_0.bm
+F:cf5a2d423540e3af37e789d70c9c1fbf:653:dolphin/L1_Read_books_128x64/frame_1.bm
+F:c91935861979d024e6637b8810889878:650:dolphin/L1_Read_books_128x64/frame_2.bm
+F:0c007a30f396f3e7a0ded2b24080357d:646:dolphin/L1_Read_books_128x64/frame_3.bm
+F:323a52816dd79d6d3186f451e26e06ad:650:dolphin/L1_Read_books_128x64/frame_4.bm
+F:494f27958f4cea9b94d09cf27725c5cd:652:dolphin/L1_Read_books_128x64/frame_5.bm
+F:a6a7491fe80255e1745c9f293da52805:646:dolphin/L1_Read_books_128x64/frame_6.bm
+F:238497e6643fd491cd6002e98c615c05:647:dolphin/L1_Read_books_128x64/frame_7.bm
+F:300651e8f53d9a29ae38d4b9292c73cf:643:dolphin/L1_Read_books_128x64/frame_8.bm
+F:3d9568deeff646b677092902a98f9ceb:325:dolphin/L1_Read_books_128x64/meta.txt
+F:2aba555567ab70cff003ded4138c6721:663:dolphin/L1_Recording_128x51/frame_0.bm
+F:8456c6e86825957e5662e2f08eb6c116:657:dolphin/L1_Recording_128x51/frame_1.bm
+F:2e4a1aca5afa5a6ab254884210875eb4:629:dolphin/L1_Recording_128x51/frame_10.bm
+F:9f1cf96598e3d935879b1d0c97705778:659:dolphin/L1_Recording_128x51/frame_11.bm
+F:409abfeca974e5649affcd1faafea988:628:dolphin/L1_Recording_128x51/frame_2.bm
+F:66b2a5abf05acbf79f9943e01b8b8cec:654:dolphin/L1_Recording_128x51/frame_3.bm
+F:d55c5ed28c2ff48f42ab30b420d64fa3:662:dolphin/L1_Recording_128x51/frame_4.bm
+F:2ce12d8cfdd953c9dadb9459c580a320:622:dolphin/L1_Recording_128x51/frame_5.bm
+F:da631e3837fcdf3ee9e6abdf17fb764b:664:dolphin/L1_Recording_128x51/frame_6.bm
+F:604a7cdac2491c9bc2e88b9e91c99dcc:626:dolphin/L1_Recording_128x51/frame_7.bm
+F:fc94649dc98244dd9a0ab7fe62721d3c:663:dolphin/L1_Recording_128x51/frame_8.bm
+F:b2475ab8ee26cbd9a403ee603520bd35:661:dolphin/L1_Recording_128x51/frame_9.bm
+F:a7c2b3b420706712149cc2426c68df4f:219:dolphin/L1_Recording_128x51/meta.txt
+F:9858fd34b55cebcb9be50c5710212a13:580:dolphin/L1_Sleep_128x64/frame_0.bm
+F:e47ef8c846083b8fde028b1724861444:589:dolphin/L1_Sleep_128x64/frame_1.bm
+F:9749bd05b47fd07cc3a41ab201f86bf4:582:dolphin/L1_Sleep_128x64/frame_2.bm
+F:edf11266b20b846ace622e41cd36906b:597:dolphin/L1_Sleep_128x64/frame_3.bm
+F:8fbb96a9d809d85fa6bad931fe4e6fe2:510:dolphin/L1_Sleep_128x64/meta.txt
+F:283b41f1b2c581c510ff176293b7288a:443:dolphin/L1_Waves_128x50/frame_0.bm
+F:c9fc5127e1d8a4217b6b177716725ba0:448:dolphin/L1_Waves_128x50/frame_1.bm
+F:8e0797bf26d5d8d3cbeb99798c222b80:463:dolphin/L1_Waves_128x50/frame_2.bm
+F:da02b1deb3119b31f2b8f182d5bf3242:472:dolphin/L1_Waves_128x50/frame_3.bm
+F:8e6fb4133acbda7e5bb9adad0aed306c:620:dolphin/L1_Waves_128x50/meta.txt
+F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_0.bm
+F:9e628f5e154f12d6c57b13befed1f5f6:385:dolphin/L2_Furippa2_128x64/frame_1.bm
+F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L2_Furippa2_128x64/frame_10.bm
+F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L2_Furippa2_128x64/frame_11.bm
+F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L2_Furippa2_128x64/frame_12.bm
+F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L2_Furippa2_128x64/frame_13.bm
+F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L2_Furippa2_128x64/frame_14.bm
+F:e3c92103f403857b502081d3b058e53a:740:dolphin/L2_Furippa2_128x64/frame_15.bm
+F:432669d796bbf7be1d14f5b7db036a92:533:dolphin/L2_Furippa2_128x64/frame_16.bm
+F:53485c6b465c80a1ce8ddf03c4976039:451:dolphin/L2_Furippa2_128x64/frame_17.bm
+F:333b75b16c088428a28259c931630fb9:397:dolphin/L2_Furippa2_128x64/frame_18.bm
+F:ed02d68380382361f3f01cbf01d13b0c:402:dolphin/L2_Furippa2_128x64/frame_2.bm
+F:b0ba042d7b60dc5681182b1d4005f0a2:374:dolphin/L2_Furippa2_128x64/frame_3.bm
+F:518a84fa5a4e9e7f84246d5d82e87f15:440:dolphin/L2_Furippa2_128x64/frame_4.bm
+F:9b7b0ae6f4f55d30cb43b0465216aa25:449:dolphin/L2_Furippa2_128x64/frame_5.bm
+F:03b153949b0dae2efe1fc5f0dc57a0ef:466:dolphin/L2_Furippa2_128x64/frame_6.bm
+F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_7.bm
+F:a8433f451cf3efc4ce2fb04a38c1f84f:319:dolphin/L2_Furippa2_128x64/frame_8.bm
+F:d32a11bf9779d57191c1e59fe69cf83d:317:dolphin/L2_Furippa2_128x64/frame_9.bm
+F:ebe088426d184cf6651288accd21add6:241:dolphin/L2_Furippa2_128x64/meta.txt
+F:af4ec0085c29732085c51b18dc97bc27:543:dolphin/L2_Hacking_pc_128x64/frame_0.bm
+F:eb141965fb6fb9f8b28766bac92abe1a:545:dolphin/L2_Hacking_pc_128x64/frame_1.bm
+F:f7b33d3541dab08aaf4e8375e262b982:548:dolphin/L2_Hacking_pc_128x64/frame_2.bm
+F:03634d90c54fd235aa76c0f9f794c80b:608:dolphin/L2_Hacking_pc_128x64/frame_3.bm
+F:4c77406302f3fb74f8bdba568097082a:609:dolphin/L2_Hacking_pc_128x64/frame_4.bm
+F:b0d1783358094534ac95b3455124d5fe:409:dolphin/L2_Hacking_pc_128x64/meta.txt
+F:584c92e6fb15e99389b84d567e6d4d02:699:dolphin/L2_Soldering_128x64/frame_0.bm
+F:3fa01b93460379204b6d14f43573b4f3:688:dolphin/L2_Soldering_128x64/frame_1.bm
+F:6fad29757d4b7231b1d0ec53d0529b45:699:dolphin/L2_Soldering_128x64/frame_10.bm
+F:e82c83e5a03abf4f6a1efd0a0f1ca33a:689:dolphin/L2_Soldering_128x64/frame_2.bm
+F:7f9f310e22ef85af225dd1aefa2c47ba:689:dolphin/L2_Soldering_128x64/frame_3.bm
+F:1ff31af6f90f07c0cdfa3283f52a5adc:693:dolphin/L2_Soldering_128x64/frame_4.bm
+F:1a8f25aff949860cc6ffc79b4f48d5dd:696:dolphin/L2_Soldering_128x64/frame_5.bm
+F:dbaa75feb8aebaf9b1cc5201c29952b8:712:dolphin/L2_Soldering_128x64/frame_6.bm
+F:ee356bd981fba90c402d8e08d3015792:732:dolphin/L2_Soldering_128x64/frame_7.bm
+F:09d5c5a685df606562d407bb9dac798e:705:dolphin/L2_Soldering_128x64/frame_8.bm
+F:5451816e73bad029b3b9f3f55d294582:698:dolphin/L2_Soldering_128x64/frame_9.bm
+F:c38ffad11987faf5ba6e363ead705e78:319:dolphin/L2_Soldering_128x64/meta.txt
+F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_0.bm
+F:8cf20e07d84fd6a1157ba932beca70ea:438:dolphin/L3_Furippa3_128x64/frame_1.bm
+F:018344c951691b7b1d77c1c6729d3e42:559:dolphin/L3_Furippa3_128x64/frame_10.bm
+F:07008e2508064ab7a8467802472a9803:728:dolphin/L3_Furippa3_128x64/frame_11.bm
+F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L3_Furippa3_128x64/frame_12.bm
+F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L3_Furippa3_128x64/frame_13.bm
+F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L3_Furippa3_128x64/frame_14.bm
+F:e333224a4bed87b606df57a252ed4887:741:dolphin/L3_Furippa3_128x64/frame_15.bm
+F:a20a6abfbd66fc3f92c66adacc4444a3:559:dolphin/L3_Furippa3_128x64/frame_16.bm
+F:c1e051dce6b90e4f69b4792d0356a6b3:492:dolphin/L3_Furippa3_128x64/frame_17.bm
+F:377f3621507c6590120cbc1c8ca92999:445:dolphin/L3_Furippa3_128x64/frame_18.bm
+F:81f09c0fcd2bddb8a107a199e7149230:463:dolphin/L3_Furippa3_128x64/frame_2.bm
+F:ed7fd1ada1070493462c1899f7372baf:424:dolphin/L3_Furippa3_128x64/frame_3.bm
+F:e5fb2cdc4e08d6abff3191d37a1007ed:499:dolphin/L3_Furippa3_128x64/frame_4.bm
+F:923a05250e5a93c7db7bbbf48448d164:504:dolphin/L3_Furippa3_128x64/frame_5.bm
+F:1e9628db28a9a908c4a4b24cb16c5d20:521:dolphin/L3_Furippa3_128x64/frame_6.bm
+F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_7.bm
+F:f1ec6e12daba9490f9e2e0e308ae3f83:419:dolphin/L3_Furippa3_128x64/frame_8.bm
+F:106997120ad4cd23bd51e6f26bd7d74d:435:dolphin/L3_Furippa3_128x64/frame_9.bm
+F:ebe088426d184cf6651288accd21add6:241:dolphin/L3_Furippa3_128x64/meta.txt
+F:42970030123b2468984785fea7c60318:524:dolphin/L3_Hijack_radio_128x64/frame_0.bm
+F:491c6d8ef21e48ca0f6b5fbd269c820b:527:dolphin/L3_Hijack_radio_128x64/frame_1.bm
+F:ff499c8716c5f7fc1110a5ee82bda20c:550:dolphin/L3_Hijack_radio_128x64/frame_10.bm
+F:ee39d82d6efc6a6992d19b6d75a6c509:572:dolphin/L3_Hijack_radio_128x64/frame_11.bm
+F:5d14e8cb9d67bf8f597d6c749d07a135:539:dolphin/L3_Hijack_radio_128x64/frame_12.bm
+F:9461004b75a34a36097668159c4cabe6:579:dolphin/L3_Hijack_radio_128x64/frame_13.bm
+F:c925d4b1dff9c81463944cf930d7da8d:526:dolphin/L3_Hijack_radio_128x64/frame_2.bm
+F:f98ed80cfab3a94b580be81654401c89:529:dolphin/L3_Hijack_radio_128x64/frame_3.bm
+F:97ba548c27732be9e05fb8f7be8204ce:571:dolphin/L3_Hijack_radio_128x64/frame_4.bm
+F:524932eb2391057fc1dea7237c7086e3:574:dolphin/L3_Hijack_radio_128x64/frame_5.bm
+F:8eb9672f719926ac9c4c158575f388cd:524:dolphin/L3_Hijack_radio_128x64/frame_6.bm
+F:7ca93fbab93bc278d4a11089d624a07b:655:dolphin/L3_Hijack_radio_128x64/frame_7.bm
+F:37b4368f0b7235f3a7347bf499541666:645:dolphin/L3_Hijack_radio_128x64/frame_8.bm
+F:ea9c3d7bab4756c2916369d5e130fa71:611:dolphin/L3_Hijack_radio_128x64/frame_9.bm
+F:8583743f18a12ff647d3478e7aebdad6:230:dolphin/L3_Hijack_radio_128x64/meta.txt
+F:f5f02a9df03bba734bdb7ed3297795f0:611:dolphin/L3_Lab_research_128x54/frame_0.bm
+F:8f9655ad286464159443922d00e45620:614:dolphin/L3_Lab_research_128x54/frame_1.bm
+F:7793b1bc107d4ea2e311e92dc16bf946:576:dolphin/L3_Lab_research_128x54/frame_10.bm
+F:f24b8409f9dc770f3845424fe0ab489e:585:dolphin/L3_Lab_research_128x54/frame_11.bm
+F:4ea93c4482dac43f40b67cc308f21e6d:571:dolphin/L3_Lab_research_128x54/frame_12.bm
+F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_13.bm
+F:79719219aaebc95ea525def9173cabf5:618:dolphin/L3_Lab_research_128x54/frame_2.bm
+F:05572cfd756704acd6ce9d6c15d03fc0:608:dolphin/L3_Lab_research_128x54/frame_3.bm
+F:a26604a0d5427d5cf62a7a911a68b16c:615:dolphin/L3_Lab_research_128x54/frame_4.bm
+F:9edc345fe53017970f93dc680818e63e:618:dolphin/L3_Lab_research_128x54/frame_5.bm
+F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_6.bm
+F:5442895c85f769349288aa3df0990f9d:585:dolphin/L3_Lab_research_128x54/frame_7.bm
+F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm
+F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm
+F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt
+D:infrared/assets
+F:5b16e1a59daf3ef1d0fc95b3b5596d67:74300:infrared/assets/tv.ir
+D:nfc/assets
+F:c6826a621d081d68309e4be424d3d974:4715:nfc/assets/aid.nfc
+F:86efbebdf41bb6bf15cc51ef88f069d5:2565:nfc/assets/country_code.nfc
+F:41b4f08774249014cb8d3dffa5f5c07d:1757:nfc/assets/currency_code.nfc
+F:c60e862919731b0bd538a1001bbc1098:17453:nfc/assets/mf_classic_dict.nfc
+D:subghz/assets
+F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo
+F:610a0ffa2479a874f2060eb2348104c5:2712:subghz/assets/keeloq_mfcodes
+F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user
+F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s
+F:00e967e5c558e44a0651bb821d5cf1d0:414:subghz/assets/setting_frequency_analyzer_user
+F:16e8c7cb4a13f26ea55b2b0a59f9cc7a:554:subghz/assets/setting_user
+D:u2f/assets
+F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der
+F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f

+ 1 - 1
lib/update_util/update_manifest.c

@@ -13,7 +13,7 @@
 #define MANIFEST_KEY_RADIO_ADDRESS "Radio address"
 #define MANIFEST_KEY_RADIO_VERSION "Radio version"
 #define MANIFEST_KEY_RADIO_CRC "Radio CRC"
-#define MANIFEST_KEY_ASSETS_FILE "Assets"
+#define MANIFEST_KEY_ASSETS_FILE "Resources"
 
 UpdateManifest* update_manifest_alloc() {
     UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest));

+ 0 - 1
make/rules.mk

@@ -86,7 +86,6 @@ $(OBJ_DIR)/upload: $(OBJ_DIR)/$(PROJECT).bin
 	dfu-util -d 0483:df11 -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS)
 	touch $@
 
-
 .PHONY: flash
 flash: $(OBJ_DIR)/flash
 

+ 8 - 5
scripts/assets.py

@@ -203,15 +203,12 @@ class Main(App):
         manifest_file = os.path.join(directory_path, "Manifest")
         old_manifest = Manifest()
         if os.path.exists(manifest_file):
-            self.logger.info(
-                f"old manifest is present, loading for compare and removing file"
-            )
+            self.logger.info("old manifest is present, loading for compare")
             old_manifest.load(manifest_file)
-            os.unlink(manifest_file)
         self.logger.info(f'Creating new Manifest for directory "{directory_path}"')
         new_manifest = Manifest()
         new_manifest.create(directory_path)
-        new_manifest.save(manifest_file)
+
         self.logger.info(f"Comparing new manifest with old")
         only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest)
         for record in only_in_old:
@@ -220,6 +217,12 @@ class Main(App):
             self.logger.info(f"Changed: {record}")
         for record in only_in_new:
             self.logger.info(f"Only in new: {record}")
+        if any((only_in_old, changed, only_in_new)):
+            self.logger.warning("Manifests are different, updating")
+            new_manifest.save(manifest_file)
+        else:
+            self.logger.info("Manifest is up-to-date!")
+
         self.logger.info(f"Complete")
 
         return 0

+ 6 - 6
scripts/dist.py

@@ -18,7 +18,7 @@ class Main(App):
         self.parser_copy.add_argument("-t", dest="target", required=True)
         self.parser_copy.add_argument("-p", dest="projects", nargs="+", required=True)
         self.parser_copy.add_argument("-s", dest="suffix", required=True)
-        self.parser_copy.add_argument("-a", dest="assets", required=False)
+        self.parser_copy.add_argument("-r", dest="resources", required=False)
         self.parser_copy.add_argument(
             "--bundlever",
             dest="version",
@@ -79,16 +79,16 @@ class Main(App):
                 self.args.version,
                 "-t",
                 self.args.target,
-                "-dfu",
+                "--dfu",
                 self.get_dist_filepath(self.get_project_filename("firmware", "dfu")),
-                "-stage",
+                "--stage",
                 self.get_dist_filepath(self.get_project_filename("updater", "bin")),
             ]
-            if self.args.assets:
+            if self.args.resources:
                 bundle_args.extend(
                     (
-                        "-a",
-                        self.args.assets,
+                        "-r",
+                        self.args.resources,
                     )
                 )
             self.logger.info(

+ 1 - 1
scripts/flash.py

@@ -8,7 +8,7 @@ import os
 from flipper.app import App
 from flipper.cube import CubeProgrammer
 
-STATEMENT = "AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE"
+STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE"
 
 
 class Main(App):

+ 10 - 7
scripts/flipper/assets/manifest.py

@@ -18,10 +18,10 @@ class ManifestRecord:
     def toLine(self):
         raise NotImplementedError
 
-    def _unpack(self, manifest, key, type):
+    def _unpack(self, manifest, key, nodetype):
         key, value = manifest.readline().split(":", 1)
         assert key == key
-        return type(value)
+        return nodetype(value)
 
 
 MANIFEST_TAGS_RECORDS = {}
@@ -94,7 +94,7 @@ class ManifestRecordFile(ManifestRecord):
     @staticmethod
     def fromLine(line):
         data = line.split(":", 3)
-        return ManifestRecordFile(data[2], data[0], data[1])
+        return ManifestRecordFile(data[2], data[0], int(data[1]))
 
     def toLine(self):
         return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n"
@@ -133,7 +133,7 @@ class Manifest:
     def addFile(self, path, md5, size):
         self.records.append(ManifestRecordFile(path, md5, size))
 
-    def create(self, directory_path):
+    def create(self, directory_path, ignore_files=["Manifest"]):
         for root, dirs, files in os.walk(directory_path):
             relative_root = root.replace(directory_path, "", 1)
             if relative_root.startswith("/"):
@@ -141,13 +141,16 @@ class Manifest:
             # process directories
             for dir in dirs:
                 relative_dir_path = os.path.join(relative_root, dir)
-                self.logger.info(f'Adding directory: "{relative_dir_path}"')
+                self.logger.debug(f'Adding directory: "{relative_dir_path}"')
                 self.addDirectory(relative_dir_path)
             # Process files
             for file in files:
                 relative_file_path = os.path.join(relative_root, file)
+                if file in ignore_files:
+                    self.logger.info(f'Skipping file "{relative_file_path}"')
+                    continue
                 full_file_path = os.path.join(root, file)
-                self.logger.info(f'Adding file: "{relative_file_path}"')
+                self.logger.debug(f'Adding file: "{relative_file_path}"')
                 self.addFile(
                     relative_file_path,
                     file_md5(full_file_path),
@@ -155,7 +158,7 @@ class Manifest:
                 )
 
     def toFsTree(self):
-        root = FsNode("", FsNode.Type.Directory)
+        root = FsNode("", FsNode.NodeType.Directory)
         for record in self.records:
             if isinstance(record, ManifestRecordDirectory):
                 root.addDirectory(record.path)

+ 28 - 10
scripts/flipper/utils/fstree.py

@@ -3,13 +3,13 @@ from collections import OrderedDict
 
 
 class FsNode:
-    class Type(Enum):
+    class NodeType(Enum):
         File = 0
         Directory = 1
 
-    def __init__(self, name: str, type: "FsNode.Type", **kwargs):
+    def __init__(self, name: str, nodetype: "FsNode.Type", **kwargs):
         self.name = name
-        self.type = type
+        self.nodetype = nodetype
         self.data = kwargs
         self.parent = None
         self.children = OrderedDict()
@@ -25,7 +25,7 @@ class FsNode:
         parent_node = self.traverse(fragments)
         if not parent_node:
             raise Exception(f"No parent node found for: {path}")
-        parent_node.addChild(FsNode(name, FsNode.Type.Directory))
+        parent_node.addChild(FsNode(name, FsNode.NodeType.Directory))
 
     def addFile(self, path, md5, size):
         fragments = path.split("/")
@@ -34,7 +34,7 @@ class FsNode:
         parent_node = self.traverse(fragments)
         if not parent_node:
             raise Exception(f"No parent node found for: {path}")
-        parent_node.addChild(FsNode(name, FsNode.Type.File, md5=md5, size=size))
+        parent_node.addChild(FsNode(name, FsNode.NodeType.File, md5=md5, size=size))
 
     def getChild(self, name):
         return self.children[name]
@@ -58,19 +58,37 @@ class FsNode:
     def dump(self):
         ret = {}
         ret["name"] = (self.name,)
-        ret["type"] = (self.type,)
+        ret["type"] = (self.nodetype,)
         ret["path"] = (self.getPath(),)
         if len(self.children):
             ret["children"] = [node.dump() for node in self.children.values()]
         return ret
 
 
+def walk_nodes(node: FsNode):
+    yield node
+    for child in node.children.values():
+        yield from walk_nodes(child)
+
+
+#  Returns filenames: [only_in_left], [changed], [only_in_right]
 def compare_fs_trees(left: FsNode, right: FsNode):
     # import pprint
     # pprint.pprint(left.dump())
     # pprint.pprint(right.dump())
+    left_dict = dict((node.getPath(), node) for node in walk_nodes(left))
+    right_dict = dict((node.getPath(), node) for node in walk_nodes(right))
+
+    left_names = set(left_dict.keys())
+    right_names = set(right_dict.keys())
+    common_names = left_names.intersection(right_names)
 
-    only_in_left = []
-    changed = []
-    only_in_right = []
-    return [], [], []
+    return (
+        list(left_names - right_names),
+        list(
+            name
+            for name in common_names
+            if left_dict[name].data != right_dict[name].data
+        ),
+        list(right_names - left_names),
+    )

+ 20 - 16
scripts/update.py

@@ -10,8 +10,12 @@ import tarfile
 
 
 class Main(App):
+    UPDATE_MANIFEST_NAME = "update.fuf"
+
     #  No compression, plain tar
-    ASSET_TAR_MODE = "w:"
+    RESOURCE_TAR_MODE = "w:"
+    RESOURCE_TAR_FORMAT = tarfile.USTAR_FORMAT
+    RESOURCE_FILE_NAME = "resources.tar"
 
     def init(self):
         self.subparsers = self.parser.add_subparsers(help="sub-command help")
@@ -24,17 +28,17 @@ class Main(App):
         self.parser_generate.add_argument("-d", dest="directory", required=True)
         self.parser_generate.add_argument("-v", dest="version", required=True)
         self.parser_generate.add_argument("-t", dest="target", required=True)
-        self.parser_generate.add_argument("-dfu", dest="dfu", required=False)
-        self.parser_generate.add_argument("-a", dest="assets", required=False)
-        self.parser_generate.add_argument("-stage", dest="stage", required=True)
+        self.parser_generate.add_argument("--dfu", dest="dfu", required=False)
+        self.parser_generate.add_argument("-r", dest="resources", required=False)
+        self.parser_generate.add_argument("--stage", dest="stage", required=True)
         self.parser_generate.add_argument(
-            "-radio", dest="radiobin", default="", required=False
+            "--radio", dest="radiobin", default="", required=False
         )
         self.parser_generate.add_argument(
-            "-radioaddr", dest="radioaddr", required=False
+            "--radioaddr", dest="radioaddr", required=False
         )
         self.parser_generate.add_argument(
-            "-radiover", dest="radioversion", required=False
+            "--radiover", dest="radioversion", required=False
         )
 
         self.parser_generate.set_defaults(func=self.generate)
@@ -43,7 +47,7 @@ class Main(App):
         stage_basename = basename(self.args.stage)
         dfu_basename = basename(self.args.dfu)
         radiobin_basename = basename(self.args.radiobin)
-        assets_basename = ""
+        resources_basename = ""
 
         if not exists(self.args.directory):
             os.makedirs(self.args.directory)
@@ -54,10 +58,10 @@ class Main(App):
             shutil.copyfile(
                 self.args.radiobin, join(self.args.directory, radiobin_basename)
             )
-        if self.args.assets:
-            assets_basename = "assets.tar"
-            self.package_assets(
-                self.args.assets, join(self.args.directory, assets_basename)
+        if self.args.resources:
+            resources_basename = self.RESOURCE_FILE_NAME
+            self.package_resources(
+                self.args.resources, join(self.args.directory, resources_basename)
             )
 
         file = FlipperFormatFile()
@@ -75,14 +79,14 @@ class Main(App):
             file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin)))
         else:
             file.writeKey("Radio CRC", self.int2ffhex(0))
-        file.writeKey("Assets", assets_basename)
-        file.save(join(self.args.directory, "update.fuf"))
+        file.writeKey("Resources", resources_basename)
+        file.save(join(self.args.directory, self.UPDATE_MANIFEST_NAME))
 
         return 0
 
-    def package_assets(self, srcdir: str, dst_name: str):
+    def package_resources(self, srcdir: str, dst_name: str):
         with tarfile.open(
-            dst_name, self.ASSET_TAR_MODE, format=tarfile.USTAR_FORMAT
+            dst_name, self.RESOURCE_TAR_MODE, format=self.RESOURCE_TAR_FORMAT
         ) as tarball:
             tarball.add(srcdir, arcname="")