From 49cad5677c9b9af27042511dd35f9329a618ae22 Mon Sep 17 00:00:00 2001 From: Sebastien Merle Date: Fri, 30 Aug 2024 17:54:44 +0200 Subject: [PATCH] Add grisp pack command --- rebar.config | 3 +- rebar.lock | 47 +++-- src/rebar3_grisp_firmware.erl | 6 +- src/rebar3_grisp_pack.erl | 324 ++++++++++++++++++++++++++++++++++ src/rebar3_grisp_util.erl | 18 +- 5 files changed, 381 insertions(+), 17 deletions(-) create mode 100644 src/rebar3_grisp_pack.erl diff --git a/rebar.config b/rebar.config index bfde460..952c14d 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,7 @@ {erl_opts, [debug_info]}. {deps, [ - grisp_tools, + % grisp_tools, + {grisp_tools, {git, "git@github.com:grisp/grisp_tools", {branch, "sylane/pack-command"}}}, grid ]}. diff --git a/rebar.lock b/rebar.lock index c11800f..a057844 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,41 +1,64 @@ {"1.2.0", [{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.12.2">>},1}, {<<"certifi">>,{pkg,<<"certifi">>,<<"2.12.0">>},2}, - {<<"grid">>,{pkg,<<"grid">>,<<"0.1.0">>},0}, - {<<"grisp_tools">>,{pkg,<<"grisp_tools">>,<<"2.6.1">>},0}, - {<<"hackney">>,{pkg,<<"hackney">>,<<"1.18.2">>},1}, + {<<"edifa">>,{pkg,<<"edifa">>,<<"1.0.0">>},1}, + {<<"erlexec">>,{pkg,<<"erlexec">>,<<"2.0.7">>},2}, + {<<"grid">>,{pkg,<<"grid">>,<<"0.2.1">>},0}, + {<<"grisp_tools">>, + {git,"git@github.com:grisp/grisp_tools", + {ref,"07b5533c74d5275f1a67da849ab59acc63328932"}}, + 0}, + {<<"grisp_update_packager">>, + {git,"git@github.com:grisp/grisp_update_packager", + {ref,"ba69691d7e936218df62c8a49fe4b0d359156f38"}}, + 1}, + {<<"hackney">>,{pkg,<<"hackney">>,<<"1.20.1">>},1}, {<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},2}, {<<"mapz">>,{pkg,<<"mapz">>,<<"2.4.0">>},1}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.3.0">>},2}, {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},2}, + {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.7">>},3}, {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},2}, - {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},2}]}. + {<<"termseal">>,{pkg,<<"termseal">>,<<"0.1.1">>},2}, + {<<"textual">>,{pkg,<<"textual">>,<<"0.1.1">>},1}, + {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},2}, + {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"2.0.4">>},2}]}. [ {pkg_hash,[ {<<"bbmustache">>, <<"0CABDCE0DB9FE6D3318131174B9F2B351328A4C0AFBEB3E6E99BB0E02E9B621D">>}, {<<"certifi">>, <<"2D1CCA2EC95F59643862AF91F001478C9863C2AC9CB6E2F89780BFD8DE987329">>}, - {<<"grid">>, <<"880F3D2E5B4E9B3B93FDE2BC93F11F6CD6DE82BE886D3AF026C2D6A17C762907">>}, - {<<"grisp_tools">>, <<"492F579EE450C7618EDB118A5BBC3F8FE00EC0073305246B80C444C1B176EE8C">>}, - {<<"hackney">>, <<"D7FF544DDAE5E1CB49E9CF7FA4E356D7F41B283989A1C304BFC47A8CC1CF966F">>}, + {<<"edifa">>, <<"0F1A01A0C79B7135F334B3FCEEB624F0574C5ED3E4554B06C8664AADA6A339C8">>}, + {<<"erlexec">>, <<"76D0BC7487929741B5BB9F74DA2AF5DAF1492134733CF9A05C7AAA278B6934C5">>}, + {<<"grid">>, <<"4DCBF6155AB24131CB493D417F28093F019197ED7401F28BF82FF60E2C9B0D2C">>}, + {<<"hackney">>, <<"8D97AEC62DDDDD757D128BFD1DF6C5861093419F8F7A4223823537BAD5D064E2">>}, {<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>}, {<<"mapz">>, <<"77A8E38B69BAB16C5D3EBD44E6C619F8AF1F1598B0CAAE301D266605A0865756">>}, {<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>}, {<<"mimerl">>, <<"D0CD9FC04B9061F82490F6581E0128379830E78535E017F7780F37FEA7545726">>}, {<<"parse_trans">>, <<"6E6AA8167CB44CC8F39441D05193BE6E6F4E7C2946CB2759F015F8C56B76E5FF">>}, + {<<"quickrand">>, <<"D2BD76676A446E6A058D678444B7FDA1387B813710D1AF6D6E29BB92186C8820">>}, {<<"ssl_verify_fun">>, <<"354C321CF377240C7B8716899E182CE4890C5938111A1296ADD3EC74CF1715DF">>}, - {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]}, + {<<"termseal">>, <<"C9D93D4FF638EE99F9377D3438FC7AD132D2901EBBAF10C54F8DEA1D7E24D61C">>}, + {<<"textual">>, <<"42D6AFE1E58F128E607C237EC213CD3DD69B780A3527039B2A90CA6600456B3C">>}, + {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, + {<<"uuid">>, <<"77C3E3EE1E1701A2856CE945846D7CEB71931C60633A305D0B0FEAE03B2B3B5C">>}]}, {pkg_hash_ext,[ {<<"bbmustache">>, <<"688B33A4D5CC2D51F575ADF0B3683FC40A38314A2F150906EDCFC77F5B577B3B">>}, {<<"certifi">>, <<"EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C">>}, - {<<"grid">>, <<"E71751225A9DFF8C7C96551CC181C0FDD8D8C666D3C2FE44A832D6F8B7BE0013">>}, - {<<"grisp_tools">>, <<"7642DE1A466B92AE70C0924605211AD126F65B0F2BFC56069FA996C5CCC78104">>}, - {<<"hackney">>, <<"AF94D5C9F97857DB257090A4A10E5426ECB6F4918AA5CC666798566AE14B65FD">>}, + {<<"edifa">>, <<"A1E010561E7D236A24C668D95626BE2BFE082ED0331CE1E6798BE0CD43F59A7B">>}, + {<<"erlexec">>, <<"AF2DD940BB8E32F5AA40A65CB455DCAA18F5334FD3507E9BFD14A021E9630897">>}, + {<<"grid">>, <<"C8EA819A0E40631BECE3149FBA7D306DF6CF8BC35358089878F05B20E6D87D4C">>}, + {<<"hackney">>, <<"FE9094E5F1A2A2C0A7D10918FEE36BFEC0EC2A979994CFF8CFE8058CD9AF38E3">>}, {<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>}, {<<"mapz">>, <<"4B68DF5CF0522E0D6545DF7B681BC052865CDB78405AD4CC9C55FE45EE7B25BE">>}, {<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>}, {<<"mimerl">>, <<"A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D">>}, {<<"parse_trans">>, <<"620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A">>}, + {<<"quickrand">>, <<"B8ACBF89A224BC217C3070CA8BEBC6EB236DBE7F9767993B274084EA044D35F0">>}, {<<"ssl_verify_fun">>, <<"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8">>}, - {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]} + {<<"termseal">>, <<"466280936214AF1894FC431642E83341B7D13580A3F3485820A2D300C5CAEB49">>}, + {<<"textual">>, <<"28C1AE5DE77D3A13C9101DD64204C87069232149C2B924762F43D75730516CE9">>}, + {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, + {<<"uuid">>, <<"7A4CCD1C151D9B88B4383FA802BCCF9BCB3754B7F53D7CAA164D51A14A6652E4">>}]} ]. diff --git a/src/rebar3_grisp_firmware.erl b/src/rebar3_grisp_firmware.erl index 525fb69..03a0a6b 100644 --- a/src/rebar3_grisp_firmware.erl +++ b/src/rebar3_grisp_firmware.erl @@ -283,7 +283,7 @@ event([firmware, prepare, _, {error, not_a_file, Path}]) -> event([firmware, build_firmware, create_image]) -> console("* Creating disk image..."); event([firmware, build_firmware, create_image, {error, Reason}]) -> - abort_message("Failed to create firmware image file; ~s", Reason); + abort_message("Failed to create firmware image file: ~s", Reason); event([firmware, build_firmware, copy_bootloader]) -> console("* Writing bootloader..."); event([firmware, build_firmware, copy_bootloader, {error, Reason}]) -> @@ -346,9 +346,9 @@ event(Event) -> debug("[rebar3_grisp] ~p", [Event]), case lists:last(Event) of {error, Reason, Info} when is_binary(Info) -> - abort("Unexpected 1 ~p error: ~s", [Reason, Info]); + abort("Unexpected ~p error: ~s", [Reason, Info]); {error, Reason, Info} -> - abort("Unexpected 2 ~p error: ~p", [Reason, Info]); + abort("Unexpected ~p error: ~p", [Reason, Info]); {error, Reason} -> abort("Unexpected ~p error", [Reason]); _ -> ok diff --git a/src/rebar3_grisp_pack.erl b/src/rebar3_grisp_pack.erl new file mode 100644 index 0000000..fd6b151 --- /dev/null +++ b/src/rebar3_grisp_pack.erl @@ -0,0 +1,324 @@ +-module(rebar3_grisp_pack). + +% Callbacks +-export([init/1]). +-export([do/1]). +-export([format_error/1]). + +-import(rebar3_grisp_util, [ + debug/2, + info/1, + info/2, + console/1, + console/2, + warn/1, + warn/2, + abort/1, + abort/2 +]). + +-define(MAX_DDOT, 2). + +%--- Callbacks ----------------------------------------------------------------- + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Provider = providers:create([ + {namespace, grisp}, + {name, pack}, + {module, ?MODULE}, + {bare, true}, + {deps, [{default, install_deps}, {default, compile}]}, + {example, "rebar3 grisp pack"}, + {opts, [ + {relname, $n, "relname", string, "Specify the name for the release that will be deployed"}, + {relvsn, $v, "relvsn", string, "Specify the version of the release"}, + {system, undefined, "system", string, "The system firmware to use in the update package"}, + {bootloader, undefined, "bootloader", string, "The bootloader firmware to use in the update package"}, + {block_size, undefined, "block-size", integer, "The size of the blocks in bytes, before compression"}, + {key, $k, "key", string, "Private key PEM file to use to sign the update package"}, + {force_firmware, $F, "force_firmware", {boolean, false}, "Force firmware building even if it already exists"}, + {force, $f, "force", {boolean, false}, "Replace existing files"}, + {quiet, $q, "quiet", {boolean, false}, "Do not show the instructions on how to update a GRiSP2 board"} + ]}, + {profiles, [grisp]}, + {short_desc, "Generate a GRiSP software update package"}, + {desc, + "Generate a tarball that can be used with grisp software update.\n" + "\n" + "If no firmware file is specified, it will be generated by " + "calling 'rebar3 grisp firmware' with the optional release name " + "and version. As for the firmware command, options passed after " + "'--' are sent to the Rebar 3 release task.\n" + } + ]), + {ok, rebar_state:add_provider(State, Provider)}. + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(RState) -> + try + {Args, ExtraArgs} = rebar_state:command_parsed_args(RState), + RelNameArg = proplists:get_value(relname, Args, undefined), + RelVsnArg = proplists:get_value(relvsn, Args, undefined), + {RelName, RelVsn} + = rebar3_grisp_util:select_release(RState, RelNameArg, RelVsnArg), + case {proplists:get_value(firmware, Args, undefined), + proplists:get_value(bootloader, Args, undefined)} of + {undefined, undefined} -> + Force = proplists:get_value(force_firmware, Args, false), + case get_firmware(RState, Force, RelName, RelVsn, ExtraArgs) of + {error, _Reason} = Error -> Error; + {ok, SysFile, BootFile, RState2} -> + grisp_tools_pack(RState2, RelName, RelVsn, + [{firmware, SysFile}, + {bootloader, BootFile} | Args]) + end; + {SysFile, BootFile} + when SysFile =/= undefined, BootFile =/= undefined -> + case {filelib:is_file(SysFile), + filelib:is_file(BootFile)} of + {false, _} -> + abort("System firmware file not found: ~s", [SysFile]); + {_, false} -> + abort("Bootloader firmware file not found: ~s", [BootFile]); + {true, true} -> + SysRelPath = grisp_tools_util:maybe_relative(SysFile, ?MAX_DDOT), + BootRelPath = grisp_tools_util:maybe_relative(BootFile, ?MAX_DDOT), + console("* Using provided system firmware: ~s", [SysRelPath]), + console("* Using provided bootloader firmware: ~s", [BootRelPath]), + grisp_tools_pack(RState, RelName, RelVsn, Args) + end; + _ -> + abort("Both the system and bootloader firmwares are required, " + "the options --system and --bootloader must be specified together.", []) + end + catch + error:{release_not_selected, [{Name, [Version|_]}|_]} -> + abort( + "Multiple releases defined!~n" + "You must specify a name and optionally a version. Examples:~n" + "~n" + " rebar3 grisp pack --relname ~p~n" + " rebar3 grisp pack --relname ~p --relvsn ~s~n", + [Name, Name, Version] + ); + error:no_release_configured -> + App = rebar_app_info:name(hd(rebar_state:project_apps(RState))), + abort( + "No release configured" + "~n" + "You must specify at least one release in 'rebar.config' to be " + "able to create a software update package.~nExample:~n" + "~n" + " {relx,~n" + " {~s, \"0.1.0\", [~s]}~n" + " }.~n", + [App, App] + ); + error:{unknown_release_name, {Name, _Version}, Names} -> + abort( + "Unknown release '~p'~n" + "~n" + "Must be one of:" ++ [["~n ", atom_to_list(N)] || N <- Names], + [Name] + ); + error:{unknown_release_version, {Name, Version}, Versions} -> + abort( + "Release '~p' has no version ~s~n" + "~n" + "Must be one of:" ++ [["~n ", V] || V <- Versions], + [Name, Version] + ); + error:{create_dir_failed, Dir, {error, Reason}} -> + abort( + "Error creating directory ~s: ~s", + [Dir, file:format_error(Reason)] + ) + end. + +-spec format_error(any()) -> iolist(). +format_error(Reason) -> + io_lib:format("~p", [Reason]). + + +%--- Internal ------------------------------------------------------------------ + +get_firmware(RState, Force, RelName, RelVsn, ExtraRelArgs) -> + SysFile + = rebar3_grisp_util:firmware_file_path(RState, system, RelName, RelVsn), + BootFile + = rebar3_grisp_util:firmware_file_path(RState, boot, RelName, RelVsn), + case {filelib:is_file(SysFile), filelib:is_file(BootFile)} of + {true, true} when Force =:= false -> + SysRelPath = grisp_tools_util:maybe_relative(SysFile, ?MAX_DDOT), + BootRelPath = grisp_tools_util:maybe_relative(BootFile, ?MAX_DDOT), + console("* Using existing system firmware: ~s", [SysRelPath]), + console("* Using existing bootloader firmware: ~s", [BootRelPath]), + {ok, SysFile, BootFile, RState}; + _ -> + console("* Building firmwares...", []), + case build_firmwares(RState, Force, RelName, + RelVsn, ExtraRelArgs) of + {ok, RState2} -> {ok, SysFile, BootFile, RState2}; + {error, _Reason} = Error -> Error + end + end. + +build_firmwares(RState, Force, RelName, RelVsn, ExtraRelArgs) -> + Args = [ + "--tar", + "--relname", atom_to_list(RelName), + "--relvsn", RelVsn, + "--bootloader", + "--force", + "--quiet" + ] ++ case Force =:= true of + true -> ["--force-bundle"]; + false -> [] + end ++ case ExtraRelArgs of + [_|_] -> ["--" | ExtraRelArgs]; + _ -> [] + end, + rebar3_grisp_util:rebar_command(RState, grisp, firmware, Args). + +grisp_tools_pack(RState, RelName, RelVsn, Args) -> + SysFile = proplists:get_value(system, Args), + BootFile = proplists:get_value(bootloader, Args), + Force = proplists:get_value(force, Args, false), + KeyFile = proplists:get_value(key, Args), + BlockSize = proplists:get_value(block_size, Args), + PackageFile = rebar3_grisp_util:update_file_path(RState, RelName, RelVsn), + + PackSpec = #{ + name => RelName, + version => RelVsn, + block_size => BlockSize, + key_file => KeyFile, + firmware => SysFile, + bootloader => BootFile, + package => PackageFile, + force => Force, + handlers => grisp_tools:handlers_init(#{ + event => {fun event_handler/2, RState}, + shell => {fun rebar3_grisp_handler:shell/3, #{}} + }) + }, + State = grisp_tools:pack(PackSpec), + #{event := RState2} = grisp_tools:handlers_finalize(State), + info("Update package created"), + % case proplists:get_value(quiet, Args) of + % false -> info("~s", [update_usage(State)]); + % true -> ok + % end, + {ok, RState2}. + +event_handler(Event, RState) -> + event(Event), + {ok, RState}. + +event([pack, prepare]) -> + console("* Preparing and validating..."); +event([pack, prepare, _, {error, firmware_not_found, Path}]) -> + RelPath = grisp_tools_util:maybe_relative(Path, ?MAX_DDOT), + abort("System firmware file not found: ~s", [RelPath]); +event([pack, prepare, _, {error, bootloader_not_found, Path}]) -> + RelPath = grisp_tools_util:maybe_relative(Path, ?MAX_DDOT), + abort("Bootloader firmware file not found: ~s", [RelPath]); +event([pack, prepare, _, {error, file_exists, Path}]) -> + RelPath = grisp_tools_util:maybe_relative(Path, ?MAX_DDOT), + abort("File already exists (use --force to overwrite): ~s", [RelPath]); +event([pack, prepare, _, {error, file_access, Path}]) -> + RelPath = grisp_tools_util:maybe_relative(Path, ?MAX_DDOT), + abort("File not accessible: ~s", [RelPath]); +event([pack, prepare, _, {error, not_a_file, Path}]) -> + RelPath = grisp_tools_util:maybe_relative(Path, ?MAX_DDOT), + abort("Not a regular file: ~s", [RelPath]); +event([pack, package]) -> + console("* Creating software update package..."); +event([pack, package, {error, Reason}]) -> + abort_message("Failed to create package: ~s", Reason); +event(Event) -> + debug("[rebar3_grisp] ~p", [Event]), + case lists:last(Event) of + {error, Reason, Info} when is_binary(Info) -> + abort("Unexpected ~p error: ~s", [Reason, Info]); + {error, Reason, Info} -> + abort("Unexpected ~p error: ~p", [Reason, Info]); + {error, Reason} -> + abort("Unexpected ~p error", [Reason]); + _ -> ok + end. + +abort_message(Prefix, Msg) when is_binary(Msg) -> + abort("~s; ~s", [Prefix, Msg]); +abort_message(Prefix, Reason) -> + abort("~s: ~p", [Prefix, Reason]). + +% update_usage(FirmwareSpec) -> + % FirmwareItems = maps:to_list(maps:with([system, image, boot], FirmwareSpec)), + % FirmwareDesc = #{ + % system => {"system", "/dev/mmc1.0"}, + % image => {"emmc", "/dev/mmc1"}, + % boot => {"bootloader", "/dev/mmc1"} + % }, + % Firmwares = [{K, R, L, D} || {K, #{target := T}} <- FirmwareItems, + % {L, D} <- [maps:get(K, FirmwareDesc)], + % R <- [grisp_tools_util:maybe_relative(T, ?MAX_DDOT)]], + % Prefix = " ", + % Cautions = iolist_to_binary([ + % case FirmwareSpec of + % #{image := #{truncate := true}} -> + % [[Prefix, "- When writing a truncated EMMC image firmware, only the first\n"], + % [Prefix, " system partition is written. If the active system is the\n"], + % [Prefix, " second one, the board will continue to boot the old software.\n"], + % [Prefix, " You will need to manually change the active system partition\n"], + % [Prefix, " in the bootloader console and restart the board:\n"], + % [Prefix, " $ let state.bootstate.active_system=0\n"], + % [Prefix, " $ state -s\n"]]; + % _ -> [] + % end, + % case FirmwareSpec of + % #{system := #{}} -> + % [[Prefix, "- When writing a system firmware, be sure to do it on the active system\n"], + % [Prefix, " partition (/dev/mmc1.0 or /dev/mmc1.1) or the board will continue to\n"], + % [Prefix, " boot the old software.\n"]]; + % _ -> [] + % end + % ]), + % iolist_to_binary([ + % ["Instructions to update GRiSP2 firmware(s):\n"], + % case os:type() of + % {unix, darwin} -> + % [[Prefix, "- Copy the relevent firmware(s) to the SD card:\n"], + % [[Prefix, " $ cp \"", R, "\" /Volumes/GRISP # ", L, " firmware\n"] + % || {_, R, L, _} <- Firmwares], + % [Prefix, "- Unmount the SD card:\n"], + % [Prefix, " $ diskutil umount /Volumes/GRISP\n"], + % [Prefix, "- Open a serial console to the GRiSP board:\n"], + % [Prefix, " $ screen /dev/tty.usbserial-0${GRISP_BOARD_SERIAL}1 115200\n"]]; + % {unix, linux} -> + % [[Prefix, "- Copy the relevent firmware(s) to the SD card:\n"], + % [[Prefix, " $ cp \"", R, "\" /media/$USER/GRISP # ", L, " firmware\n"] + % || {_, R, L, _} <- Firmwares], + % [Prefix, "- Unmount the SD card:\n"], + % [Prefix, " $ umount /media/$USER/GRISP\n"], + % [Prefix, "- Open a serial console to the GRiSP board:\n"], + % [Prefix, " $ screen /dev/ttyUSB1 115200\n"]]; + % _ -> + % [[Prefix, "- Copy the relevent firmware(s) to the SD card.\n"], + % [Prefix, "- Unmount the SD card.\n"], + % [Prefix, "- Open a serial console to the GRiSP board.\n"]] + % end, + % [Prefix, "- Insert the SD card.\n"], + % [Prefix, "- Reset the GRiSP board using the onboard reset button.\n"], + % [Prefix, "- Enter into barebox console mode by pressing any key before 3 seconds.\n"], + % [Prefix, "- Write the relevent firmware(s):\n"], + % [[Prefix, " $uncompress \"/mnt/mmc/", filename:basename(R), "\" ", D, " # ", L, " firmware\n"] + % || {_, R, L, D} <- Firmwares], + % [Prefix, "- Remove the SD card.\n"], + % [Prefix, "- Reset the GRiSP board again.\n"], + % case Cautions of + % <<>> -> []; + % _ -> ["CAUTIONS:\n", Cautions] + % end + % ]). diff --git a/src/rebar3_grisp_util.erl b/src/rebar3_grisp_util.erl index 3c2dcd3..60e29c6 100644 --- a/src/rebar3_grisp_util.erl +++ b/src/rebar3_grisp_util.erl @@ -39,6 +39,9 @@ -export([firmware_dir/1]). -export([firmware_file_name/4]). -export([firmware_file_path/4]). +-export([update_dir/1]). +-export([update_file_name/3]). +-export([update_file_path/3]). -export([toolchain_root/1]). -import(rebar3_grisp_tools, [event/2]). @@ -204,7 +207,7 @@ bundle_file_path(RebarState, RelName, RelVsn) -> filename:join(BundleDir, BundleName). firmware_dir(RebarState) -> - filename:join([root(RebarState), "firmware"]). + filename:join([root(RebarState), "firmware"]). firmware_file_name(RebarState, image, RelName, RelVsn) -> Config = config(RebarState), @@ -227,6 +230,19 @@ firmware_file_path(RebarState, Type, RelName, RelVsn) -> BundleName = firmware_file_name(RebarState, Type, RelName, RelVsn), filename:join(BundleDir, BundleName). +update_dir(RebarState) -> + filename:join([root(RebarState), "update"]). + +update_file_name(RebarState, RelName, RelVsn) -> + Config = config(RebarState), + Board = platform(Config), + iolist_to_binary(io_lib:format("~s.~s.~s.tar", [Board, RelName, RelVsn])). + +update_file_path(RebarState, RelName, RelVsn) -> + UpdateDir = rebar3_grisp_util:update_dir(RebarState), + UpdateName = update_file_name(RebarState, RelName, RelVsn), + filename:join(UpdateDir, UpdateName). + rebar_command(RebarState, Namespace, Command, Args) -> % Backup current command state OriginalNamespace = rebar_state:namespace(RebarState),